这一步将 config 里面关于 mod 的配置进行加载和配置开启。
mod 配置格式
通过 mod_handle 将当前的 env 进行关联
mod_handler.set_env(env)
mod_handle 可以理解为一个管理配置的封装类,首先第一步做的就是将自身的 _env 将当前环境中的 env 关联起来,拿到该 env 的config, 对自己所管理的 mod 们进行配置。
根据上一小节的图例,可以知道:
enable 决定这个这个扩展是否被启用;
lib: 要导入的模块名
priority: 模块的优先级(最后存入的是一个排序的字典)
在执行到 load_mod() 的时候,一是能拿到本身的配置,更新入用户输入配置;
二是将 真正的 Mod 类导入。
相关源码: mod/init.py
def set_env(self, environment):
self._env = environment
config = environment.config
for mod_name in config.mod.__dict__:
mod_config = getattr(config.mod, mod_name)
# enable 决定这个扩展是否被启用
if not mod_config.enabled:
continue
# 将启用的扩展加到 _mod_list 中
self._mod_list.append((mod_name, mod_config))
for idx, (mod_name, user_mod_config) in enumerate(self._mod_list):
if hasattr(user_mod_config, 'lib'):
# 扩展中需要导入的模块名
lib_name = user_mod_config.lib
elif mod_name in SYSTEM_MOD_LIST:
lib_name = "rqalpha.mod.rqalpha_mod_" + mod_name
else:
lib_name = "rqalpha_mod_" + mod_name
system_log.debug(_(u"loading mod {}").format(lib_name))
# 根据配置导入 mod 库
mod_module = import_mod(lib_name)
# 不能导入的 从 mod_list 中删除
if mod_module is None:
del self._mod_list[idx]
return
# 在每个被导入的模块中执行 load_mod()
mod = mod_module.load_mod()
# __config__ 是写在 __init__ 文件中的默认配置
mod_config = RqAttrDict(copy.deepcopy(getattr(mod_module, "__config__", {})))
# 将用户输入配置更新到 mod 配置中
mod_config.update(user_mod_config)
setattr(config.mod, mod_name, mod_config)
self._mod_list[idx] = (mod_name, mod_config)
self._mod_dict[mod_name] = mod
# 在 mod_list 里面按照优先级排序
self._mod_list.sort(key=lambda item: getattr(item[1], "priority", 100))
environment.mod_dict = self._mod_dict
开启配置
在主程序中的代码段:
mod_handler.start_up()
在 ModHandle 中的代码段:
def start_up(self):
for mod_name, mod_config in self._mod_list:
# 开启配置 改变 env 属性
self._mod_dict[mod_name].start_up(self._env, mod_config)
举个例子,在我们的用户配置里面,我们对 simulatiom 这个扩展的配置如下:
程序运行最终会执行到 mod/simulation/mod.py 中, Simulation 类的 start_up()
通过执行 start_up,为 env 配置了相关的扩展部件。感觉这种设计很灵活。
def start_up(self, env, mod_config):
# 根据 mod_config 配置去改变 env 相应的属性
mod_config.matching_type = self.parse_matching_type(mod_config.matching_type)
if mod_config.commission_multiplier < 0:
raise patch_user_exc(ValueError(_(u"invalid commission multiplier value: value range is [0, +∞)")))
if env.config.base.margin_multiplier <= 0:
raise patch_user_exc(ValueError(_(u"invalid margin multiplier value: value range is (0, +∞]")))
if env.config.base.frequency == "tick":
mod_config.volume_limit = False
if mod_config.matching_type not in [
MATCHING_TYPE.NEXT_TICK_LAST,
MATCHING_TYPE.NEXT_TICK_BEST_OWN,
MATCHING_TYPE.NEXT_TICK_BEST_COUNTERPARTY,
]:
raise RuntimeError(_("Not supported matching type {}").format(mod_config.matching_type))
else:
if mod_config.matching_type not in [
MATCHING_TYPE.NEXT_BAR_OPEN,
MATCHING_TYPE.CURRENT_BAR_CLOSE,
]:
raise RuntimeError(_("Not supported matching type {}").format(mod_config.matching_type))
if mod_config.signal:
env.set_broker(SignalBroker(env, mod_config))
else:
# 设置了模拟券商代理
env.set_broker(SimulationBroker(env, mod_config))
# 设置了时间源
event_source = SimulationEventSource(env, env.config.base.account_list)
env.set_event_source(event_source)