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.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, 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 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: # 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 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, 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 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 > 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): 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._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 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 __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
def __fetch_orders(self, signals=False): """ This is the synchronous REST fetching, but prefer the WS asynchronous and live one. Mainly used for initial fetching. """ try: open_orders = self._watcher.connector.open_orders() except Exception as e: logger.error("__fetch_orders: %s" % repr(e)) raise orders = {} for data in open_orders: market = self.market(data['symbol']) if data['status'] == 'NEW': # might be... order = Order(self, data['symbol']) order.set_order_id(data['orderId']) order.quantity = data['origQty'] order.executed = data['executedQty'] order.direction = Order.LONG if data['side'] == 'BUY' else Order.SHORT if data['type'] == 'LIMIT': order.order_type = Order.ORDER_LIMIT order.price = data['price'] elif data['type'] == 'LIMIT_MAKER': order.order_type = Order.ORDER_LIMIT # _MAKER order.price = data['price'] elif data['type'] == 'MARKET': order.order_type = Order.ORDER_MARKET elif data['type'] == 'STOP_LOSS': order.order_type = Order.ORDER_STOP order.stop_price = data['stopPrice'] elif data['type'] == 'STOP_LOSS_LIMIT': order.order_type = Order.ORDER_STOP_LIMIT order.price = data['price'] order.stop_price = data['stopPrice'] elif data['type'] == 'TAKE_PROFIT': order.order_type = Order.ORDER_TAKE_PROFIT order.stop_price = data['stopPrice'] elif data['type'] == 'TAKE_PROFIT_LIMIT': order.order_type = Order.ORDER_TAKE_PROFIT_LIMIT order.price = data['price'] order.stop_price = data['stopPrice'] order.created_time = data['time'] order.transact_time = data['updateTime'] if data['timeInForce'] == 'GTC': order.time_in_force = Order.TIME_IN_FORCE_GTC elif data['timeInForce'] == 'IOC': order.time_in_force = Order.TIME_IN_FORCE_IOC elif data['timeInForce'] == 'FOK': order.time_in_force = Order.TIME_IN_FORCE_FOK else: order.time_in_force = Order.TIME_IN_FORCE_GTC # "icebergQty": "0.0" # @todo a day when I'll be rich orders[order.order_id] = order if signals: # deleted (for signals if no WS) deleted_list = self._orders.keys() - orders.keys() # @todo # created (for signals if no WS) created_list = orders.keys() - self._orders.keys() # @todo self._orders = orders
def on_order_traded(self, market_id, data, ref_order_id): """ Order update, trade order in that case, is always successed by an asset update signal. Binance order modification is not possible, need cancel and recreate. @note Consume 1 API credit to get the asset quote price at the time of the trade. """ market = self._markets.get(data['symbol']) if market is None: # not interested by this market return base_asset = self.__get_or_add_asset(market.base) quote_asset = self.__get_or_add_asset(market.quote) quote_market = None order = self._orders.get(data['id']) if order is None: # not found (might not occurs) order = Order(self, data['symbol']) order.set_order_id(data['id']) # its might be the creation timestamp but it will be the trade execution order.created_time = data['timestamp'] order.direction = data['direction'] order.order_type = data['type'] order.time_in_force = data['time-in-force'] order.quantity = data['quantity'] order.price = data.get('price') order.stop_price = data.get('stop-price') self._orders[data['id']] = order order.executed += data['filled'] if data['trade-id']: # same asset used for commission buy_or_sell = data['direction'] == Order.LONG # base details in the trade order base_trade_qty = data['filled'] base_exec_price = data['exec-price'] # price of the quote asset expressed in prefered quote at time of the trade (need a REST call) quote_trade_qty = data['quote-transacted'] # or base_trade_qty * base_exec_price quote_exec_price = 1.0 if quote_asset.quote and quote_asset.symbol != quote_asset.quote: # quote price to be fetched if self._watcher.has_instrument(quote_asset.symbol+quote_asset.quote): # direct, and get the related market quote_market = self._markets.get(quote_asset.symbol+quote_asset.quote) quote_exec_price = self.history_price(quote_asset.symbol+quote_asset.quote, data['timestamp']) elif self._watcher.has_instrument(quote_asset.quote+quote_asset.symbol): # indirect, but cannot have the market quote_exec_price = 1.0 / self.history_price(quote_asset.quote+quote_asset.symbol, data['timestamp']) # base asset self.__update_asset(order.order_type, base_asset, market, data['trade-id'], base_exec_price, base_trade_qty, buy_or_sell, data['timestamp']) # quote asset self.__update_asset(order.order_type, quote_asset, quote_market, None, quote_exec_price, quote_trade_qty, not buy_or_sell, data['timestamp']) # commission asset if data['commission-asset'] == base_asset.symbol: self.__update_asset(Order.ORDER_MARKET, base_asset, market, None, base_exec_price, data['commission-amount'], False, data['timestamp']) else: commission_asset = self.__get_or_add_asset(data['commission-asset']) commission_asset_market = None quote_exec_price = 1.0 if commission_asset.quote and commission_asset.symbol != commission_asset.quote: # commission asset price to be fetched if self._watcher.has_instrument(commission_asset.symbol+commission_asset.quote): # direct, and get the related market commission_asset_market = self.market(commission_asset.symbol+commission_asset.quote) quote_exec_price = commission_asset_market.price elif self._watcher.has_instrument(commission_asset.quote+commission_asset.symbol): # indirect, but cannot have the market quote_exec_price = 1.0 / self.history_price(commission_asset.quote+commission_asset.symbol, data['timestamp']) self.__update_asset(Order.ORDER_MARKET, commission_asset, commission_asset_market, None, quote_exec_price, data['commission-amount'], False, data['timestamp'])