def _valid_order(self, order): """ 判断订单是否合法。 """ if order.quantity <= 0: raise TradingError(err="交易数量不能小于0") # 撤单 if order.side == TradeSide.CANCEL: if order not in self.open_orders: raise TradingError(err='撤销失败: 不存在该订单!') if order.side == TradeSide.PING: try: poskey = PositionKey(order.contract, order.direction) pos = self.positions[poskey] if pos.closable < order.quantity: raise TradingError(err='可平仓位不足') except KeyError: # 没有持有该合约 #logger.warn("不存在合约[%s]" % order.contract) raise TradingError(err="不存在合约[%s]" % order.contract) elif order.side == TradeSide.KAI: new_price = self._ticks[order.contract] if self.holding['cash'] < order.order_margin(new_price): raise TradingError(err='没有足够的资金开仓') else: self.holding['cash'] -= order.order_margin(new_price) return True
def _valid_order(self, order): if order.quantity <= 0: logger.warn("下单数量错误!") return False """ 判断订单是否合法。 """ if order.side == TradeSide.PING: try: poskey = PositionKey(order.contract, order.direction) pos = self.positions[poskey] if pos.quantity >= order.quantity: return True except KeyError: # 没有持有该合约 logger.warn("不存在合约[%s]" % order.contract) #assert False return False logger.warn("下单仓位问题") return False elif order.side == TradeSide.KAI: if self.holding['cash'] < order.price * order.quantity: raise TradingError(err='没有足够的资金开仓') else: new_price = self._ticks[order.contract] self.holding['cash'] -= order.order_margin(new_price) return True
def update_signal(self, event): """ 处理策略函数产生的下单事件。 可能产生一系列order事件,在bar的开盘时间交易。 """ assert event.type == Event.SIGNAL new_orders = [] for order in event.orders: errmsg = self._valid_order(order) if errmsg == '': order.datetime = self._datetime new_orders.append(order) if order.side == TradeSide.KAI: self.holding['cash'] -= \ order.order_margin(self._bars[order.contract].open) else: logger.warn(errmsg) # print len(event.orders), len(new_orders) continue self.open_orders.update(new_orders) # 改变对象的值,不改变对象地址。 self._all_orders.extend(new_orders) for order in new_orders: self.api.order(copy.deepcopy(order)) for order in new_orders: if order.side == TradeSide.PING: pos = self.positions[ PositionKey(order.contract, order.direction)] pos.closable -= order.quantity
def _update_positions(current_positions, deal_positions, trans): """ 更新持仓 current_positions: 当前持仓 deal_positions: 开平仓对 """ class PositionsDetail(object): """ 当前相同合约持仓集合(可能不同时间段下单)。 :ivar cost: 持仓成本。 :ivar total: 持仓总数。 :ivar positions: 持仓集合。 :vartype positions: list """ def __init__(self): self.total = 0 self.positions = [] self.cost = 0 assert trans.quantity > 0 poskey = PositionKey(trans.contract, trans.direction) p = current_positions.setdefault(poskey, PositionsDetail()) if trans.side == TradeSide.KAI: # 开仓 p.positions.append(trans) p.total += trans.quantity elif trans.side == TradeSide.PING: # 平仓 assert (len(p.positions) > 0 and '所平合约没有持仓') left_vol = trans.quantity last_index = 0 p.total -= trans.quantity for position in reversed(p.positions): if position.quantity < left_vol: # 还需从之前的仓位中平。 left_vol -= position.quantity last_index -= 1 deal_positions.append( OneDeal(position, trans, position.quantity)) elif position.quantity == left_vol: left_vol -= position.quantity last_index -= 1 deal_positions.append( OneDeal(position, trans, position.quantity)) break else: position.quantity -= left_vol left_vol = 0 deal_positions.append(OneDeal(position, trans, left_vol)) break if last_index != 0: p.positions = p.positions[0:last_index] assert (left_vol == 0) # 会被catch捕获 AssertError
def _update_holding(self, trans): """ 更新佣金和平仓盈亏。 """ if trans.side == TradeSide.CANCEL: return self.holding['commission'] += trans.commission # 平仓,更新历史持仓盈亏。 if trans.side == TradeSide.PING: poskey = PositionKey(trans.contract, trans.direction) flag = 1 if trans.direction == Direction.LONG else -1 profit = (trans.price-self.positions[poskey].cost) * \ trans.quantity * flag * trans.volume_multiple self.holding['history_profit'] += profit self._all_transactions.append(trans)
def _update_holding(self, trans): """ 更新佣金和平仓盈亏。 """ # 每笔佣金,和数目无关! self.holding['commission'] += trans.commission # 平仓,更新历史持仓盈亏。 if trans.side == TradeSide.PING: poskey = PositionKey(trans.contract, trans.direction) multi = 1 if trans.direction == Direction.LONG else -1 profit = (trans.price - self.positions[poskey].cost) * trans.quantity * multi self.holding['history_profit'] += profit self._all_transactions.append(trans)
def _update_positions(self, trans): """ 更新持仓 """ poskey = PositionKey(trans.contract, trans.direction) pos = self.positions.setdefault(poskey, Position(trans)) #print len(self.positions) #print pos.contract, pos.quantity if trans.side == TradeSide.KAI: # 开仓 pos.cost = (pos.cost * pos.quantity + trans.price * trans.quantity) / (pos.quantity + trans.quantity) pos.quantity += trans.quantity elif trans.side == TradeSide.PING: # 平仓 pos.quantity -= trans.quantity if pos.quantity == 0: del self.positions[poskey]
def update_datetime(self, dt): """ 在新的价格数据来的时候触发。 """ if self._datetime == None: self._datetime = dt self._start_date = dt self._init_state() elif self._datetime.date() != dt.date(): for order in self.open_orders: if order.side == TradeSide.PING: pos = self.positions[PositionKey(order.contract, order.direction)] pos.closable += order.quantity self.open_orders.clear() for key, pos in self.positions.iteritems(): pos.closable += pos.today pos.today = 0 self._datetime = dt
def update_signal(self, event): """ 处理策略函数产生的下单事件。 """ assert event.type == Event.SIGNAL new_orders = [] for order in event.orders: if self._valid_order(order): order.datetime = self._datetime self.api.order(copy.deepcopy(order)) new_orders.append(order) else: continue self.open_orders.update(new_orders) # 改变对象的值,不改变对象地址。 self._all_orders.extend(new_orders) for order in new_orders: if order.side == TradeSide.PING: pos = self.positions[PositionKey(order.contract, order.direction)] pos.closable -= order.quantity
def _update_positions(self, trans): """ 更新持仓 """ poskey = PositionKey(trans.contract, trans.direction) if trans.side == TradeSide.CANCEL: pos = self.positions.get(poskey, None) if pos: pos.closable += trans.quantity return pos = self.positions.setdefault(poskey, Position(trans)) if trans.side == TradeSide.KAI: pos.cost = (pos.cost*pos.quantity + trans.price*trans.quantity) / \ (pos.quantity+trans.quantity) pos.quantity += trans.quantity if trans.contract.is_stock: pos.today += trans.quantity else: pos.closable += trans.quantity assert(pos.quantity == pos.today + pos.closable) elif trans.side == TradeSide.PING: pos.quantity -= trans.quantity if pos.quantity == 0: del self.positions[poskey]
def position(self, direction='long', symbol=None): """ 合约当前持仓仓位。 Args: direction (str/int): 持仓方向。多头 - 'long' / 1 ;空头 - 'short' / 2 , 默认为多头。 symbol (str): 字符串合约,默认为None表示主合约。 Returns: Position. 该合约的持仓 """ if not self.on_bar: raise Exception('只有on_bar函数内能查询当前持仓!') direction = Direction.arg_to_type(direction) contract = Contract(symbol) if symbol else \ self.contract # @TODO assert direction try: poskey = PositionKey(contract, direction) return self.blotter.positions[poskey] except KeyError: return None
def _valid_order(self, order): """ 判断订单是否合法。 """ if order.quantity <= 0: return "交易数量要大于0" # 撤单 if order.side == TradeSide.CANCEL: if order not in self.open_orders: return '撤销失败: 不存在该订单!' if order.side == TradeSide.PING: try: poskey = PositionKey(order.contract, order.direction) pos = self.positions[poskey] if pos.closable < order.quantity: return '可平仓位不足' except KeyError: # 没有持有该合约 # logger.warn("不存在合约[%s]" % order.contract) return "不存在合约[%s]" % order.contract elif order.side == TradeSide.KAI: new_price = self._bars[order.contract].open if self.holding['cash'] < order.order_margin(new_price): # print self.holding['cash'], new_price * order.quantity return '没有足够的资金开仓' return ''
def pos(self, contract, direction): try: poskey = PositionKey(contract, direction) return self.blotter.positions[poskey].closable except KeyError: return 0
def _update_positions(self, current_positions, deal_positions, trans): """ 根据交易明细计算开平仓对。 """ class PositionsDetail(object): """ 当前相同合约持仓集合(可能不同时间段下单)。 :ivar cost: 持仓成本。 :ivar total: 持仓总数。 :ivar positions: 持仓集合。 :vartype positions: list """ def __init__(self): self.total = 0 self.positions = [] self.cost = 0 assert trans.quantity > 0 poskey = PositionKey(trans.contract, trans.direction) p = current_positions.setdefault(poskey, PositionsDetail()) if trans.side == TradeSide.KAI: # 开仓 p.positions.append(trans) p.total += trans.quantity elif trans.side == TradeSide.PING: # 平仓 assert(len(p.positions) > 0 and '所平合约没有持仓') left_vol = trans.quantity last_index = 0 search_index = 0 p.total -= trans.quantity if trans.contract.is_stock: for position in reversed(p.positions): # 开仓日期小于平仓时间 if position.datetime.date() < trans.datetime.date(): break search_index -= 1 if search_index != 0: positions = p.positions[:search_index] left_positions = p.positions[search_index:] else: positions = p.positions for position in reversed(positions): if position.quantity < left_vol: # 还需从之前的仓位中平。 left_vol -= position.quantity last_index -= 1 deal_positions.append( OneDeal(position, trans, position.quantity)) elif position.quantity == left_vol: left_vol -= position.quantity last_index -= 1 deal_positions.append( OneDeal(position, trans, position.quantity)) break else: position.quantity -= left_vol left_vol = 0 deal_positions.append(OneDeal(position, trans, left_vol)) break if last_index != 0 and search_index != 0: p.positions = positions[0:last_index] + left_positions elif last_index != 0: p.positions = positions[0:last_index] # last_index == 0, 表示没找到可平的的开仓对,最后一根强平 # 可以被catch捕获 AssertError assert(left_vol == 0 or last_index == 0)
def position(self, contract, direction): try: poskey = PositionKey(contract, direction) return self.blotter.positions[poskey].quantity except KeyError: return 0