def _init(self, loc): init_transformer = InitTransformer() init_transformer.visit(self.ast_root) # XXX 必须要一个module node作为根节点。 exec(compile(wrap_with_module(init_transformer.init_node), "[Strategy:%s]" % self.__code.name, mode="exec") , dict(open=self.__strategy.open, print=self.__strategy.printer.print, **loc), loc) self.__globals.update(Globals(loc["init"](), {}))
def get_func_within_environment(self, ast_: ast.AST, allow_trading=True, filename=None): assert isinstance(ast_, ast.FunctionDef) self.set_environment(ast_, allow_trading=allow_trading) glb = self.get_globals(allow_trading=allow_trading) loc = {} if filename is None: filename = ast_.name exec(compile(wrap_with_module(ast_), filename=filename, mode="exec"), glb, loc) return loc[ast_.name]
def _init(self, loc): init_transformer = InitTransformer() init_transformer.visit(self.ast_root) # XXX 必须要一个module node作为根节点。 exec( compile(wrap_with_module(init_transformer.init_node), "[Strategy:%s]" % self.__code.name, mode="exec"), dict(open=self.__strategy.open, print=self.__strategy.printer.print, **loc), loc) self.__globals.update(Globals(loc["init"](), {}))
def bind_code_to_strategy(self, code): def get_parameter_default(paras, name, check, default, pop=True): if pop: para = paras.pop(name, None) else: para = paras.get(name, None) if para: temp = para.default if temp == inspect._empty: # TODO未给定值的处理 return default elif check(temp): return temp else: raise KeyError("变量%s所赋值不合法", name) else: return default def get_global_attrs(locals_): for name, attr in self.ATTR_MAP.items(): if getattr(self, attr) is None: setattr(self, attr, locals_.get(name)) def set_global_attrs(globals_): for name, attr in self.ATTR_MAP.items(): value = getattr(self, attr) if value is not None: globals_[name] = value else: pass def upper_first_letter(string): return string[0].upper() + string[1:] # get the system functions in use ast_ = ast.parse(code) import_inspector = ImportInspector() import_inspector.visit(ast_) # 模块导入检查 signal_locals_ = {} function_locals = {} signal_globals_ = {'open': self.open} # 可动态管理的全策略命名空间,禁用open function_globals_ = {'open': self.open} # 可动态管理的系统函数命名空间,禁用open # 获取并检查一些全局变量的设定 exec(compile(code, "[Strategy:%s]" % self.name, mode="exec"), signal_globals_, signal_locals_) # get_global_attrs(signal_locals_) # 弃用,暂时保留以便向下兼容 set_global_attrs(signal_globals_) set_global_attrs(function_globals_) signal_globals_.update(signal_locals_) signal_globals_.update(self.__glb) function_globals_.update(self.__glb) self.engine.set_capital_base(self.capital_base) self.engine.start_time = self.start_time self.engine.end_time = self.end_time check_time_frame(self.time_frame) sys_func_detector = SystemFunctionsDetector() sys_func_detector.visit(ast_) sys_func_dir = self.user_dir.get_sys_func_dir() funcs_in_use = sys_func_detector.get_funcs_in_use() # get the instructions to inject to every handle signal_to_inject_init = {} function_to_inject_init = {} signal_to_inject_loop = {} function_to_inject_loop = {} code_lines = ["import functools", "__globals = globals()"] code_lines.extend(["{0} = __globals['{0}']".format(key) for key in self.__glb.keys() if key not in ["Sell", "Buy", "SellShort", "BuyToCover"]]) # init中可以设定全局变量,所以要以"global foo"的方式进行注入。 if inspect.isfunction(signal_locals_.get('init', None)): init_transformer = InitTransformer() init_transformer.visit(ast_) # XXX 必须要一个module node作为根节点。 exec(compile(wrap_with_module(init_transformer.init_node), "[Strategy:%s]" % self.name, mode="exec"), signal_globals_, signal_locals_) self.handlers['init'] = signal_locals_['init'] # 执行init并记录locals,之后注入信号 init_globals = self.handlers['init']() signal_globals_.update(init_globals) init_to_inject_init = ["{0} = __globals['{0}']".format(key) for key in init_globals.keys()] else: init_to_inject_init = [] for key, value in signal_locals_.items(): if inspect.isfunction(value): if key == "init": continue paras = inspect.signature(value).parameters.copy() # 获取handler函数的参数列表 is_handle = get_parameter_default(paras, "IsHandle", lambda x: isinstance(x, bool), True) if not is_handle: continue custom = get_parameter_default(paras, "Custom", lambda x: isinstance(x, bool), False) if not custom: # TODO加入真正的验证方法 # 转化为tuple是因为symbols要那来当做字典的键 symbols = tuple(get_parameter_default(paras, "Symbols", lambda x: True, self.symbols)) time_frame = get_parameter_default(paras, "TimeFrame", check_time_frame, self.time_frame) max_length = get_parameter_default(paras, "MaxLen", lambda x: isinstance(x, int) and (x > 0), self.max_length) self.engine.add_cache_info(symbols, time_frame, max_length) self.signals[key] = self.signal_factory.new(self.engine, self.user, self.name, key, symbols, time_frame) additional_instructions = ["{0} = system_functions['%s.%s'%('{1}','{0}')]".format(f, key) for f, s in funcs_in_use.items() if key in s] + ['del(system_functions)'] temp = [] # Begin open,high,low,close相关变量的注入 quotes = ["open", "high", "low", "close", "datetime", "timestamp", "volume"] temp.extend(["{0} = __globals['Data']['{1}']['{3}']['{2}']" .format(upper_first_letter(field), time_frame, symbols[0], field) for field in quotes]) temp.extend(["{0} = __globals['Data']['{1}']['{3}']['{2}']" .format(field[0].upper(), time_frame, symbols[0], field) for field in quotes]) temp.extend(["{0}s = __globals['Data']['{1}']['{2}']" .format(upper_first_letter(field), time_frame, field) for field in quotes]) # end # get_current_bar 函数的注入,BarNum实际通过该函数维护 temp.append("{0} = __globals['signals']['{1}'].{0}".format('get_current_bar', key)) temp.append("Symbol = Symbols[0]") # Symbol注入 temp.append("Point=Points[Symbol]") # Points注入 function_to_inject_init[key] = code_lines + temp + ["del(functools)", "del(__globals)"] + \ additional_instructions temp.extend(["{0} = functools.partial(__globals['{0}'],signal='{1}')".format( field, key) for field in ["Sell", "Buy", "SellShort", "BuyToCover"]]) # TODO 现在是将init中的变量当做局部变量注入每个信号的初始化部分,其实这样并不等同于全局变量的概念, # 只不过对于单个信号的策略是一样的。 signal_to_inject_init[key] = code_lines + temp + init_to_inject_init + \ ["del(functools)", "del(__globals)"] + additional_instructions # 信号与函数中相比多出的就是交易指令 signal_to_inject_loop[key] = ["BarNum = get_current_bar()", "Pos = Positions[Symbol]", "MarketPosition = Pos.type", "CurrentContracts= Pos.volume"] function_to_inject_loop[key] = signal_to_inject_loop[key] else: # TODO自定义事件处理 pass for para_name in paras.keys(): # TODO加入类型检测 default = get_parameter_default(paras, para_name, lambda x: True, None, pop=False) if default is None: raise ValueError('参数%s未指定初始值' % para_name) elif not isinstance(default, (int, float)): raise ValueError('参数%s的值必须为整数或浮点数' % para_name) self.signals[key].add_parameters(para_name, default) self.__points.update({key: value.point for key, value in self.engine.symbol_pool.items()}) series_exporter = SeriesExporter() # deal with the export syntax # export the system functions in use for func, signals in funcs_in_use.items(): for signal in signals: fullname = os.path.join(sys_func_dir, func + ".py") with codecs.open(fullname, "r", "utf-8") as f: func_ast = ast.parse(f.read()) f.close() import_inspector.visit(func_ast) # 检查模块导入 function_injector = LocalsInjector({func: function_to_inject_init[signal]}, {func: function_to_inject_loop[signal]}) function_injector.visit(func_ast) func_ast = series_exporter.visit(func_ast) # TODO 多个handle时需要对每个handle调用的系统函数建立独立的系统函数 exec(compile(func_ast, "[SysFunctions:%s]" % func, mode="exec"), function_globals_, function_locals) self.system_functions['%s.%s' % (signal, func)] = SeriesFunction(function_locals[func], signal) # new方法是对__init__的封装,创建SeriesFunction对象所需信息有其所在的函数体本身,signal和其运行时传入的参数, # 编译时所能确定的只有前者,采用偏函数的方式将两者结合到一起 # inject global vars into locals of handler signal_injector = LocalsInjector(signal_to_inject_init, signal_to_inject_loop) signal_injector.visit(ast_) ast_ = series_exporter.visit(ast_) exec(compile(ast_, "[Strategy:%s]" % self.name, mode="exec"), signal_globals_, signal_locals_) for key in signal_to_inject_init.keys(): self.signals[key].set_generator(signal_locals_[key]) self.log("<%s>策略添加成功" % self.name, logging.INFO) return True
def bind_code_to_strategy(self, code): def get_parameter_default(paras, name, check, default, pop=True): if pop: para = paras.pop(name, None) else: para = paras.get(name, None) if para: temp = para.default if temp == inspect._empty: # TODO未给定值的处理 return default elif check(temp): return temp else: raise KeyError("变量%s所赋值不合法", name) else: return default def get_global_attrs(locals_): for name, attr in self.ATTR_MAP.items(): if getattr(self, attr) is None: setattr(self, attr, locals_.get(name)) def set_global_attrs(globals_): for name, attr in self.ATTR_MAP.items(): value = getattr(self, attr) if value is not None: globals_[name] = value else: raise ValueError('全局变量%s未被赋值' % name) def upper_first_letter(string): return string[0].upper() + string[1:] # get the system functions in use ast_ = ast.parse(code) import_inspector = ImportInspector() import_inspector.visit(ast_) # 模块导入检查 signal_locals_ = {} function_locals = {} signal_globals_ = {'open': self.open} # 可动态管理的全策略命名空间,禁用open function_globals_ = {'open': self.open} # 可动态管理的系统函数命名空间,禁用open # 获取并检查一些全局变量的设定 exec(compile(code, "[Strategy:%s]" % self.name, mode="exec"), signal_globals_, signal_locals_) get_global_attrs(signal_locals_) # 弃用,暂时保留以便向下兼容 set_global_attrs(signal_globals_) set_global_attrs(function_globals_) signal_globals_.update(signal_locals_) signal_globals_.update(self.__glb) function_globals_.update(self.__glb) self.engine.set_capital_base(self.capital_base) self.engine.start_time = self.start_time self.engine.end_time = self.end_time check_time_frame(self.time_frame) sys_func_detector = SystemFunctionsDetector() sys_func_detector.visit(ast_) sys_func_dir = self.user_dir.get_sys_func_dir() funcs_in_use = sys_func_detector.get_funcs_in_use() # get the instructions to inject to every handle signal_to_inject_init = {} function_to_inject_init = {} signal_to_inject_loop = {} function_to_inject_loop = {} code_lines = ["import functools", "__globals = globals()"] code_lines.extend([ "{0} = __globals['{0}']".format(key) for key in self.__glb.keys() if key not in ["Sell", "Buy", "SellShort", "BuyToCover"] ]) # init中可以设定全局变量,所以要以"global foo"的方式进行注入。 if inspect.isfunction(signal_locals_.get('init', None)): init_transformer = InitTransformer() init_transformer.visit(ast_) # XXX 必须要一个module node作为根节点。 exec( compile(wrap_with_module(init_transformer.init_node), "[Strategy:%s]" % self.name, mode="exec"), signal_globals_, signal_locals_) self.handlers['init'] = signal_locals_['init'] # 执行init并记录locals,之后注入信号 init_globals = self.handlers['init']() signal_globals_.update(init_globals) init_to_inject_init = [ "{0} = __globals['{0}']".format(key) for key in init_globals.keys() ] else: init_to_inject_init = [] for key, value in signal_locals_.items(): if inspect.isfunction(value): if key == "init": continue paras = inspect.signature( value).parameters.copy() # 获取handler函数的参数列表 is_handle = get_parameter_default( paras, "IsHandle", lambda x: isinstance(x, bool), True) if not is_handle: continue custom = get_parameter_default(paras, "Custom", lambda x: isinstance(x, bool), False) if not custom: # TODO加入真正的验证方法 # 转化为tuple是为了去掉重复,而且symbols要那来当做字典的键 symbols = tuple( get_parameter_default(paras, "Symbols", lambda x: True, self.symbols)) time_frame = get_parameter_default(paras, "TimeFrame", check_time_frame, self.time_frame) max_length = get_parameter_default( paras, "MaxLen", lambda x: isinstance(x, int) and (x > 0), self.max_length) self.engine.add_cache_info(symbols, time_frame, max_length) self.signals[key] = self.signal_factory.new( self.engine, self.user, self.name, key, symbols, time_frame) additional_instructions = [ "{0} = system_functions['%s.%s'%('{1}','{0}')]".format( f, key) for f, s in funcs_in_use.items() if key in s ] + ['del(system_functions)'] temp = [] # Begin open,high,low,close相关变量的注入 quotes = [ "open", "high", "low", "close", "datetime", "timestamp", "volume" ] temp.extend([ "{0} = __globals['Data']['{1}']['{3}']['{2}']".format( upper_first_letter(field), time_frame, symbols[0], field) for field in quotes ]) temp.extend([ "{0} = __globals['Data']['{1}']['{3}']['{2}']".format( field[0].upper(), time_frame, symbols[0], field) for field in quotes ]) temp.extend([ "{0}s = __globals['Data']['{1}']['{2}']".format( upper_first_letter(field), time_frame, field) for field in quotes ]) # end # get_current_bar 函数的注入,BarNum实际通过该函数维护 temp.append("{0} = __globals['signals']['{1}'].{0}".format( 'get_current_bar', key)) temp.append("Symbol = Symbols[0]") # Symbol注入 temp.append("Point=Points[Symbol]") # Points注入 function_to_inject_init[key] = code_lines + temp + ["del(functools)", "del(__globals)"] + \ additional_instructions temp.extend([ "{0} = functools.partial(__globals['{0}'],signal='{1}')" .format(field, key) for field in ["Sell", "Buy", "SellShort", "BuyToCover"] ]) # TODO 现在是将init中的变量当做局部变量注入每个信号的初始化部分,其实这样并不等同于全局变量的概念, # 只不过对于单个信号的策略是一样的。 signal_to_inject_init[key] = code_lines + temp + init_to_inject_init + \ ["del(functools)", "del(__globals)"] + additional_instructions # 信号与函数中相比多出的就是交易指令 signal_to_inject_loop[key] = [ "BarNum = get_current_bar()", "Pos = Positions[Symbol]", "MarketPosition = Pos.type", "CurrentContracts= Pos.volume" ] function_to_inject_loop[key] = signal_to_inject_loop[key] else: # TODO自定义事件处理 pass for para_name in paras.keys(): # TODO加入类型检测 default = get_parameter_default(paras, para_name, lambda x: True, None, pop=False) if default is None: raise ValueError('参数%s未指定初始值' % para_name) elif not isinstance(default, (int, float)): raise ValueError('参数%s的值必须为整数或浮点数' % para_name) self.signals[key].add_parameters(para_name, default) self.__points.update({ key: value.point for key, value in self.engine.symbol_pool.items() }) series_exporter = SeriesExporter() # deal with the export syntax # export the system functions in use for func, signals in funcs_in_use.items(): for signal in signals: fullname = os.path.join(sys_func_dir, func + ".py") with codecs.open(fullname, "r", "utf-8") as f: func_ast = ast.parse(f.read()) f.close() import_inspector.visit(func_ast) # 检查模块导入 function_injector = LocalsInjector( {func: function_to_inject_init[signal]}, {func: function_to_inject_loop[signal]}) function_injector.visit(func_ast) func_ast = series_exporter.visit(func_ast) # TODO 多个handle时需要对每个handle调用的系统函数建立独立的系统函数 exec( compile(func_ast, "[SysFunctions:%s]" % func, mode="exec"), function_globals_, function_locals) self.system_functions['%s.%s' % (signal, func)] = SeriesFunction( function_locals[func], signal) # new方法是对__init__的封装,创建SeriesFunction对象所需信息有其所在的函数体本身,signal和其运行时传入的参数, # 编译时所能确定的只有前者,采用偏函数的方式将两者结合到一起 # inject global vars into locals of handler signal_injector = LocalsInjector(signal_to_inject_init, signal_to_inject_loop) signal_injector.visit(ast_) ast_ = series_exporter.visit(ast_) exec(compile(ast_, "[Strategy:%s]" % self.name, mode="exec"), signal_globals_, signal_locals_) for key in signal_to_inject_init.keys(): self.signals[key].set_generator(signal_locals_[key]) print("<%s>信号添加成功" % self.name) return True