class ExecuteUnit(object): """ 策略执行的物理单元,支持多个策略同时运行。 每个执行单元都可能跟踪多个数据(策略用到的周期合约数据集合)。 其中第一个合约为"主合约" 。 每个执行器可加载多个策略,只要数据需求不超过pcontracts。 :ivar dt_begin: 策略执行的时间起点。 :ivar dt_end: 策略执行的时间终点。 :ivar pcontracts: 策略用到的周期合约数据集合。 :ivar _strategies: 策略集合。 :ivar datasource: 数据源。 """ def __init__(self, pcontracts, window_size=0, dt_start=datetime(1980,1,1), dt_end=datetime(2100,1,1), spec_date = { }): # 'symbol':[,] series.g_rolling = False if window_size == 0 else True series.g_window = window_size self.all_data = { } # PContract -> DataWrapper self.finished_data = [] self.pcontracts = pcontracts self._combs = [] self._window_size = window_size + 1 self._data_manager = DataManager() for pcon in pcontracts: if pcon in spec_date: dt_start = spec_date[pcon][0] dt_end = spec_date[pcon][1] assert(dt_start < dt_end) self.load_data(pcon, dt_start, dt_end) self.context = Context(self.all_data) def _init_strategies(self): for pcon, dcontext in self.all_data.iteritems(): # switch context self.context.switch_to_contract(pcon) for i, combination in enumerate(self._combs): for j, s in enumerate(combination): self.context.switch_to_strategy(i, j) s.on_init(self.context) def add_comb(self, comb, settings = { }): """ 添加策略组合组合 Args: comb (list): 一个策略组合 """ self._combs.append(comb) if settings: num_strategy = len(comb) assert (settings['captial'] > 0) assert len(settings['ratio']) == num_strategy assert(sum(settings['ratio']) == 1) ctxs = [] for i, s in enumerate(comb): iset = { } if settings: iset = { 'captial': settings['captial'] * settings['ratio'][i] } logger.debug(iset) ctxs.append(StrategyContext(s.name, iset)) self.context.add_strategy_context(ctxs) blotters = [ ctx.blotter for ctx in ctxs] return blotter.Profile(blotters, self.all_data, self.pcontracts[0], len(self._combs)-1) def run(self): # 初始化策略自定义时间序列变量 print 'runing strategies..' self._init_strategies() print 'on_bars..' # todo 对单策略优化 has_next = True # 遍历每个数据轮, 次数为数据的最大长度 for pcon, data in self.all_data.iteritems(): self.context.switch_to_contract(pcon) self.context.rolling_foward() while True: # 遍历数据轮的所有合约 for pcon, data in self.all_data.iteritems(): self.context.switch_to_contract(pcon) if self.context.time_aligned(): self.context.update_system_vars() # 组合遍历 for i, combination in enumerate(self._combs): # 策略遍历 for j, s in enumerate(combination): self.context.switch_to_strategy(i, j) self.context.update_strategy_environment(i, j) self.context.update_user_vars() s.on_bar(self.context) # 每轮数据的最后处理 #print "*********" for i, combination in enumerate(self._combs): for j, s in enumerate(combination): self.context.switch_to_strategy(i, j) # 只有在on_final引用跨合约数据才有保证。 s.on_final(self.context) self.context.process_trading_events() self.context.last_date = datetime(2100,1,1) # toremove = [] for pcon, data in self.all_data.iteritems(): self.context.switch_to_contract(pcon) has_next = self.context.rolling_foward() if not has_next: toremove.append(pcon) if toremove: for key in toremove: del self.all_data[key] if len(self.all_data) == 0: # 策略退出后的处理 for i, combination in enumerate(self._combs): for j, s in enumerate(combination): self.context.switch_to_strategy(i, j) s.on_exit(self.context) return def load_data(self, pcontract, dt_start=datetime(1980,1,1), dt_end=datetime(2100,1,1)): """ 加载周期合约数据 Args: pcontract (PContract): 周期合约 dt_start(datetime): 开始时间 dt_end(datetime): 结束时间 Returns: pd.DataFrame. k线数据 """ try: return self.all_data[str(pcontract)] except KeyError: wrapper = self._data_manager.load_bars(pcontract, dt_start, dt_end, self._window_size) window_size = len(wrapper.data) if not series.g_rolling else self._window_size self.all_data[pcontract] = DataContext(wrapper, window_size) return wrapper