def __init__(self, is_backtest=False): """Constructor""" self.__event_engine = EventEngine() # 事件处理引擎 self.__account_manager = AccountManager() # 账户管理 self.__trade_manager = TradeManager(self, is_backtest) # 交易管理器 self.__data_cache = DataCache(self) # 数据中继站 self.__strategys = {} # 策略管理器
def __init__(self, backtesting=False): """Constructor""" self.__event_engine = EventEngine() # 事件处理引擎 self.__account_manager = AccountManager() # 账户管理 self.__backtesting = backtesting # 是否为回测 self.__orders_done = {} # 保存所有已处理报单数据的字典 self.__orders_todo = {} # 保存所有未处理报单(即挂单)数据的字典 self.__deals = {} # 保存所有成交数据的字典 self.__positions = {} # Key:id, value:position with responding id self.__strategys = {} # 保存策略对象的字典,key为策略名称,value为策略对象 self.__data = {} # 统一的数据视图 self.__symbols = {} # key:(symbol,timeframe),value:maxlen self.start_time = None self.end_time = None self.__current_positions = {} # key:symbol,value:current position self.__initial_positions = {} # key:symbol,value:initial position
def __init__(self, backtesting=False): """Constructor""" self.__event_engine = EventEngine() # 事件处理引擎 self.__account_manager = AccountManager() #账户管理 self.__backtesting = backtesting # 是否为回测 self.__orders_done = {} # 保存所有已处理报单数据的字典 self.__orders_todo = {} # 保存所有未处理报单(即挂单)数据的字典 self.__deals = {} # 保存所有成交数据的字典 self.__positions = {} # Key:id, value:position with responding id self.__strategys = {} # 保存策略对象的字典,key为策略名称,value为策略对象 self.__datas = {} # 统一的数据视图 self.__symbols = {} # key:(symbol,timeframe),value:maxlen self.start_time = None self.end_time = None self.__current_positions = {} # key:symbol,value:current position self.__initial_positions = {}# key:symbol,value:initial position
class StrategyEngine(object): """策略引擎""" CACHE_MAXLEN = 10000 # ---------------------------------------------------------------------- def __init__(self, backtesting=False): """Constructor""" self.__event_engine = EventEngine() # 事件处理引擎 self.__account_manager = AccountManager() # 账户管理 self.__backtesting = backtesting # 是否为回测 self.__orders_done = {} # 保存所有已处理报单数据的字典 self.__orders_todo = {} # 保存所有未处理报单(即挂单)数据的字典 self.__deals = {} # 保存所有成交数据的字典 self.__positions = {} # Key:id, value:position with responding id self.__strategys = {} # 保存策略对象的字典,key为策略名称,value为策略对象 self.__data = {} # 统一的数据视图 self.__symbols = {} # key:(symbol,timeframe),value:maxlen self.start_time = None self.end_time = None self.__current_positions = {} # key:symbol,value:current position self.__initial_positions = {} # key:symbol,value:initial position # TODO单独放入utils中 symbols = property(partial(get_attr, attr='symbols'), None, None) start_time = property(partial(get_attr, attr='start_time'), partial(set_attr, attr='start_time'), None) end_time = property(partial(get_attr, attr='end_time'), partial(set_attr, attr='end_time'), None) # ---------------------------------------------------------------------- def get_current_contracts(self): # TODO 现在持仓手数 return () # ---------------------------------------------------------------------- def get_current_positions(self): # TODO 读取每个品种的有效Position return self.__current_positions def get_deals(self): return self.__deals def get_positions(self): return self.__positions # ---------------------------------------------------------------------- def get_data(self): return self.__data # ---------------------------------------------------------------------- def get_profit_records(self): """获取平仓收益记录""" return self.__account_manager.get_profit_records() # ---------------------------------------------------------------------- def get_traceback(self): pass # ---------------------------------------------------------------------- def get_position_records(self): """获取仓位收益记录""" def get_point(deal, entry, volume): if entry == DEAL_ENTRY_IN: if deal.type == DEAL_TYPE_BUY: return ({ 'type': 'point', 'x': deal.time + deal.time_msc / (10**6), 'y': deal.price, 'color': 'buy', 'text': 'Buy %s' % volume }) elif deal.type == DEAL_TYPE_SELL: return ({ 'type': 'point', 'x': deal.time + deal.time_msc / (10**6), 'y': deal.price, 'color': 'short', 'text': 'Short %s' % volume }) elif entry == DEAL_ENTRY_OUT: if deal.type == DEAL_TYPE_BUY: return ({ 'type': 'point', 'x': deal.time + deal.time_msc / (10**6), 'y': deal.price, 'color': 'cover', 'text': 'Cover %s' % volume }) elif deal.type == DEAL_TYPE_SELL: return ({ 'type': 'point', 'x': deal.time + deal.time_msc / (10**6), 'y': deal.price, 'color': 'sell', 'text': 'Sell %s' % volume }) def get_lines(position_start, position_end): deal_start = self.__deals[position_start.deal] deal_end = self.__deals[position_end.deal] start_time = deal_start.time + deal_start.time_msc / (10**6) end_time = deal_end.time + deal_end.time_msc / (10**6) result = { 'type': 'line', 'x_start': start_time, 'x_end': end_time, 'y_start': deal_start.price, 'y_end': deal_end.price } if (deal_end.type == DEAL_TYPE_BUY) ^ (deal_start.price >= deal_end.price): result['color'] = 'win' else: result['color'] = 'lose' def next_position(position): return self.__positions.get(position.next_id, None) def prev_position(position): return self.__positions.get(position.prev_id, None) result = [] stack = [] for symbol in {symbol for (symbol, _) in self.__symbols}: position = next_position(self.__init_positions[symbol]) while (position != None): deal = self.__deals[position.deal] if deal.entry == DEAL_ENTRY_IN: # open or overweight position result.append(get_point(deal, DEAL_ENTRY_IN, deal.volume)) stack.append((position, deal.volume)) else: if deal.entry == DEAL_ENTRY_INOUT: # reverse position volume_left = deal.volume - position.volume result.append( get_point(deal, DEAL_ENTRY_IN, position.volume)) else: # underweight position volume_left = deal.volume result.append(get_point(deal, DEAL_ENTRY_OUT, volume_left)) while volume_left > 0: position_start, volume = stack.pop() result.append(get_lines(position_start, position)) volume_left -= volume if volume_left < 0: stack.append(position_start, -volume_left) elif deal.entry == DEAL_ENTRY_INOUT and position.volume > 0: stack.append((position, position.volume)) position = next_position(position) return result # ---------------------------------------------------------------------- def set_capital_base(self, base): self.__account_manager.set_capital_base(base) # ---------------------------------------------------------------------- def add_symbols(self, symbols, time_frame, max_length=0): for symbol in symbols: if (symbol, time_frame) not in self.__symbols: self.__symbols[(symbol, time_frame)] = max_length self.__symbols[(symbol, time_frame)] = max( max_length, self.__symbols[(symbol, time_frame)]) self.register_event(EVENT_BAR_SYMBOL[symbol][time_frame], self.update_bar_data) # ---------------------------------------------------------------------- def initialize(self): # TODO 数据结构还需修改 self.__deals.clear() self.__positions.clear() self.__data.clear() # TODO 这里的auto_inc是模块级别的,需要修改成对象级别的。 Deal.set_auto_inc(0) Position.set_auto_inc(0) self.__current_positions.clear() for (symbol, time_frame), maxlen in self.__symbols.items(): if symbol not in self.__data: self.__data[symbol] = {} if time_frame not in self.__data[symbol]: self.__data[symbol][time_frame] = {} if maxlen == 0: maxlen = self.CACHE_MAXLEN for field in ['open', 'high', 'low', 'close', 'time', 'volume']: self.__data[symbol][time_frame][field] = deque(maxlen=maxlen) if symbol not in self.__current_positions: position = Position(symbol) self.__current_positions[symbol] = position self.__initial_positions[symbol] = position self.__positions[position.get_id()] = position # ---------------------------------------------------------------------- def add_file(self, file): self.__event_engine.add_file(file) # ---------------------------------------------------------------------- def add_strategy(self, strategy): """添加已创建的策略实例""" self.__strategys[strategy.get_id()] = strategy strategy.engine = self # ---------------------------------------------------------------------- def update_market_data(self, event): """行情更新""" # TODO行情数据 pass # ---------------------------------------------------------------------- def update_bar_data(self, event): bar = event.content['data'] symbol = bar.symbol time_frame = bar.time_frame for field in ['open', 'high', 'low', 'close', 'time', 'volume']: self.__data[symbol][time_frame][field].appendleft( getattr(bar, field)) # ---------------------------------------------------------------------- def __process_order(self, tick): """处理停止单""" pass # ---------------------------------------------------------------------- def update_order(self, event): """报单更新""" # TODO 成交更新 # ---------------------------------------------------------------------- def update_trade(self, event): """成交更新""" # TODO 成交更新 pass # ---------------------------------------------------------------------- def __update_position(self, deal): def sign(num): if abs(num) <= 10**-7: return 0 elif num > 0: return 1 else: return -1 if deal.volume == 0: return position_prev = self.__current_positions[deal.symbol] position_now = Position(deal.symbol, deal.strategy, deal.handle) position_now.prev_id = position_prev.get_id() position_prev.next_id = position_now.get_id() position = position_prev.type # XXX常量定义改变这里的映射函数也可能改变 if deal.type * position >= 0: deal.entry = DEAL_ENTRY_IN if position == 0: # open position position_now.price_open = deal.price position_now.time_open = deal.time position_now.time_open_msc = deal.time_msc else: # overweight position position_now.time_open = position_prev.time_open position_now.time_open_msc = position_prev.time_open_msc position_now.volume = deal.volume + position_prev.volume position_now.type = deal.type position_now.price_current = ( position_prev.price_current * position_prev.volume + deal.price * deal.volume) / position_now.volume else: contracts = position_prev.volume - deal.volume position_now.volume = abs(contracts) position_now.type = position * sign(contracts) if position_now.type == 0: # close position deal.entry = DEAL_ENTRY_OUT deal.profit = (deal.price - position_prev.price_current ) * position * position_prev.volume position_now.price_current = 0 position_now.volume = 0 # 防止浮点数精度可能引起的问题 position_now.time_open = position_prev.time_open position_now.time_open_msc = position_prev.time_open_msc elif position_now != position: # reverse position deal.entry = DEAL_ENTRY_INOUT deal.profit = (deal.price - position_prev.price_current ) * position * position_prev.volume position_now.price_current = deal.price position_now.time_open = deal.time position_now.time_open_msc = deal.time_msc position_now.price_open = position_now.price_current else: # underweight position # XXX 平部分仓位是直接计算入平仓收益还是将收益暂时算在浮动中 deal.entry = DEAL_ENTRY_OUT deal.profit = (deal.price - position_prev.price_current ) * position * deal.volume position_now.price_current = position_prev.price_current position_now.time_open = position_prev.time_open position_now.time_open_msc = position_prev.time_open_msc position_now.time_update = deal.time position_now.time_update_msc = deal.time_msc deal.position = position_now.get_id() position_now.deal = deal.get_id() self.__current_positions[deal.symbol] = position_now self.__positions[position_now.get_id()] = position_now self.__deals[deal.get_id()] = deal if deal.profit != 0: self.__account_manager.update_deal(deal) # ---------------------------------------------------------------------- @staticmethod def check_order(order): if not isinstance(order, Order): return False # TODO更多关于订单合法性的检查 return True # ---------------------------------------------------------------------- def __send_order_to_broker(self, order): if self.__backtesting: time_frame = SymbolsListener.get_by_id( order.handle).get_time_frame() time_ = self.__data[order.symbol][time_frame]["time"][ 0] + time_frame_to_seconds(time_frame) order.time_done = int(time_) order.time_done_msc = int((time_ - int(time_)) * (10**6)) order.volume_current = order.volume_initial deal = Deal(order.symbol, order.strategy, order.handle) deal.volume = order.volume_current deal.time = order.time_done deal.time_msc = order.time_done_msc deal.type = 1 - ( (order.type & 1) << 1) # 参见ENUM_ORDER_TYPE和ENUM_DEAL_TYPE的定义 deal.price = self.__data[order.symbol][time_frame]["close"][0] # TODO加入手续费等 order.deal = deal.get_id() deal.order = order.get_id() return [deal], {} # TODO 市价单成交 else: pass # TODO 实盘交易 # ---------------------------------------------------------------------- def send_order(self, order): """ 发单(仅允许限价单) symbol:合约代码 direction:方向,DIRECTION_BUY/DIRECTION_SELL offset:开平,OFFSET_OPEN/OFFSET_CLOSE price:下单价格 volume:下单手数 strategy:策略对象 """ # TODO 更多属性的处理 if self.check_order(order): if order.type <= 1: # market order # send_order_to_broker = async_handle(self.__event_engine, self.__update_position)(self.__send_order_to_broker) # send_order_to_broker(order) result = self.__send_order_to_broker(order) self.__update_position(*result[0]) else: self.__orders_todo[order.get_id()] = order return True else: return False # ---------------------------------------------------------------------- def cancel_order(self, order_id): """ 撤单 """ if order_id == 0: self.__orders_todo = {} else: if order_id in self.__orders_todo: del (self.__orders_todo[order_id]) # ---------------------------------------------------------------------- def put_event(self, event): # TODO 加入验证 # TODO 多了一层函数调用,尝试用绑定的形式 self.__event_engine.put(event) # ---------------------------------------------------------------------- def register_event(self, event_type, handle): """注册事件监听""" # TODO 加入验证 self.__event_engine.register(event_type, handle) def unregister_event(self, event_type, handle): """取消事件监听""" self.__event_engine.unregister(event_type, handle) # ---------------------------------------------------------------------- def writeLog(self, log): """写日志""" event = Event(type_=EVENT_LOG) event.content['log'] = log self.__event_engine.put(event) # ---------------------------------------------------------------------- def start(self): """启动所有策略""" self.__event_engine.start() for strategy in self.__strategys.values(): strategy.start() # ---------------------------------------------------------------------- def stop(self): """停止所有策略""" self.__event_engine.stop() for strategy in self.__strategys.values(): strategy.stop() def wait(self): """等待所有事件处理完毕""" self.__event_engine.wait() self.stop() # TODO 对限价单的支持 # ---------------------------------------------------------------------- def sell(self, symbol, volume=1, price=None, stop=False, limit=False, strategy=None, listener=None): if volume == 0: return position = self.__current_positions.get(symbol, None) if not position or position.type <= 0: return # XXX可能的返回值 order = Order(symbol, ORDER_TYPE_SELL, strategy, listener) order.volume_initial = volume if self.__backtesting: time_ = self.__data[symbol][SymbolsListener.get_by_id( listener).get_time_frame()]['time'][0] else: time_ = time.time() order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_)) * (10**6)) return self.send_order(order) # ---------------------------------------------------------------------- def buy(self, symbol, volume=1, price=None, stop=False, limit=False, strategy=None, listener=None): if self.__backtesting: time_ = self.__data[symbol][SymbolsListener.get_by_id( listener).get_time_frame()]['time'][0] else: time_ = time.time() position = self.__current_positions.get(symbol, None) if position and position.type < 0: order = Order(symbol, ORDER_TYPE_BUY, strategy, listener) order.volume_initial = position.volume order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_)) * (10**6)) # TODO 这里应该要支持事务性的下单操作 self.send_order(order) if volume == 0: return order = Order(symbol, ORDER_TYPE_BUY, strategy, listener) order.volume_initial = volume order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_)) * (10**6)) return self.send_order(order) # ---------------------------------------------------------------------- def cover(self, symbol, volume=1, price=None, stop=False, limit=False, strategy=None, listener=None): if volume == 0: return position = self.__current_positions.get(symbol, None) order = Order(symbol, ORDER_TYPE_BUY, strategy, listener) if not position or position.type >= 0: return # XXX可能的返回值 order.volume_initial = volume if self.__backtesting: time_ = self.__data[symbol][SymbolsListener.get_by_id( listener).get_time_frame()]['time'][0] else: time_ = time.time() order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_)) * (10**6)) return self.send_order(order) # ---------------------------------------------------------------------- def short(self, symbol, volume=1, price=None, stop=False, limit=False, strategy=None, listener=None): if self.__backtesting: time_ = self.__data[symbol][SymbolsListener.get_by_id( listener).get_time_frame()]['time'][0] else: time_ = time.time() position = self.__current_positions.get(symbol, None) if position and position.type > 0: order = Order(symbol, ORDER_TYPE_SELL, strategy, listener) order.volume_initial = position.volume order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_)) * (10**6)) # TODO 这里应该要支持事务性的下单操作 self.send_order(order) if volume == 0: return order = Order(symbol, ORDER_TYPE_SELL, strategy, listener) order.volume_initial = volume order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_)) * (10**6)) return self.send_order(order)
class StrategyEngine(object): """策略引擎""" CACHE_MAXLEN = 10000 # ---------------------------------------------------------------------- def __init__(self, is_backtest=False): """Constructor""" self.__event_engine = EventEngine() # 事件处理引擎 self.__account_manager = AccountManager() # 账户管理 self.__trade_manager = TradeManager(self, is_backtest) # 交易管理器 self.__data_cache = DataCache(self) # 数据中继站 self.__strategys = {} # 策略管理器 def get_data(self): return self.__data_cache.data def get_symbol_pool(self): return self.__data_cache.symbol_pool def get_current_positions(self): return self.__trade_manager.current_positions def get_current_time(self): return self.__data_cache.current_time def get_positions(self): return self.__trade_manager.positions def get_deals(self): return self.__trade_manager.deals def get_strategys(self): return self.__strategys def get_profit_records(self): """获取平仓收益记录""" return self.__account_manager.get_profit_records() def get_symbol_timeframe(self): return self.__data_cache.get_cache_info().keys() # XXX之所以不用装饰器的方式是考虑到不知经过一层property会不会影响效率,所以保留用get_XXX直接访问 # property: current_time = property(get_current_time) symbol_pool = property(get_symbol_pool) data = property(get_data) current_positions = property(get_current_positions) positions = property(get_positions) deal = property(get_deals) strategys = property(get_strategys) profit_records = property(get_profit_records) symbol_timeframe = property(get_symbol_timeframe) def update_deal(self, deal): self.__account_manager.update_deal(deal) def open_position(self, *args, **kwargs): self.__trade_manager.open_position(*args, **kwargs) def close_position(self, *args, **kwargs): self.__trade_manager.close_position(*args, **kwargs) def set_capital_base(self, base): self.__account_manager.set_capital_base(base) # ---------------------------------------------------------------------- def add_cache_info(self, *args, **kwargs): self.__data_cache.add_cache_info(*args, **kwargs) # TODO 从全局的品种池中查询 # ---------------------------------------------------------------------- def add_file(self, file): self.__event_engine.add_file(file) # ---------------------------------------------------------------------- def add_strategy(self, strategy): """添加已创建的策略实例""" self.__strategys[strategy.get_id()] = strategy strategy.engine = self # ---------------------------------------------------------------------- def put_event(self, event): # TODO 加入验证 # TODO 多了一层函数调用,尝试用绑定的形式 self.__event_engine.put(event) # ---------------------------------------------------------------------- def register_event(self, event_type, handle): """注册事件监听""" # TODO 加入验证 self.__event_engine.register(event_type, handle) def unregister_event(self, event_type, handle): """取消事件监听""" self.__event_engine.unregister(event_type, handle) # ---------------------------------------------------------------------- def write_log(self, log): """写日志""" self.__event_engine.put(Event(type=EVENT_LOG, log=log)) # ---------------------------------------------------------------------- def start(self): """启动所有策略""" for strategy in self.__strategys.values(): strategy.start() self.__data_cache.start() self.__trade_manager.init() self.__event_engine.start() # ---------------------------------------------------------------------- def stop(self): """停止所有策略""" self.__event_engine.stop() self.__data_cache.stop() for strategy in self.__strategys.values(): strategy.stop() self._recycle() # 释放资源 # ---------------------------------------------------------------------- def _recycle(self): self.__data_cache.stop() self.__trade_manager.recycle() self.__account_manager.initialize() def wait(self, call_back=None, finished=True, *args, **kwargs): """等待所有事件处理完毕 :param call_back: 运行完成时的回调函数 :param finish: 向下兼容,finish为True时,事件队列处理完成时结束整个回测引擎;为False时只是调用回调函数,继续挂起回测引擎。 """ self.__event_engine.wait() result = call_back(*args, **kwargs) if finished: self._set_finished() self.stop() return result def _set_finished(self): # 标记即不会再有新数据到来 self.__event_engine.set_finished()
class StrategyEngine(object): """策略引擎""" CACHE_MAXLEN = 10000 #---------------------------------------------------------------------- def __init__(self, backtesting=False): """Constructor""" self.__event_engine = EventEngine() # 事件处理引擎 self.__account_manager = AccountManager() #账户管理 self.__backtesting = backtesting # 是否为回测 self.__orders_done = {} # 保存所有已处理报单数据的字典 self.__orders_todo = {} # 保存所有未处理报单(即挂单)数据的字典 self.__deals = {} # 保存所有成交数据的字典 self.__positions = {} # Key:id, value:position with responding id self.__strategys = {} # 保存策略对象的字典,key为策略名称,value为策略对象 self.__datas = {} # 统一的数据视图 self.__symbols = {} # key:(symbol,timeframe),value:maxlen self.start_time = None self.end_time = None self.__current_positions = {} # key:symbol,value:current position self.__initial_positions = {}# key:symbol,value:initial position #TODO单独放入utils中 symbols = property(partial(get_attr,attr='symbols'), None, None) start_time = property(partial(get_attr,attr='start_time'), partial(set_attr,attr='start_time'),None) end_time = property(partial(get_attr,attr='end_time'), partial(set_attr,attr='end_time'),None) #---------------------------------------------------------------------- def get_current_contracts(self): #TODO 现在持仓手数 return() #---------------------------------------------------------------------- def get_current_positions(self): #TODO 读取每个品种的有效Position return(self.__current_positions) #---------------------------------------------------------------------- def get_datas(self): return(self.__datas) #---------------------------------------------------------------------- def get_profit_records(self): """获取平仓收益记录""" return(self.__account_manager.get_profit_records()) #---------------------------------------------------------------------- def get_position_records(self): """获取仓位收益记录""" def get_point(deal, entry, volume): if entry == DEAL_ENTRY_IN: if deal.type == DEAL_TYPE_BUY: return({'type':'point','x':deal.time+deal.time_msc/(10**6), 'y':deal.price,'color':'buy','text':'Buy %s'%volume}) elif deal.type == DEAL_TYPE_SELL: return({'type':'point','x':deal.time+deal.time_msc/(10**6), 'y':deal.price,'color':'short','text':'Short %s'%volume}) elif entry == DEAL_ENTRY_OUT: if deal.type == DEAL_TYPE_BUY: return({'type':'point','x':deal.time+deal.time_msc/(10**6), 'y':deal.price,'color':'cover','text':'Cover %s'%volume}) elif deal.type == DEAL_TYPE_SELL: return({'type':'point','x':deal.time+deal.time_msc/(10**6), 'y':deal.price,'color':'sell','text':'Sell %s'%volume}) def get_lines(position_start, position_end): deal_start = self.__deals[position_start.deal] deal_end = self.__deals[position_end.deal] start_time = deal_start.time+deal_start.time_msc/(10**6) end_time = deal_end.time+deal_end.time_msc/(10**6) result = {'type':'line','x_start':start_time,'x_end':end_time,'y_start':deal_start.price, 'y_end':deal_end.price} if (deal_end.type == DEAL_TYPE_BUY)^(deal_start.price>=deal_end.price): result['color'] = 'win' else: result['color'] = 'lose' def next_position(position): return(self.__positions.get(position.next_id,None)) def prev_position(position): return(self.__positions.get(position_prev_id,None)) result = [] stack = [] for symbol in {symbol for (symbol, _) in self.__symbols}: position = next_postion(self.__init_positions[symbol]) while (position != None): deal = self.__deals[position.deal] if deal.entry == DEAL_ENTRY_IN: #open or overweight position result.append(get_point(deal, DEAL_ENTRY_IN, deal.volume)) stack.append((postion,deal.volume)) else: if deal.entry == DEAL_ENTRY_INOUT: #reverse position volume_left = deal.volume - position.volume result.append(get_point(deal, DEAL_ENTRY_IN, position.volume)) else: #underweight position volume_left = deal.volume result.append(get_point(deal, DEAL_ENTYR_OUT, volume_left)) while volume_left > 0: position_start, volume = stack.pop() result.append(get_line(position_start, position)) volume_left -= volume if volume_left < 0: stack.append(position_start, -volume_left) elif deal.entry == DEAL_ENTRY_INOUT and position.volume > 0: stack.append((position, position.volume)) position = next_postion(position) return(result) #---------------------------------------------------------------------- def set_capital_base(self, base): self.__account_manager.set_capital_base(base) #---------------------------------------------------------------------- def add_symbols(self, symbols, time_frame, max_length = 0): for symbol in symbols: if (symbol,time_frame) not in self.__symbols: self.__symbols[(symbol,time_frame)] = max_length self.__symbols[(symbol,time_frame)] = max(max_length, self.__symbols[(symbol,time_frame)]) self.register_event(EVENT_BAR_SYMBOL[symbol][time_frame],self.update_bar_data) #---------------------------------------------------------------------- def initialize(self): #TODO数据结构还需修改 for (symbol, time_frame), maxlen in self.__symbols.items(): for field in ['open','high','low','close','time','volume']: if not symbol in self.__datas: self.__datas[symbol] = {} if not time_frame in self.__datas[symbol]: self.__datas[symbol][time_frame] = {} if maxlen == 0: maxlen = self.CACHE_MAXLEN for field in ['open','high','low','close','time','volume']: self.__datas[symbol][time_frame][field] = deque(maxlen=maxlen) if symbol not in self.__current_positions: position = Position(symbol) self.__current_positions[symbol] = position self.__initial_positions[symbol] = position self.__positions[position.get_id()] = position #---------------------------------------------------------------------- def add_strategy(self,strategy): """添加已创建的策略实例""" self.__strategys[strategy.get_id()] = strategy strategy.engine = self #---------------------------------------------------------------------- def update_market_data(self, event): """行情更新""" #TODO行情数据 pass #---------------------------------------------------------------------- def update_bar_data(self,event): bar = event.content['data'] symbol = bar.symbol time_frame = bar.time_frame for field in ['open','high','low','close','time','volume']: self.__datas[symbol][time_frame][field].appendleft(getattr(bar,field)) #---------------------------------------------------------------------- def __process_order(self, tick): """处理停止单""" pass #---------------------------------------------------------------------- def update_order(self, event): """报单更新""" #TODO 成交更新 #---------------------------------------------------------------------- def update_trade(self, event): """成交更新""" #TODO 成交更新 pass #---------------------------------------------------------------------- def __update_position(self, deal): def sign(num): if abs(num) <= 10**-7: return(0) elif num > 0: return(1) else: return(-1) if deal.volume == 0: return position_prev = self.__current_positions[deal.symbol] position_now = Position(deal.symbol, deal.strategy, deal.handle) position_now.prev_id = position_prev.get_id() position_prev.next_id = position_now.get_id() position = position_prev.type #XXX常量定义改变这里的映射函数也可能改变 if deal.type * position >= 0: deal.entry = DEAL_ENTRY_IN if position == 0: #open position position_now.price_open = deal.price position_now.time_open = deal.time position_now.time_open_msc = deal.time_msc else: #overweight position position_now.time_open = position_prev.time_open position_now.time_open_msc = position_prev.time_open_msc position_now.volume = deal.volume + position_prev.volume position_now.type = deal.type position_now.price_current = (position_prev.price_current*position_prev.volume +deal.price*deal.volume)/position_now.volume else: contracts = position_prev.volume - deal.volume position_now.volume = abs(contracts) position_now.type = position * sign(contracts) if position_now.type == 0: #close position deal.entry = DEAL_ENTRY_OUT deal.profit = (deal.price-position_prev.price_current)*position*position_prev.volume position_now.price_current = 0 position_now.volume = 0 #防止浮点数精度可能引起的问题 position_now.time_open = position_prev.time_open position_now.time_open_msc = position_prev.time_open_msc elif position_now != position: #reverse position deal.entry = DEAL_ENTRY_INOUT deal.profit = (deal.price-position_prev.price_current)*position*position_prev.volume position_now.price_current = deal.price position_now.time_open = deal.time position_now.time_open_msc = deal.time_msc position_now.price_open = price_now.price_current else: #underweight position #XXX 平部分仓位是直接计算入平仓收益还是将收益暂时算在浮动中 deal.entry = DEAL_ENTRY_OUT deal.profit = (deal.price-position_prev.price_current)*position*deal.volume position_now.price_current = position_prev.price_current position_now.time_open = position_prev.time_open position_now.time_open_msc = position_prev.time_open_msc position_now.time_update = deal.time position_now.time_update_msc = deal.time_msc deal.position = position_now.get_id() position_now.deal = deal.get_id() self.__current_positions[deal.symbol] = position_now self.__positions[position_now.get_id()] = position_now self.__deals[deal.get_id()] = deal if deal.profit != 0: self.__account_manager.update_deal(deal) #---------------------------------------------------------------------- @staticmethod def check_order(order): if not isinstance(order, Order): return(False) #TODO更多关于订单合法性的检查 return(True) #---------------------------------------------------------------------- def __send_order_to_broker(self,order): if self.__backtesting: time_frame = SymbolsListener.get_by_id(order.handle).get_time_frame() time_ = self.__datas[order.symbol][time_frame]["time"][0] order.time_done = int(time_) order.time_done_msc = int((time_-int(time_))*(10**6)) order.volume_current = order.volume_initial deal = Deal(order.symbol, order.strategy, order.handle) deal.volume = order.volume_current deal.time = order.time_done deal.time_msc = order.time_done_msc deal.type = 1-((order.type&1)<<1) #参见ENUM_ORDER_TYPE和ENUM_DEAL_TYPE的定义 deal.price = self.__datas[order.symbol][time_frame]["close"][0] #TODO加入手续费等 order.deal = deal.get_id() deal.order = order.get_id() return([deal],{}) #TODO 市价单成交 else: pass #TODO 实盘交易 #---------------------------------------------------------------------- def send_order(self, order): """ 发单(仅允许限价单) symbol:合约代码 direction:方向,DIRECTION_BUY/DIRECTION_SELL offset:开平,OFFSET_OPEN/OFFSET_CLOSE price:下单价格 volume:下单手数 strategy:策略对象 """ #TODO 更多属性的处理 if self.check_order(order): if order.type <= 1:#market order #send_order_to_broker = async_handle(self.__event_engine, self.__update_position)(self.__send_order_to_broker) #send_order_to_broker(order) result = self.__send_order_to_broker(order) self.__update_position(*result[0]) else: self.__orders_todo[order.get_id()] = order return(True) else: return(False) #---------------------------------------------------------------------- def cancel_order(self, order_id): """ 撤单 """ if order_id == 0: self.__orders_todo = {} else: if order_id in self.__orders_todo: del(self.__orders_todo[order_id]) #---------------------------------------------------------------------- def put_event(self, event): #TODO 加入验证 #TODO 多了一层函数调用,尝试用绑定的形式 self.__event_engine.put(event) #---------------------------------------------------------------------- def register_event(self, event_type, handle): """注册事件监听""" #TODO 加入验证 self.__event_engine.register(event_type, handle) def unregister_event(self, event_type, handle): """取消事件监听""" self.__event_engine.unregister(event_type, handle) #---------------------------------------------------------------------- def writeLog(self, log): """写日志""" event = Event(type_=EVENT_LOG) event.content['log'] = log self.__event_engine.put(event) #---------------------------------------------------------------------- def start(self): """启动所有策略""" self.__event_engine.start() for strategy in self.__strategys.values(): strategy.start() #---------------------------------------------------------------------- def stop(self): """停止所有策略""" self.__event_engine.stop() for strategy in self.__strategys.values(): strategy.stop() def wait(self): """等待所有事件处理完毕""" self.__event_engine.wait() self.stop() #TODO 对限价单的支持 #---------------------------------------------------------------------- def sell(self, symbol, volume=1, price=None, stop=False ,limit=False, strategy=None, listener=None): if volume == 0: return position = self.__current_positions.get(symbol,None) if not position or position.type <= 0: return#XXX可能的返回值 order = Order(symbol, ORDER_TYPE_SELL, strategy, listener) order.volume_initial = volume if self.__backtesting: time_ = self.__datas[symbol][SymbolsListener.get_by_id(listener).get_time_frame()]['time'][0] else: time_ = time.time() order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_))*(10**6)) return(self.send_order(order)) #---------------------------------------------------------------------- def buy(self, symbol, volume=1, price=None, stop=False, limit=False, strategy=None, listener=None): if volume == 0: return position = self.__current_positions.get(symbol,None) order = Order(symbol, ORDER_TYPE_BUY, strategy, listener) if position and position.type < 0: order.volume_initial = volume + position.volume else: order.volume_initial = volume if self.__backtesting: time_ = self.__datas[symbol][SymbolsListener.get_by_id(listener).get_time_frame()]['time'][0] else: time_ = time.time() order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_))*(10**6)) return(self.send_order(order)) #---------------------------------------------------------------------- def cover(self, symbol, volume=1, price=None, stop=False, limit=False, strategy=None, listener=None): if volume == 0: return position = self.__current_positions.get(symbol,None) order = Order(symbol, ORDER_TYPE_BUY, strategy, listener) if not position or position.type >= 0: return#XXX可能的返回值 order.volume_initial = volume if self.__backtesting: time_ = self.__datas[symbol][SymbolsListener.get_by_id(listener).get_time_frame()]['time'][0] else: time_ = time.time() order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_))*(10**6)) return(self.send_order(order)) #---------------------------------------------------------------------- def short(self, symbol, volume=1, price=None, stop=False, limit=False, strategy=None, listener=None): if volume == 0: return position = self.__current_positions.get(symbol,None) order = Order(symbol, ORDER_TYPE_SELL, strategy, listener) if position and position.type > 0: order.volume_initial = volume + position.volume else: order.volume_initial = volume if self.__backtesting: time_ = self.__datas[symbol][SymbolsListener.get_by_id(listener).get_time_frame()]['time'][0] else: time_ = time.time() order.time_setup = int(time_) order.time_setup_msc = int((time_ - int(time_))*(10**6)) return(self.send_order(order))