def update_position(self, current_position, order_amount, current_price, order_type, timestamp): """ :param timestamp: :type timestamp: :param current_position: :type current_position: Position :param order_amount: :type order_amount: :param current_price: :type current_price: :param order_type: :type order_type: """ if order_type == ORDER_TYPE_LONG: need_money = (order_amount * current_price) * (1 + self.slippage + self.buy_cost) if self.latest_account['cash'] < need_money: raise NotEnoughMoneyError() self.latest_account['cash'] -= need_money # 计算平均价 long_amount = current_position['long_amount'] + order_amount current_position['average_long_price'] = (current_position['average_long_price'] * current_position[ 'long_amount'] + current_price * order_amount) / long_amount current_position['long_amount'] = long_amount if current_position['trading_t'] == 0: current_position['available_long'] += order_amount elif order_type == ORDER_TYPE_SHORT: need_money = (order_amount * current_price) * (1 + self.slippage + self.buy_cost) if self.latest_account['cash'] < need_money: raise NotEnoughMoneyError self.latest_account['cash'] -= need_money short_amount = current_position['short_amount'] + order_amount current_position['average_short_price'] = (current_position['average_short_price'] * current_position[ 'short_amount'] + current_price * order_amount) / short_amount current_position['short_amount'] = short_amount if current_position['trading_t'] == 0: current_position['available_short'] += order_amount elif order_type == ORDER_TYPE_CLOSE_LONG: self.latest_account['cash'] += (order_amount * current_price * (1 - self.slippage - self.sell_cost)) current_position['available_long'] -= order_amount current_position['long_amount'] -= order_amount elif order_type == ORDER_TYPE_CLOSE_SHORT: self.latest_account['cash'] += 2 * (order_amount * current_position['average_short_price']) self.latest_account['cash'] -= order_amount * current_price * (1 + self.slippage + self.sell_cost) current_position['available_short'] -= order_amount current_position['short_amount'] -= order_amount # save the order info to db order_id = '{}_{}_{}_{}'.format(self.trader_name, order_type, current_position['security_id'], to_time_str(timestamp, TIME_FORMAT_ISO8601)) order = Order(id=order_id, timestamp=to_pd_timestamp(timestamp), trader_name=self.trader_name, security_id=current_position['security_id'], order_price=current_price, order_amount=order_amount, order_type=order_type, status='success') self.session.add(order) self.session.commit()
def order(self, entity_id, current_price, current_timestamp, order_amount=0, order_pct=1.0, order_price=0, order_type=ORDER_TYPE_LONG, order_money=0): """ 下单 Parameters ---------- entity_id : str 交易标的id current_price : float 当前价格 current_timestamp: timestamp 下单的时间 order_amount : int 数量 order_pct : float 使用可用现金(仓位)的百分比,0.0-1.0 order_price : float 用于限价交易 order_type : {ORDER_TYPE_LONG,ORDER_TYPE_SHORT,ORDER_TYPE_CLOSE_LONG,ORDER_TYPE_CLOSE_SHORT} 交易类型 Returns """ # 市价交易,就是买卖是"当时"并"一定"能成交的 # 简单起见,目前只支持这种方式 if order_price == 0: current_position = self.get_current_position(entity_id=entity_id) if not current_position: trading_t = get_trading_meta(entity_id=entity_id)['trading_t'] current_position = { 'trader_name': self.trader_name, 'entity_id': entity_id, 'long_amount': 0, 'available_long': 0, 'average_long_price': 0, 'short_amount': 0, 'available_short': 0, 'average_short_price': 0, 'profit': 0, 'value': 0, 'trading_t': trading_t } # add it to latest account self.latest_account['positions'].append(current_position) # 按钱交易 if order_money > 0: # 开多 if order_type == ORDER_TYPE_LONG: if current_position['short_amount'] > 0: raise InvalidOrderError( "close the short position before open long") if order_money > self.latest_account['cash']: raise NotEnoughMoneyError() cost = current_price * (1 + self.slippage + self.buy_cost) # 买的数量 order_amount = order_money // cost if order_amount > 0: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise NotEnoughMoneyError() # 开空 elif order_type == ORDER_TYPE_SHORT: if current_position['long_amount'] > 0: raise InvalidOrderError( "close the long position before open short") if order_money > self.latest_account['cash']: raise NotEnoughMoneyError() cost = current_price * (1 + self.slippage + self.buy_cost) order_amount = order_money // cost if order_amount > 0: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise NotEnoughMoneyError() else: raise InvalidOrderParamError( 'close long/short not support order_money') # 按数量交易 elif order_amount > 0: # 开多 if order_type == ORDER_TYPE_LONG: if current_position['short_amount'] > 0: raise InvalidOrderError( "close the short position before open long") self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) # 开空 elif order_type == ORDER_TYPE_SHORT: if current_position['long_amount'] > 0: raise InvalidOrderError( "close the long position before open short") self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) # 平多 elif order_type == ORDER_TYPE_CLOSE_LONG: if current_position['available_long'] >= order_amount: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise NotEnoughPositionError() # 平空 elif order_type == ORDER_TYPE_CLOSE_SHORT: if current_position['available_short'] >= order_amount: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise Exception("not enough position") # 按仓位比例交易 elif 0 < order_pct <= 1: # 开多 if order_type == ORDER_TYPE_LONG: if current_position['short_amount'] > 0: raise InvalidOrderError( "close the short position before open long") cost = current_price * (1 + self.slippage + self.buy_cost) want_pay = self.latest_account['cash'] * order_pct # 买的数量 order_amount = want_pay // cost if order_amount > 0: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise NotEnoughMoneyError() # 开空 elif order_type == ORDER_TYPE_SHORT: if current_position['long_amount'] > 0: raise InvalidOrderError( "close the long position before open short") cost = current_price * (1 + self.slippage + self.buy_cost) want_pay = self.latest_account['cash'] * order_pct order_amount = want_pay // cost if order_amount > 0: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise NotEnoughMoneyError() # 平多 elif order_type == ORDER_TYPE_CLOSE_LONG: if current_position['available_long'] > 0: if order_pct == 1.0: order_amount = current_position['available_long'] else: order_amount = math.floor( current_position['available_long'] * order_pct) if order_amount != 0: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: self.logger.warning( "{} available_long:{} order_pct:{} order_amount:{}", entity_id, current_position['available_long'], order_pct, order_amount) else: raise NotEnoughPositionError() # 平空 elif order_type == ORDER_TYPE_CLOSE_SHORT: if current_position['available_short'] > 0: if order_pct == 1.0: order_amount = current_position['available_short'] else: order_amount = math.floor( current_position['available_short'] * order_pct) if order_amount != 0: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: self.logger.warning( "{} available_long:{} order_pct:{} order_amount:{}", entity_id, current_position['available_long'], order_pct, order_amount) else: raise Exception("not enough position")
def update_position(self, current_position, order_amount, current_price, order_type, timestamp): """ :param timestamp: :type timestamp: :param current_position: :type current_position: Position :param order_amount: :type order_amount: :param current_price: :type current_price: :param order_type: :type order_type: """ if order_type == ORDER_TYPE_LONG: need_money = (order_amount * current_price) * (1 + self.slippage + self.buy_cost) if self.account.cash < need_money: if self.rich_mode: self.input_money() else: raise NotEnoughMoneyError() self.account.cash -= need_money # 计算平均价 long_amount = current_position.long_amount + order_amount if long_amount == 0: current_position.average_long_price = 0 current_position.average_long_price = ( current_position.average_long_price * current_position.long_amount + current_price * order_amount) / long_amount current_position.long_amount = long_amount if current_position.trading_t == 0: current_position.available_long += order_amount elif order_type == ORDER_TYPE_SHORT: need_money = (order_amount * current_price) * (1 + self.slippage + self.buy_cost) if self.account.cash < need_money: if self.rich_mode: self.input_money() else: raise NotEnoughMoneyError() self.account.cash -= need_money short_amount = current_position.short_amount + order_amount current_position.average_short_price = ( current_position.average_short_price * current_position.short_amount + current_price * order_amount) / short_amount current_position.short_amount = short_amount if current_position.trading_t == 0: current_position.available_short += order_amount elif order_type == ORDER_TYPE_CLOSE_LONG: self.account.cash += order_amount * current_price * ( 1 - self.slippage - self.sell_cost) # FIXME:如果没卖完,重新计算计算平均价 current_position.available_long -= order_amount current_position.long_amount -= order_amount elif order_type == ORDER_TYPE_CLOSE_SHORT: self.account.cash += 2 * (order_amount * current_position.average_short_price) self.account.cash -= order_amount * current_price * ( 1 + self.slippage + self.sell_cost) current_position.available_short -= order_amount current_position.short_amount -= order_amount # save the order info to db order_id = "{}_{}_{}_{}".format( self.trader_name, order_type, current_position.entity_id, to_time_str(timestamp, TIME_FORMAT_ISO8601)) order = Order( id=order_id, timestamp=to_pd_timestamp(timestamp), trader_name=self.trader_name, entity_id=current_position.entity_id, order_price=current_price, order_amount=order_amount, order_type=order_type, level=self.level.value, status="success", ) self.session.add(order) self.session.commit()
def order( self, entity_id, current_price, current_timestamp, order_amount=0, order_pct=1.0, order_price=0, order_type=ORDER_TYPE_LONG, order_money=0, ): """ 下单 Parameters ---------- entity_id : str 交易标的id current_price : float 当前价格 current_timestamp: timestamp 下单的时间 order_amount : int 数量 order_pct : float 使用可用现金(仓位)的百分比,0.0-1.0 order_price : float 用于限价交易 order_type : {ORDER_TYPE_LONG,ORDER_TYPE_SHORT,ORDER_TYPE_CLOSE_LONG,ORDER_TYPE_CLOSE_SHORT} 交易类型 Returns """ # 市价交易,就是买卖是"当时"并"一定"能成交的 # 简单起见,目前只支持这种方式 if order_price == 0: current_position = self.get_current_position(entity_id=entity_id) if not current_position: trading_t = self.entity_schema.get_trading_t() current_position = Position( trader_name=self.trader_name, entity_id=entity_id, long_amount=0, available_long=0, average_long_price=0, short_amount=0, available_short=0, average_short_price=0, profit=0, value=0, trading_t=trading_t, ) # add it to latest account self.account.positions.append(current_position) # 按钱交易 if order_money > 0: # 开多 if order_type == ORDER_TYPE_LONG: if current_position.short_amount > 0: raise InvalidOrderError( "close the short position before open long") if order_money > self.account.cash: if self.rich_mode: self.input_money() else: raise NotEnoughMoneyError() cost = current_price * (1 + self.slippage + self.buy_cost) # 买的数量 order_amount = order_money // cost if order_amount < 1: self.logger.error( f"invalid order_money:{order_money}, cost:{cost}, order_amount:{order_amount}" ) return self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) # 开空 elif order_type == ORDER_TYPE_SHORT: if current_position.long_amount > 0: raise InvalidOrderError( "close the long position before open short") if order_money > self.account.cash: if self.rich_mode: self.input_money() else: raise NotEnoughMoneyError() cost = current_price * (1 + self.slippage + self.buy_cost) order_amount = order_money // cost if order_amount < 1: self.logger.error( f"invalid order_money:{order_money}, cost:{cost}, order_amount:{order_amount}" ) return self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise InvalidOrderParamError( "close long/short not support order_money") # 按数量交易 elif order_amount > 0: # 开多 if order_type == ORDER_TYPE_LONG: if current_position.short_amount > 0: raise InvalidOrderError( "close the short position before open long") self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) # 开空 elif order_type == ORDER_TYPE_SHORT: if current_position.long_amount > 0: raise InvalidOrderError( "close the long position before open short") self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) # 平多 elif order_type == ORDER_TYPE_CLOSE_LONG: if current_position.available_long >= order_amount: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise NotEnoughPositionError() # 平空 elif order_type == ORDER_TYPE_CLOSE_SHORT: if current_position.available_short >= order_amount: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: raise Exception("not enough position") # 按仓位比例交易 elif 0 < order_pct <= 1: # 开多 if order_type == ORDER_TYPE_LONG: if current_position.short_amount > 0: raise InvalidOrderError( "close the short position before open long") cost = current_price * (1 + self.slippage + self.buy_cost) want_pay = self.account.cash * order_pct # 买的数量 order_amount = want_pay // cost if order_amount < 1: if self.rich_mode: self.input_money() order_amount = max( (self.account.cash * order_pct) // cost, 1) else: raise NotEnoughMoneyError() self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) # 开空 elif order_type == ORDER_TYPE_SHORT: if current_position.long_amount > 0: raise InvalidOrderError( "close the long position before open short") cost = current_price * (1 + self.slippage + self.buy_cost) want_pay = self.account.cash * order_pct order_amount = want_pay // cost if order_amount < 1: if self.rich_mode: self.input_money() order_amount = max( (self.account.cash * order_pct) // cost, 1) else: raise NotEnoughMoneyError() self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) # 平多 elif order_type == ORDER_TYPE_CLOSE_LONG: if current_position.available_long > 0: if order_pct == 1.0: order_amount = current_position.available_long else: order_amount = math.floor( current_position.available_long * order_pct) if order_amount != 0: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: self.logger.warning( f"{entity_id} available_long:{current_position.available_long} order_pct:{order_pct} order_amount:{order_amount}" ) else: raise NotEnoughPositionError() # 平空 elif order_type == ORDER_TYPE_CLOSE_SHORT: if current_position.available_short > 0: if order_pct == 1.0: order_amount = current_position.available_short else: order_amount = math.floor( current_position.available_short * order_pct) if order_amount != 0: self.update_position(current_position, order_amount, current_price, order_type, current_timestamp) else: self.logger.warning( f"{entity_id} available_long:{current_position.available_long} order_pct:{order_pct} order_amount:{order_amount}" ) else: raise Exception("not enough position")
def order(self, security_id, current_price, current_timestamp, order_amount=0, order_pct=1.0, order_price=0, order_type=ORDER_TYPE_LONG): """ 下单 Parameters ---------- security_id : str 交易标的id current_price : float 当前价格 current_timestamp: timestamp 下单的时间 order_amount : int 数量 order_pct : float 使用可用现金(仓位)的百分比,0.0-1.0 order_price : float 用于限价交易 order_type : {ORDER_TYPE_LONG,ORDER_TYPE_SHORT,ORDER_TYPE_CLOSE_LONG,ORDER_TYPE_CLOSE_SHORT} 交易类型 Returns ------- """ # 市价交易,就是买卖是"当时"并"一定"能成交的 # 简单起见,目前只支持这种方式 if order_price == 0: current_position: Position = self.get_current_position(security_id=security_id) the_id = '{}_{}_{}'.format(self.trader_name, security_id, to_time_str(current_timestamp, TIME_FORMAT_ISO8601)) if not current_position: current_position = Position(id=the_id, trader_name=self.trader_name, timestamp=current_timestamp, security_id=security_id, long_amount=0, available_long=0, average_long_price=0, short_amount=0, available_short=0, average_short_price=0, profit=0, value=0) else: current_position = Position(id=the_id, trader_name=self.trader_name, timestamp=current_timestamp, security_id=security_id, long_amount=current_position.long_amount, available_long=current_position.available_long, average_long_price=current_position.average_long_price, short_amount=current_position.short_amount, available_short=current_position.available_short, average_short_price=current_position.average_short_price, profit=current_position.profit, value=current_position.value) # 按数量交易 if order_amount > 0: # 开多 if order_type == ORDER_TYPE_LONG: if current_position.short_amount > 0: raise InvalidOrderError("close the short position before open long") self.update_position(current_position, order_amount, current_price, order_type) # 开空 elif order_type == ORDER_TYPE_SHORT: if current_position.long_amount > 0: raise InvalidOrderError("close the long position before open short") self.update_position(current_position, order_amount, current_price, order_type) # 平多 elif order_type == ORDER_TYPE_CLOSE_LONG: if current_position.available_long >= order_amount: self.update_position(current_position, order_amount, current_price, order_type) else: raise NotEnoughPositionError() # 平空 elif order_type == ORDER_TYPE_CLOSE_SHORT: if current_position.available_short >= order_amount: self.update_position(current_position, order_amount, current_price, order_type) else: raise Exception("not enough position") # 按仓位比例交易 elif 0 < order_pct <= 1: # 开多 if order_type == ORDER_TYPE_LONG: if current_position.short_amount > 0: raise InvalidOrderError("close the short position before open long") cost = current_price * (1 + self.slippage + self.buy_cost) want_pay = self.latest_account.cash * order_pct # 买的数量 order_amount = want_pay // cost if order_amount > 0: self.update_position(current_position, order_amount, current_price, order_type) else: raise NotEnoughMoneyError() # 开空 elif order_type == ORDER_TYPE_SHORT: if current_position.long_amount > 0: raise InvalidOrderError("close the long position before open short") cost = current_price * (1 + self.slippage + self.buy_cost) want_pay = self.latest_account.cash * order_pct order_amount = want_pay // cost if order_amount > 0: self.update_position(current_position, order_amount, current_price, order_type) else: raise NotEnoughMoneyError() # 平多 elif order_type == ORDER_TYPE_CLOSE_LONG: if current_position.available_long > 1: if order_pct == 1.0: order_amount = current_position.available_long else: order_amount = math.floor(current_position.available_long * order_pct) if order_amount != 0: self.update_position(current_position, order_amount, current_price, order_type) else: self.logger.warning("{} available_long:{} order_pct:{} order_amount:{}", security_id, current_position.available_long, order_pct, order_amount) else: raise NotEnoughPositionError() # 平空 elif order_type == ORDER_TYPE_CLOSE_SHORT: if current_position.available_short > 1: if order_pct == 1.0: order_amount = current_position.available_short else: order_amount = math.floor(current_position.available_short * order_pct) if order_amount != 0: self.update_position(current_position, order_amount, current_price, order_type) else: self.logger.warning("{} available_long:{} order_pct:{} order_amount:{}", security_id, current_position.available_long, order_pct, order_amount) else: raise Exception("not enough position") self.update_account(security_id, current_position, current_timestamp)