-
Notifications
You must be signed in to change notification settings - Fork 107
3、执行过程
本项目所有命令均以如下格式执行:
finhack {module} {action} --vendor={vendor} [--background] --arg1=xxx --arg2=xxx ……
翻译过来就是:
finhack {模块} {动作} --vendor={供给侧} [--后台运行] --参数1=xxx --参数2=xxx
其中参数注册需要到 project_path/data/config/agrs.conf 下进行配置
命令运行后,将按如下优先级尝试执行对应action
- {project_path}/loader/{module}_loader.py {action}()
- finhack.core.loader.{module}_loader {action}()
- finhack.core.loader.base_loader {action}()
- {project_path}/{module}/{vendor}/{vendor}_{module}.py {action}()
- finhack/{module}/{vendor}/{vendor}_{module}.py {action}()
上面5个文件,前3个loader类型的文件,基本都是对要执行的动作做一些预处理,最终大概率还是会执行到后两个:
- {project_path}/{module}/{vendor}/{vendor}_{module}.py {action}()
- finhack/{module}/{vendor}/{vendor}_{module}.py {action}()
当安装了finhack框架后,本框架将自动在pip的可执行目录生成一个finhack文件,即本框架的主要入口文件,该文件代码如下:
#!/usr/bin/env python
import os
from finhack.core.core import Core
import multiprocessing
import atexit
def child_process_action(core):
# 注册子进程退出时的清理函数,如果有的话
# atexit.register(Utils.child_cleanup)
core.do_action()
# 子进程完成任务后退出
os._exit(0)
if __name__ == '__main__':
core = Core()
core.load_module()
from finhack.library.utils import Utils
if core.args.background:
pid = os.fork() # 创建一个新进程
if pid == -1: # 创建进程失败
print("创建后台进程失败!")
exit(1)
elif pid == 0: # 子进程中执行
child_process_action(core)
else: # 父进程中继续执行
Utils.write_pids(pid)
print("启动后台任务!")
else:
# 注册父进程退出时的清理函数
#atexit.register(Utils.auto_exit)
core.do_action()
可以看到,该文件首先初始化了finhack的Core类,然后判断是否是后台任务,如果是后台任务则启动一个子进程切换到后台执行。
Core类主要执行一些初始化的动作,包括:
- 检查项目目录的可用性
- 解析命令行参数
- 生成运行时、全局变量等各种配置
- 加载模块类、解析模块参数、执行模块action
- 初始化日志
运行命令后,框架会按照如下加载顺序寻找 model_loader,
- {project_path}/loader/{module}_loader.py
- finhack.core.loader.{module}_loader
- finhack.core.loader.base_loader
以TraderLoader为例,类名都是以vendor的大写字母开头+Loader命名
from finhack.core.loader.base_loader import BaseLoader
class TraderLoader(BaseLoader):
def run(self):
# print(self.module_path)
# print(self.user_module_path)
# print(self.klass)
trader=self.klass
trader.args=self.args
trader.run()
pass
这里面的TraderLoader继承了BaseLoader,BaseLoader的用途如下:
- 识别并加载对应的module文件
- 注册stop函数,可以停止后台运行的任务
- 注册run函数,内容同上面代码,默认直接调用vendor类的run
loader的用途是如果一个module存在多个vendor,那么有时候可能会借助loader进行一些处理,当loader类和vendor中的类存在同样的方法时,将运行loader类中的同名方法。(如大家都有run(),则优先运行loader中的run,如果loader没有,才运行vendor中的run)
按顺序优先级查找并加载,对应module的vendor类,并执行对应的action
- finhack.{module}.{vendor}.{vendor}_{module}
- project_path/{module}/{vendor}/{vendor}_{module}.py
若命令行中未指定--vendor参数,vendor默认为default
vendor类的用途在于方便自定义各种动作,比如finhack框架中有一个collector模块,vendor是tushare,讲使用tushare自动采集数据,使用者也可以在project目录,开发一些vendor为qmt、joinquant、yfinance等,进行对应数据源的采集。
个人认为finhack框架最大的优势就是可以自定义命令,在demo_project中,已经给出了具体的例子,我们只需要新建3个文件(最少为1个文件),即可建立一个完整的testmodule
1、[可选]首先我们在demo_project/loader目录下新建testmodule_loader.py,内容如下:
#类名首字母大写,为vendor+Loader的格式
import finhack.library.log as Log
from finhack.core.loader.base_loader import BaseLoader
class TestmoduleLoader(BaseLoader):
def testaction(self):
Log.logger.debug("----%s----" % (__file__))
Log.logger.debug("this is TestmoduleLoader")
Log.logger.debug("loading "+self.module_name)
Log.logger.debug("testarg1 is:"+str(self.args.testarg1))
Log.logger.debug("testarg2 is:"+str(self.args.testarg2))
obj=self.klass
obj.args=self.args
obj.run()
2、然后再建立demo_project/default/default_testmodule.py (default为vendor名),内容如下:
#类名首字母大写,vendor名字首字母大写
import finhack.library.log as Log
class DefaultTestmodule():
#finhack testmodule run
def __init__(self):
pass
def run(self):
Log.logger.debug("----%s----" % (__file__))
Log.logger.debug("this is Testmodule")
Log.logger.debug("vendor is default")
print(self.args)
while True:
time.sleep(1)
Log.logger.debug(".")
3、[可选]由于我们可能要接收一些自定义参数,所以要在demo_project/data/config/args.conf下新增节点:
[testmodule]
testarg1=this is a test key
testarg2=this is also a test key
表示testmodule接收两个参数,默认值在=后面
4、我们尝试运行自定义命令:
finhack testmodule testaction --testarg1=11111111111111111111
finhack testmodule run --testarg2=22222222222222222