def open(self, trader, instrument, direction, order_type, order_price, quantity, take_profit, stop_loss, leverage=1.0, hedging=None): """ Open a position or buy an asset. @param hedging If defined use the defined value else use the default from the market. """ order = Order(trader, instrument.market_id) order.direction = direction order.order_type = order_type order.quantity = quantity order.leverage = leverage order.margin_trade = True order.post_only = False if order_type == Order.ORDER_LIMIT: order.price = order_price if hedging: order.hedging = hedging # generated a reference order id trader.set_ref_order_id(order) self.create_ref_oid = order.ref_order_id self.dir = order.direction self.op = order.price # retains the order price self.oq = order.quantity # ordered quantity self.tp = take_profit self.sl = stop_loss self.leverage = leverage self._stats['entry-order-type'] = order.order_type if trader.create_order(order, instrument): # keep the related create position identifier if available self.create_oid = order.order_id self.position_id = order.position_id if not self.eot and order.created_time: # only at the first open self.eot = order.created_time return True else: self._entry_state = StrategyTrade.STATE_REJECTED return False
def modify_take_profit(self, trader, instrument, limit_price): if self.limit_oid: # cancel the limit order and create a new one if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None self.limit_oid = None self.limit_order_qty = 0.0 else: return False if self.e == self.x: # all entry qty is filled return True if self.e < self.x: # something wrong but its ok return False if self.position_id: # if not accepted as modification do it as limit order if trader.modify_position(self.position_id, take_profit_price=limit_price): self.tp = limit_price return True elif self.e > 0: # only if filled entry partially or totally order = Order(self, instrument.market_id) order.direction = -self.direction order.order_type = Order.ORDER_LIMIT order.reduce_only = True order.quantity = self.e - self.x # remaining order.price = limit_price order.leverage = self.leverage order.margin_trade = True trader.set_ref_order_id(order) self.limit_ref_oid = order.ref_order_id self._stats['limit-order-type'] = order.order_type if trader.create_order(order): self.limit_oid = order.order_id self.limit_order_qty = order.quantity self.last_tp_ot[0] = order.created_time self.last_tp_ot[1] += 1 self.tp = limit_price return True else: self.limit_ref_oid = None self.limit_order_qty = 0.0 return False
def open(self, trader, market_id, direction, order_type, order_price, quantity, take_profit, stop_loss, leverage=1.0, hedging=None): """ Open a position or buy an asset. @param hedging If defined use the defined value else use the default from the market. """ order = Order(trader, market_id) order.direction = direction order.order_price = order_price order.order_type = order_type order.quantity = quantity order.leverage = leverage if hedging: order.hedging = hedging # generated a reference order id trader.set_ref_order_id(order) self.create_ref_oid = order.ref_order_id self.dir = order.direction self.op = order.order_price # retains the order price self.oq = order.quantity # ordered quantity self.tp = take_profit self.sl = stop_loss self._stats['entry-maker'] = not order.is_market() if trader.create_order(order): # keep the related create position identifier if available self.position_id = order.position_id if not self.eot and order.created_time: # only at the first open self.eot = order.created_time return True else: self.create_ref_oid = None return False
def modify_take_profit(self, trader, instrument, limit_price): if self.limit_oid: # cancel the limit order and create a new one if trader.cancel_order(self.limit_oid, instrument): self.limit_ref_oid = None self.limit_oid = None self.limit_order_qty = 0.0 else: return self.ERROR if self.e == self.x: # all entry qty is filled return self.NOTHING_TO_DO if self.e < self.x: # something wrong but its ok return self.NOTHING_TO_DO if self.e > 0 and limit_price > 0.0: # only if filled entry partially or totally order = Order(self, instrument.market_id) order.direction = -self.direction order.order_type = Order.ORDER_LIMIT order.reduce_only = True order.quantity = self.e - self.x # remaining order.price = limit_price order.leverage = self.leverage order.margin_trade = True trader.set_ref_order_id(order) self.limit_ref_oid = order.ref_order_id self._stats['take-profit-order-type'] = order.order_type if trader.create_order(order, instrument): self.limit_oid = order.order_id self.limit_order_qty = order.quantity self.last_tp_ot[0] = order.created_time self.last_tp_ot[1] += 1 self.tp = limit_price return self.ACCEPTED else: self.limit_ref_oid = None self.limit_order_qty = 0.0 return self.REJECTED return self.NOTHING_TO_DO
def close(self, trader, instrument): """ Close the position and cancel the related orders. """ if self._closing: # already closing order return False if self.create_oid: # cancel the remaining buy order if trader.cancel_order(self.create_oid): self.create_ref_oid = None self.create_oid = None self._entry_state = StrategyTrade.STATE_CANCELED if self.stop_oid: # cancel the stop order if trader.cancel_order(self.stop_oid): self.stop_ref_oid = None self.stop_oid = None if self.limit_oid: # cancel the limit order if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None if self.e - self.x > 0.0: # bitmex case no have position id order = Order(trader, instrument.market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_MARKET order.reduce_only = True order.quantity = self.e - self.x # remaining qty order.leverage = self.leverage order.margin_trade = True # generated a reference order id trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id self._stats['stop-order-type'] = order.order_type if trader.create_order(order): self.stop_oid = order.order_id self.stop_order_qty = order.quantity # closing order defined self._closing = True return True else: self.stop_ref_oid = None return False return True
def open(self, trader, instrument, direction, order_type, order_price, quantity, take_profit, stop_loss, leverage=1.0, hedging=None): """ Open a position or buy an asset. """ order = Order(trader, instrument.market_id) order.direction = direction order.price = order_price order.order_type = order_type order.quantity = quantity order.post_only = False order.margin_trade = True order.leverage = leverage # generated a reference order id trader.set_ref_order_id(order) self.create_ref_oid = order.ref_order_id self.dir = order.direction self.op = order.price # retains the order price self.oq = order.quantity # ordered quantity self.tp = take_profit self.sl = stop_loss self.leverage = leverage self._stats['entry-order-type'] = order.order_type if trader.create_order(order, instrument): self.position_id = order.position_id # might be market-id if not self.eot and order.created_time: self.eot = order.created_time return True else: self._entry_state = StrategyTrade.STATE_REJECTED return False
def modify_stop_loss(self, trader, market_id, stop_price): if self.stop_oid: # cancel the stop order and create a new one if trader.cancel_order(self.stop_oid): self.stop_ref_oid = None self.stop_oid = None else: return False if self.e == self.x: # all entry qty is filled return True if self.e < self.x: # something wrong but its ok return False if self.position_id: # if not accepted as modification do it as stop order if trader.modify_position(self.position_id, stop_loss_price=stop_price): self.sl = stop_price return True elif self.e > 0: # only if filled entry partially or totally order = Order(self, market_id) order.direction = -self.direction order.order_type = Order.ORDER_STOP order.reduce_only = True order.quantity = self.e - self.x # remaining order.stop_price = stop_price trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id self._stats['exit-maker'] = not order.is_market() if trader.create_order(order): self.stop_oid = order.order_id self.stop_order_qty = order.quantity self.last_sl_ot[0] = order.created_time self.last_sl_ot[1] += 1 self.sl = stop_price return True else: self.stop_ref_oid = None self.stop_order_qty = 0.0 return False
def modify_stop_loss(self, trader, instrument, stop_price): if self.stop_oid: # cancel the stop order and create a new one if trader.cancel_order(self.stop_oid): self.stop_ref_oid = None self.stop_oid = None else: return False if self.e == self.x: # all entry qty is filled return True if self.e < self.x: # something wrong but its ok return False if self.e > 0 and stop_price > 0.0: # only if filled entry partially or totally order = Order(self, instrument.market_id) order.direction = -self.direction order.order_type = Order.ORDER_STOP order.reduce_only = True order.quantity = self.e - self.x # remaining order.stop_price = stop_price order.leverage = self.leverage order.margin_trade = True trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id self._stats['stop-order-type'] = order.order_type if trader.create_order(order): self.stop_oid = order.order_id self.stop_order_qty = order.quantity self.last_sl_ot[0] = order.created_time self.last_sl_ot[1] += 1 self.sl = stop_price return True else: self.stop_ref_oid = None self.stop_order_qty = 0.0 return False
def open(self, trader, market_id, direction, order_type, order_price, quantity, take_profit, stop_loss, leverage=1.0, hedging=None): """ Buy an asset. """ if self._entry_state != StrategyTrade.STATE_NEW: return False order = Order(trader, market_id) order.direction = direction order.price = order_price order.order_type = order_type order.quantity = quantity order.leverage = leverage # if need to retry @todo or cancel # self._market_id = market_id # self._order_type = order_type # self._leverage = leverage # generated a reference order id trader.set_ref_order_id(order) self.entry_ref_oid = order.ref_order_id self.dir = order.direction self.op = order.price # retains the order price self.oq = order.quantity # ordered quantity self.tp = take_profit self.sl = stop_loss self._stats['entry-maker'] = not order.is_market() if trader.create_order(order): if not self.eot and order.created_time: # only at the first open self.eot = order.created_time return True else: self._entry_state = StrategyTrade.STATE_REJECTED return False
def modify_take_profit(self, trader, market_id, price): if self.limit_oid: # cancel the limit order and create a new one if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None self.limit_oid = None self.limit_order_qty = 0.0 else: return False if self.e == self.x: # all entry qty is filled return True if self.e < self.x: # something wrong but its ok return False if self.position_id: # if not accepted as modification do it as limit order if trader.modify_position(self.position_id, take_profit_price=price): self.tp = price return True elif self.e > 0: # only if filled entry partially or totally order = Order(self, market_id) order.direction = self.direction order.order_type = Order.ORDER_TAKE_PROFIT_LIMIT order.reduce_only = True order.quantity = self.e - self.x # remaining order.order_price = price trader.set_ref_order_id(order) self.limit_ref_oid = order.ref_order_id self._stats['exit-maker'] = not order.is_market() if trader.create_order(order): self.limit_oid = order.order_id self.limit_order_qty = order.quantity self.tp = price return True else: self.limit_ref_oid = None self.limit_order_qty = 0.0 return False
def close_position(self, position_id, market=True, limit_price=None): if not self._activity: return False position = self._positions.get(position_id) if position is None or not position.is_opened(): return False if not self.has_market(position.symbol): logger.error( "%s does not support market %s on close position %s !" % (self.name, position.symbol, position.position_id)) return False ref_order_id = "siis_" + base64.b64encode( uuid.uuid4().bytes).decode('utf8').rstrip('=\n') # keep for might be useless in this case order.set_ref_order_id(ref_order_id) order = Order(self, position.symbol) order.set_position_id(position.position_id) order.quantity = position.quantity order.direction = -position.direction # neg direction # @todo return True
def close(self, trader, market_id): """ Close the position and cancel the related orders. """ if self._closing: # already closing order return False if self.create_oid: # cancel the remaining buy order if trader.cancel_order(self.create_oid): self.create_ref_oid = None self.create_oid = None self._entry_state = StrategyTrade.STATE_CANCELED if self.stop_oid: # cancel the stop order if trader.cancel_order(self.stop_oid): self.stop_ref_oid = None self.stop_oid = None if self.limit_oid: # cancel the limit order if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None self.limit_oid = None if self.e - self.x > 0.0: order = Order(trader, market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_MARKET order.reduce_only = True order.quantity = self.e - self.x # remaining qty # generated a reference order id trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id self._stats['exit-maker'] = not order.is_market() if trader.create_order(order): self.stop_oid = order.order_id self.stop_order_qty = order.quantity # closing order defined self._closing = True return True else: self.stop_ref_oid = None return False return True
def close(self, trader, market_id): """ Close the position and cancel the related orders. """ if self.create_oid: # cancel the remaining buy order if trader.cancel_order(self.create_oid): self.create_ref_oid = None self.create_oid = None self._entry_state = StrategyTrade.STATE_CANCELED if self.stop_oid: # cancel the stop order if trader.cancel_order(self.stop_oid): self.stop_ref_oid = None self.stop_oid = None if self.limit_oid: # cancel the limit order if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None if self.e == self.x: # all entry qty is filled return True if self.e < self.x: # something wrong but its ok return False if self.position_id: # most of the margin broker case we have a position id if self._exit_state != StrategyTrade.STATE_PARTIALLY_FILLED: if trader.close_position(self.position_id): return True else: return False else: # bitmex case no have position id order = Order(trader, market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_MARKET order.quantity = self.e - self.x # remaining qty # generated a reference order id trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id self._stats['exit-maker'] = not order.is_market() if trader.create_order(order): return True else: self.stop_ref_oid = None return False return True
def modify_stop_loss(self, trader, instrument, stop_price): if self.stop_oid: # cancel the stop order and create a new one if trader.cancel_order(self.stop_oid, instrument): self.stop_ref_oid = None self.stop_oid = None else: return self.ERROR if self.e - self.x > 0.0: # only if filled entry partially or totally order = Order(self, instrument.market_id) order.direction = -self.direction order.order_type = Order.ORDER_STOP order.reduce_only = True order.quantity = self.e - self.x # remaining order.stop_price = stop_price order.margin_trade = True order.leverage = self.leverage trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id self._stats['stop-order-type'] = order.order_type if trader.create_order(order, instrument): self.stop_oid = order.order_id self.stop_order_qty = order.quantity self.last_stop_ot[0] = order.created_time self.last_stop_ot[1] += 1 self.sl = stop_price return self.ACCEPTED else: self.stop_ref_oid = None self.stop_order_qty = 0.0 return self.REJECTED return self.NOTHING_TO_DO
def open(self, trader, market_id, direction, order_type, order_price, quantity, take_profit, stop_loss, leverage=1.0, hedging=None): """ Open a position or buy an asset. """ order = Order(trader, market_id) order.direction = direction order.order_price = order_price order.order_type = order_type order.quantity = quantity order.leverage = leverage # generated a reference order id trader.set_ref_order_id(order) self.create_ref_oid = order.ref_order_id self.dir = order.direction self.op = order.order_price # retains the order price self.oq = order.quantity # ordered quantity self.tp = take_profit self.sl = stop_loss self._stats['entry-maker'] = not order.is_market() if trader.create_order(order): self.position_id = order.position_id # might be market-id if not self.eot and order.created_time: self.eot = order.created_time return True else: self.create_ref_oid = None return False
def modify_take_profit(self, trader, instrument, limit_price): if self.limit_oid: # cancel the limit order and create a new one if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None self.limit_oid = None self.limit_order_qty = 0.0 else: return False if self.e - self.x > 0.0: # only if filled entry partially or totally order = Order(self, instrument.market_id) order.direction = -self.direction order.order_type = Order.ORDER_LIMIT order.reduce_only = True order.quantity = self.e - self.x # remaining order.price = limit_price order.margin_trade = True order.leverage = self.leverage trader.set_ref_order_id(order) self.limit_ref_oid = order.ref_order_id self._stats['limit-order-type'] = order.order_type if trader.create_order(order): self.limit_oid = order.order_id self.limit_order_qty = order.quantity self.last_tp_ot[0] = order.created_time self.last_tp_ot[1] += 1 self.tp = limit_price return True else: self.limit_ref_oid = None self.limit_order_qty = 0.0 return False
def close(self, trader, market_id): if self.sell_ref_oid: logger.error("Trade %s has already ordered an exit !" % self.id) return False if self.buy_oid: # cancel the remaining buy order if trader.cancel_order(self.sell_oid): self.buy_ref_oid = None self.buy_oid = None self._entry_state = StrategyTrade.STATE_CANCELED if self.sell_oid: # cancel the sell order and create a new one if trader.cancel_order(self.sell_oid): self.sell_ref_oid = None self.sell_oid = None self.sell_order_type = Order.ORDER_MARKET self.sell_order_qty = 0.0 self._exit_state = StrategyTrade.STATE_CANCELED if self.e == self.x: # all entry qty is filled return True if self.e < self.x: # something wrong but its ok return False order = Order(trader, market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_MARKET order.quantity = self.e - self.x # remaining qty self._stats['exit-maker'] = not order.is_market() # generated a reference order id and keep it before ordering to retrieve its signals trader.set_ref_order_id(order) self.sell_ref_oid = order.ref_order_id if trader.create_order(order): self.sell_order_type = order.order_type self.sell_order_qty = order.quantity return True else: # rejected self.sell_ref_oid = None return False
def modify_take_profit(self, trader, market_id, price): if self.limit_oid: # cancel the limit order and create a new one if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None self.limit_oid = None self.limit_order_qty = 0.0 else: return False if self.e == self.x: # all entry qty is filled return True if self.e < self.x: # something wrong but its ok return False if self.e > 0: # only if filled entry partially or totally order = Order(self, market_id) order.direction = self.direction order.order_type = Order.ORDER_TAKE_PROFIT_LIMIT # order.reduce_only = True (not for now because it implies to have the filled qty, and so need to update each time trade qty is updated) order.quantity = self.e - self.x # remaining order.order_price = price trader.set_ref_order_id(order) self.limit_ref_oid = order.ref_order_id self._stats['exit-maker'] = not order.is_market() if trader.create_order(order): self.limit_oid = order.order_id self.limit_order_qty = order.quantity self.tp = price return True else: self.limit_ref_oid = None self.limit_order_qty = 0.0 return False
def modify_take_profit(self, trader, market_id, limit_price): if self.limit_oid: # cancel the limit order and create a new one if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None self.limit_oid = None self.limit_order_qty = 0.0 else: return False if self.e - self.x > 0.0: # only if filled entry partially or totally order = Order(self, market_id) order.direction = -self.direction order.order_type = Order.ORDER_LIMIT order.reduce_only = True # (not for now because it implies to have the filled qty, and so need to update each time trade qty is updated) order.quantity = self.e - self.x # remaining order.price = limit_price trader.set_ref_order_id(order) self.limit_ref_oid = order.ref_order_id self._stats['exit-maker'] = not order.is_market() if trader.create_order(order): self.limit_oid = order.order_id self.limit_order_qty = order.quantity self.last_tp_ot[0] = order.created_time self.last_tp_ot[1] += 1 self.tp = limit_price return True else: self.limit_ref_oid = None self.limit_order_qty = 0.0 return False
def open(self, trader, instrument, direction, order_type, order_price, quantity, take_profit, stop_loss, leverage=1.0, hedging=None, use_oco=False): """ Buy an asset. """ if self._entry_state != StrategyTrade.STATE_NEW: return False order = Order(trader, instrument.market_id) order.direction = direction order.price = order_price order.order_type = order_type order.quantity = quantity # generated a reference order id trader.set_ref_order_id(order) self.entry_ref_oid = order.ref_order_id self.dir = order.direction self.op = order.price # retains the order price self.oq = order.quantity # ordered quantity self.tp = take_profit self.sl = stop_loss self._use_oco = use_oco self._stats['entry-order-type'] = order.order_type if trader.create_order(order, instrument): if not self.eot and order.created_time: # only at the first open self.eot = order.created_time return True else: self._entry_state = StrategyTrade.STATE_REJECTED return False
def modify_stop_loss(self, trader, market_id, stop_price): if self.stop_oid: # cancel the stop order and create a new one if trader.cancel_order(self.stop_oid): self.stop_ref_oid = None self.stop_oid = None else: return False if self.e - self.x > 0.0: # only if filled entry partially or totally order = Order(self, market_id) order.direction = -self.direction order.order_type = Order.ORDER_STOP order.reduce_only = True order.quantity = self.e - self.x # remaining order.stop_price = stop_price trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id self._stats['exit-maker'] = not order.is_market() if trader.create_order(order): self.stop_oid = order.order_id self.stop_order_qty = order.quantity self.last_sl_ot[0] = order.created_time self.last_sl_ot[1] += 1 self.sl = stop_price return True else: self.stop_ref_oid = None self.stop_order_qty = 0.0 return False
def close_position(self, position_id, market_or_instrument, direction, quantity, market=True, limit_price=None): if not position_id or not market_or_instrument: return False ref_order_id = "siis_" + base64.b64encode(uuid.uuid4().bytes).decode('utf8').rstrip('=\n') # keep for might be useless in this case order.set_ref_order_id(ref_order_id) order = Order(self, market_or_instrument.market_id) order.set_position_id(position_id) order.quantity = quantity order.direction = -direction # neg direction # @todo return True
def modify_stop_loss(self, trader, market_id, price): self.sl = price if self.sell_oid: # cancel the sell order and create a new one if trader.cancel_order(self.sell_oid): # returns true, no need to wait signal confirmation self.sell_ref_oid = None self.sell_oid = None self.sell_order_type = Order.ORDER_MARKET self.sell_order_qty = 0.0 self._exit_state = StrategyTrade.STATE_DELETED if self.e == self.x: # all entry qty is filled return True if self.e < self.x: # something wrong but its ok return False if price: order = Order(trader, market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_STOP order.quantity = self.e - self.x # remaining self._stats['exit-maker'] = not order.is_market() # generated a reference order id trader.set_ref_order_id(order) self.sell_ref_oid = order.ref_order_id if trader.create_order(order): self.sell_order_type = order.order_type self.sell_order_qty = order.quantity return True else: return False return True
def close_position(self, position_or_id, market=True, limit_price=None): """ Close an existing position. Market is default, take care of the fee. Limit price can be defined but then it will create a limit order in the opposite direction in some broker and modify the position in some other (depends of the mode hedging...). """ if type(position_or_id) is str: position = self._positions.get(position_or_id) else: position = position_or_id if position is None or not position.is_opened: return False # market stop order order = Order(self, position.symbol) order.direction = position.close_direction() order.order_type = Order.ORDER_MARKET order.quantity = position.quantity # fully close order.leverage = position.leverage # same as open # simply create an order in the opposite direction return self.create_order(order)
def close(self, trader, instrument): if self._closing: # already closing order return self.NOTHING_TO_DO if self.oco_oid: # @todo cancel OCO order and create an order market return self.ERROR else: if self.stop_ref_oid: logger.error("Trade %s has already ordered an exit !" % self.id) return self.NOTHING_TO_DO if self.entry_oid: # cancel the remaining buy order if trader.cancel_order(self.entry_oid, instrument): self.entry_ref_oid = None self.entry_oid = None else: return self.ERROR if self.limit_oid: # cancel the sell limit order if trader.cancel_order(self.limit_oid, instrument): self.limit_ref_oid = None self.limit_oid = None self.limit_order_qty = 0.0 else: return self.ERROR if self.stop_oid: # cancel the sell stop order and create a new one if trader.cancel_order(self.stop_oid, instrument): self.stop_ref_oid = None self.stop_oid = None self.stop_order_qty = 0.0 else: return self.ERROR if self.x >= self.e: # all qty is filled return self.NOTHING_TO_DO order = Order(trader, instrument.market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_MARKET order.quantity = self.e - self.x # remaining qty self._stats['stop-order-type'] = order.order_type # generated a reference order id and keep it before ordering to retrieve its signals trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id if trader.create_order(order, instrument): # REST sync self.stop_oid = order.order_id self.stop_order_qty = order.quantity # closing order defined self._closing = True return self.ACCEPTED else: # rejected self.stop_ref_oid = None return self.REJECTED return self.NOTHING_TO_DO
def modify_stop_loss(self, trader, instrument, stop_price): if self._closing: # already closing order return self.NOTHING_TO_DO if self._exit_state == StrategyTrade.STATE_FILLED: # exit already fully filled return self.NOTHING_TO_DO if self.oco_oid: # @todo need recreate stop and limit OCO order return self.ERROR else: if self.stop_oid: # cancel the sell stop order and create a new one if trader.cancel_order(self.stop_oid, instrument): # REST sync # returns true, no need to wait signal confirmation self.stop_ref_oid = None self.stop_oid = None self.stop_order_qty = 0.0 else: return self.ERROR if self.limit_oid: # cancel the sell limit order (only one or the other) if trader.cancel_order(self.limit_oid, instrument): # REST sync # returns true, no need to wait signal confirmation self.limit_ref_oid = None self.limit_oid = None self.limit_order_qty = 0.0 else: return self.ERROR if self.x >= self.e: # all entry qty is filled return self.NOTHING_TO_DO if stop_price: order = Order(trader, instrument.market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_STOP order.stop_price = stop_price order.quantity = self.e - self.x # remaining self._stats['stop-order-type'] = order.order_type # generated a reference order id trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id if trader.create_order(order, instrument): # REST sync self.stop_oid = order.order_id self.stop_order_qty = order.quantity self.last_stop_ot[0] = order.created_time self.last_stop_ot[1] += 1 self.sl = stop_price return self.ACCEPTED else: # rejected self.stop_ref_oid = None self.stop_order_qty = 0.0 return self.REJECTED return self.NOTHING_TO_DO
def close(self, trader, market_id): if self._closing: # already closing order return False if self.oco_oid: # @todo cancel OCO order and create an order market return False else: # if self.stop_ref_oid: # logger.error("Trade %s has already ordered an exit !" % self.id) # return False if self.entry_oid: # cancel the remaining buy order if trader.cancel_order(self.entry_oid): self.entry_ref_oid = None self.entry_oid = None if self.limit_oid: # cancel the sell limit order if trader.cancel_order(self.limit_oid): self.limit_ref_oid = None self.limit_oid = None self.limit_order_type = Order.ORDER_MARKET self.limit_order_qty = 0.0 if self.stop_oid: # cancel the sell stop order and create a new one if trader.cancel_order(self.stop_oid): self.stop_ref_oid = None self.stop_oid = None self.stop_order_type = Order.ORDER_MARKET self.stop_order_qty = 0.0 if self.x >= self.e: # all qty is filled return True order = Order(trader, market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_MARKET order.quantity = self.e - self.x # remaining qty self._stats['exit-maker'] = not order.is_market() # generated a reference order id and keep it before ordering to retrieve its signals trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id if trader.create_order(order): self.stop_order_type = order.order_type self.stop_order_qty = order.quantity # closing order defined self._closing = True return True else: # rejected self.stop_ref_oid = None return False
def modify_stop_loss(self, trader, market_id, stop_price): if self._closing: # already closing order return False if self._exit_state == StrategyTrade.STATE_FILLED: # exit already fully filled return False if self.oco_oid: # @todo need recreate stop and limit OCO order return False else: if self.stop_oid: # cancel the sell stop order and create a new one if trader.cancel_order(self.stop_oid): # REST sync # returns true, no need to wait signal confirmation self.stop_ref_oid = None self.stop_oid = None self.stop_order_type = Order.ORDER_MARKET self.stop_order_qty = 0.0 if self.limit_oid: # cancel the sell limit order (only one or the other) if trader.cancel_order(self.limit_oid): # REST sync # returns true, no need to wait signal confirmation self.limit_ref_oid = None self.limit_oid = None self.limit_order_type = Order.ORDER_MARKET self.limit_order_qty = 0.0 if self.x >= self.e: # all entry qty is filled return True if stop_price: order = Order(trader, market_id) order.direction = -self.dir # neg dir order.order_type = Order.ORDER_STOP order.stop_price = stop_price order.quantity = self.e - self.x # remaining # @todo not correct, depend of what is executed self._stats['exit-maker'] = not order.is_market() # generated a reference order id trader.set_ref_order_id(order) self.stop_ref_oid = order.ref_order_id if trader.create_order(order): # REST sync self.stop_order_type = order.order_type self.stop_order_qty = order.quantity self.last_sl_ot[0] = order.created_time self.last_sl_ot[1] += 1 self.sl = stop_price return True else: # rejected self.stop_ref_oid = None return False return True
def close_position(trader, market, position, close_exec_price, order_type=Order.ORDER_LIMIT): """ Close a position. """ if not position: return False trader.lock() if not position.is_opened(): trader.unlock() return False # create an order for the close order = Order(trader, position.symbol) order.set_position_id(position.position_id) order.direction = position.close_direction() order.order_type = order_type if order_type == Order.ORDER_LIMIT: order.price = close_exec_price order.quantity = position.quantity order.leverage = position.leverage order.close_only = True order.reduce_only = True # increase or reduce the current position org_quantity = position.quantity exec_price = 0.0 # price difference depending of the direction delta_price = 0 if position.direction == Position.LONG: delta_price = close_exec_price - position.entry_price elif position.direction == Position.SHORT: delta_price = position.entry_price - close_exec_price # keep for percent calculation prev_entry_price = position.entry_price or close_exec_price leverage = order.leverage # most of thoose data rarely change except the base_exchange_rate value_per_pip = market.value_per_pip contract_size = market.contract_size lot_size = market.lot_size one_pip_means = market.one_pip_means base_exchange_rate = market.base_exchange_rate margin_factor = market.margin_factor realized_position_cost = 0.0 # realized cost of the position in base currency # effective meaning of delta price in base currency effective_price = (delta_price / one_pip_means) * value_per_pip # in base currency position_gain_loss = 0.0 # the position is closed, exact quantity in the opposite direction position_gain_loss = effective_price * position.quantity position.quantity = 0.0 position.exit_price = close_exec_price # directly executed quantity order.executed = order.quantity exec_price = close_exec_price realized_position_cost = market.effective_cost(order.quantity, close_exec_price) margin_cost = market.margin_cost(order.quantity, close_exec_price) # and decrease used margin trader.account.free_margin(margin_cost) # transaction time is current timestamp order.transact_time = trader.timestamp if position_gain_loss != 0.0 and realized_position_cost > 0.0: # ratio gain_loss_rate = position_gain_loss / realized_position_cost relative_gain_loss_rate = delta_price / prev_entry_price # if maker close (limit+post-order) (for now same as market) position.profit_loss = position_gain_loss position.profit_loss_rate = gain_loss_rate # if taker close (market) position.profit_loss_market = position_gain_loss position.profit_loss_market_rate = gain_loss_rate trader.account.add_realized_profit_loss(position_gain_loss / base_exchange_rate) # display only for debug if position_gain_loss > 0.0: Terminal.inst().high( "Close profitable position with %.2f on %s (%.2fpips) (%.2f%%) at %s" % (position_gain_loss, order.symbol, delta_price / one_pip_means, gain_loss_rate * 100.0, market.format_price(close_exec_price)), view='debug') elif position_gain_loss < 0.0: Terminal.inst().low( "Close loosing position with %.2f on %s (%.2fpips) (%.2f%%) at %s" % (position_gain_loss, order.symbol, delta_price / one_pip_means, gain_loss_rate * 100.0, market.format_price(close_exec_price)), view='debug') else: gain_loss_rate = 0.0 # unlock before notify signals trader.unlock() # # order signal (SIGNAL_ORDER_OPENED+DELETED because we assume fully completed) # order_data = { 'id': order.order_id, 'symbol': order.symbol, 'type': order.order_type, 'direction': order.direction, 'timestamp': order.created_time, 'quantity': order.quantity, 'price': order.price, 'stop-price': order.stop_price, 'stop-loss': order.stop_loss, 'take-profit': order.take_profit, 'time-in-force': order.time_in_force } # signal as watcher service (opened + fully traded qty) trader.service.watcher_service.notify( Signal.SIGNAL_ORDER_OPENED, trader.name, (order.symbol, order_data, order.ref_order_id)) order_data = { 'id': order.order_id, 'symbol': order.symbol, 'type': order.order_type, 'trade-id': 0, 'direction': order.direction, 'timestamp': order.transact_time, 'quantity': order.quantity, 'price': order.price, 'stop-price': order.stop_price, 'exec-price': exec_price, 'avg-price': position.entry_price, 'filled': order.executed, 'cumulative-filled': order.executed, 'quote-transacted': realized_position_cost, # its margin 'stop-loss': order.stop_loss, 'take-profit': order.take_profit, 'time-in-force': order.time_in_force, 'commission-amount': 0, 'commission-asset': trader.account.currency } trader.service.watcher_service.notify( Signal.SIGNAL_ORDER_TRADED, trader.name, (order.symbol, order_data, order.ref_order_id)) # # position signal # # closed position position_data = { 'id': position.position_id, 'symbol': position.symbol, 'direction': position.direction, 'timestamp': order.transact_time, 'quantity': 0, 'avg-entry-price': position.entry_price, 'avg-exit-price': position.exit_price, 'exec-price': exec_price, 'stop-loss': None, 'take-profit': None, 'profit-loss': position.profit_loss, 'profit-loss-currency': market.quote } trader.service.watcher_service.notify( Signal.SIGNAL_POSITION_DELETED, trader.name, (order.symbol, position_data, order.ref_order_id)) # and then deleted order trader.service.watcher_service.notify(Signal.SIGNAL_ORDER_DELETED, trader.name, (order.symbol, order.order_id, "")) position.exit(exec_price) return True
def __update_orders(self): if not self.connected: return # filters only siis managed orders src_orders = self._watcher.connector.ws.open_orders("") # "siis_") # first delete older orders order_rm_list = [] for k, order in self._orders.items(): found = False for src_order in src_orders: src_order_id = src_order['clOrdID'] or src_order['orderID'] if order.order_id == src_order[ 'clOrdID'] or order.order_id == src_order['orderID']: found = True break if not found: order_rm_list.append(order.order_id) for order_id in order_rm_list: del self._orders[order_id] # insert or update active orders for src_order in src_orders: found = False src_order_id = src_order['clOrdID'] or src_order['orderID'] order = self._orders.get(src_order_id) if order is None: # insert order = Order(self, src_order['symbol']) order.set_order_id(src_order_id) self._orders[order.order_id] = order else: order = self._orders.get(src_order_id) # logger.info(src_order) # probably modifier or when leavesQty is update the ordStatus must change # if src_order['ordStatus'] != "New": # continue # update order.direction = Position.LONG if src_order[ 'side'] == 'Buy' else Position.SHORT # 'orderQty' (ordered qty), 'cumQty' (cumulative done), 'leavesQty' (remaning) order.quantity = src_order.get('leavesQty', src_order.get('orderQty', 0)) if src_order.get('transactTime'): order.transact_time = self._parse_datetime( src_order.get('transactTime')).timestamp() if src_order['ordType'] == "Market": order.order_type = Order.ORDER_MARKET elif src_order['ordType'] == "Limit": order.order_type = Order.ORDER_LIMIT order.price = src_order.get('price') elif src_order['ordType'] == "Stop": order.order_type = Order.ORDER_STOP order.stop_price = src_order.get('stopPx') elif src_order['ordType'] == "StopLimit": order.order_type = Order.ORDER_STOP_LIMIT order.price = src_order.get('price') order.stop_price = src_order.get('stopPx') elif src_order['ordType'] == "MarketIfTouched": order.order_type = Order.ORDER_TAKE_PROFIT order.stop_price = src_order.get('stopPx') elif src_order['ordType'] == "LimitIfTouched": order.order_type = Order.ORDER_TAKE_PROFIT_LIMIT order.price = src_order.get('price') order.stop_price = src_order.get('stopPx') if src_order['timeInForce'] == 'GoodTillCancel': order.time_in_force = Order.TIME_IN_FORCE_GTC elif src_order['timeInForce'] == 'ImmediateOrCancel': order.time_in_force = Order.TIME_IN_FORCE_IOC elif src_order['timeInForce'] == 'FillOrKill': order.time_in_force = Order.TIME_IN_FORCE_FOK else: order.time_in_force = Order.TIME_IN_FORCE_GTC # triggered, ordRejReason, currency # @todo # execution options exec_inst = src_order['execInst'].split(',') # taker or maker fee if 'ParticipateDoNotInitiate' in exec_inst: order.post_only = True else: order.post_only = False # close reduce only if 'Close' in exec_inst: # close only order (must be used with reduce only, only reduce a position, and close opposites orders) order.close_only = True else: order.close_only = False # close reduce only if 'ReduceOnly' in exec_inst: # reduce only order (only reduce a position) order.reduce_only = True else: order.redeuce_only = False # execution price if 'LastPrice' in exec_inst: order.price_type = Order.PRICE_LAST elif 'IndexPrice' in exec_inst: order.price_type = Order.PRICE_MARK elif 'MarkPrice' in exec_inst: order.price_type = Order.PRICE_INDEX