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 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 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 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, 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 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, 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): """ 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_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 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_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_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 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 trader_market = self._markets.get(market_or_instrument.market_id) if not trader_market: error_logger.error( "Trader %s refuse to close position because the market %s is not found" % (self.name, market_or_instrument.market_id)) return False result = False with self._mutex: # retrieve the position position = self._positions.get(position_id) if position and position.is_opened(): # market stop order order = Order(self, position.symbol) order.set_position_id(position_id) order.direction = position.close_direction() if limit_price: order.order_type = Order.ORDER_LIMIT order.price = limit_price else: order.order_type = Order.ORDER_MARKET order.quantity = position.quantity # fully close order.leverage = position.leverage # same as open order.close_only = True order.reduce_only = True # # price according to order type # bid_price = 0 ofr_price = 0 if order.order_type == Order.ORDER_LIMIT: bid_price = order.price ofr_price = order.price elif order.order_type == Order.ORDER_MARKET: bid_price = trader_market.bid ofr_price = trader_market.ofr # open long are executed on bid and short on ofr, close the inverse if order.direction == Position.LONG: open_exec_price = ofr_price # bid_price close_exec_price = bid_price # ofr_price elif order.direction == Position.SHORT: open_exec_price = bid_price # ofr_price close_exec_price = ofr_price # bid_price else: logger.error("Unsupported direction") return False if not open_exec_price or not close_exec_price: logger.error("No order execution price") return False if self._slippage > 0.0: # @todo deferred to update return False else: # immediate execution of the order if trader_market.has_position: # close isolated position result = close_position(self, trader_market, position, close_exec_price, Order.ORDER_MARKET) else: # close position (could be using FIFO method) result = exec_margin_order(self, order, trader_market, open_exec_price, close_exec_price) else: result = False return result
def __update_reversal(self, instrument): # consts MIN_SCORE = 4 * 60 # min score to reach to validate an order BSD_SCORE_FACTOR = 2 # 2,3 CBO_SCORE_FACTOR = 2 # 2,3 RSI_SCORE_FACTOR = 0.5 # 0.5,1,2 RSI_TREND_SCORE_FACTOR = 1 # 0.5,1,2,4 EMA_VWMA_CROSS_SCORE_FACTOR = 8000 # 5000,8000 VWMA_PRICE_CROSS_SCORE_FACTOR = 2000 # 2000,4000 EMA_VWM_BONUS_SCORE = 2 # 1,2,3,5 TIME_SCORE_REGRESSION_FACTOR = 0.75 # 0.375,0.5,0.75 RSI_LOW = 30 # 25,30,35 RSI_HIGH = 70 # 65,70,75 # @todo a plot of the account balance and % gain/loss of each trade # process in 1 minute, retrieve analysis data instrument strategy_trader = self._strategy_traders.get(instrument) # compute with the max samples num_samples = instrument.num_samples(Instrument.TF_MIN) depth = min(self.depth, num_samples) last_prices = instrument.last_prices(Instrument.TF_MIN, Instrument.PRICE_CLOSE, depth) last_volumes = instrument.last_volumes(Instrument.TF_MIN, depth) # current timestamp timestamp = self.timestamp # instrument.last_candles(Instrument.TF_MIN, depth) # @todo Typical price is attained by taking adding the high, low and close, and dividing by three: (H+L+C)/3 if depth < self.min_depth: # not enought samples return rsi = strategy_trader.rsi.compute(last_prices) sma = strategy_trader.sma.compute(last_prices) ema = strategy_trader.ema.compute(last_prices) vwma = strategy_trader.vwma.compute(last_prices, last_volumes) # # scorify # bsd_score = 0 cbo_score = 0 rsi_score = 0 ema_vwma_score = 0 ema_vwma_bonus_score = 0 price_vwma_score = 0 if strategy_trader.blueskyday: if strategy_trader.blueskyday[-1].direction == Position.LONG: bsd_score = BSD_SCORE_FACTOR elif strategy_trader.blueskyday[-1].direction == Position.SHORT: bsd_score = -BSD_SCORE_FACTOR if strategy_trader.channelbreakout: if strategy_trader.channelbreakout[-1].direction == Position.LONG: cbo_score = CBO_SCORE_FACTOR elif strategy_trader.channelbreakout[ -1].direction == Position.SHORT: cbo_score = -CBO_SCORE_FACTOR # rsi 30/70, gives strong signals # @todo be we could compute it on two tf (the last 14N and the more global at depth level to have two trends) rsi_argmin = np.argmin(rsi) rsi_argmax = np.argmax(rsi) # trend of the rsi or MM if rsi_argmin < rsi_argmax and rsi[rsi_argmin] < rsi[rsi_argmax]: # ++ rsi_trend = (rsi[rsi_argmax] + rsi[rsi_argmin]) / (rsi[rsi_argmax] - rsi[rsi_argmin]) elif rsi_argmax < rsi_argmin and rsi[rsi_argmax] > rsi[ rsi_argmin]: ## -- rsi_trend = (rsi[rsi_argmin] + rsi[rsi_argmax]) / (rsi[rsi_argmin] - rsi[rsi_argmax]) else: rsi_trend = 0 if rsi[-1] < RSI_LOW: rsi_score = (RSI_LOW - rsi[-1]) * RSI_SCORE_FACTOR # ++ if rsi_trend > 0: rsi_score += rsi_trend * RSI_TREND_SCORE_FACTOR elif rsi[-1] > RSI_HIGH: rsi_score = (RSI_HIGH - rsi[-1]) * RSI_SCORE_FACTOR if rsi_trend < 0: rsi_score += rsi_trend * RSI_TREND_SCORE_FACTOR # prev = rsi[0] # for (i, v) in enumerate(rsi): # if v < prev and v < RSI_LOW: # longs.append((i, last_prices[i])) # prev = v # elif v > prev and v > RSI_HIGH: # shorts.append((i, last_prices[i])) # prev = v # ema/vwma crossing ema_vwma_score = ( ema[-1] - vwma[-1]) / last_prices[-1] * EMA_VWMA_CROSS_SCORE_FACTOR # vwma/price crossing price_vwma_score = (last_prices[-1] - vwma[-1] ) / last_prices[-1] * VWMA_PRICE_CROSS_SCORE_FACTOR # if last_prices[-1] > vwma[-1]: # strategy_trader.scores[-1] += 1 # elif last_prices[-1] < vwma[-1]: # strategy_trader.scores[-1] -= 1 # ema/vwma crossing and vwmap/price more score !! if ema[-1] > vwma[-1] and last_prices[-1] > vwma[-1]: ema_vwma_bonus_score = EMA_VWM_BONUS_SCORE elif ema[-1] < vwma[-1] and last_prices[-1] < vwma[-1]: ema_vwma_bonus_score = -EMA_VWM_BONUS_SCORE # support/resistance signal # @todo and then scores +-= 2 # price delta min including spread, have to determine if the price can vary of a minimal size # @todo # confirmation on N candles, and don't take care of pyramided orders total_score = rsi_score + ema_vwma_score + price_vwma_score + ema_vwma_bonus_score + bsd_score + cbo_score # # score tuning # # store the total score strategy_trader.scores[-1] = total_score final_score = total_score # average of the two last score and increase the last, score is exp if signals are in the trend if len(strategy_trader.scores) > 2: final_score = np.average(strategy_trader.scores[-2:]) final_score += strategy_trader.scores[-2] # and store it strategy_trader.scores[-1] = final_score # handle a score convergence to avoid multiple signals if (strategy_trader.cur_score > 0 and final_score > 0) or (strategy_trader.cur_score < 0 and final_score < 0): # cancel all # strategy_trader.scores = [0] # or ignore # strategy_trader.scores[-1] = 0 # or take 75% of the previous score to minimize its impact progressively # strategy_trader.scores[-1] = strategy_trader.scores[-2] * TIME_SCORE_REGRESSION_FACTOR # or keep only 37.5% of it strategy_trader.scores[-1] *= TIME_SCORE_REGRESSION_FACTOR * 0.5 # keep as final score or nullify final_score = strategy_trader.scores[-1] # handle a score divergence # if (rsi_score > 0 and ema_vwma_score < 0) or (rsi_score < 0 and ema_vwma_bonus_score > 0): # total_score *= 0.25 # limit strategy_trader.scores len to max depth if len(strategy_trader.scores) > self.depth: strategy_trader.scores = strategy_trader.scores[ len(strategy_trader.scores) - self.depth:] # # pass an order if score is accepted # if abs(final_score) >= MIN_SCORE: # keep apart the current score strategy_trader.cur_score = final_score if final_score > 0: strategy_trader.longs.append((timestamp, last_prices[-1])) elif final_score < 0: strategy_trader.shorts.append((timestamp, last_prices[-1])) date_str = datetime.fromtimestamp(timestamp).strftime( '%Y-%m-%d %H:%M:%S') direction = Position.LONG if final_score > 0 else Position.SHORT # create an order an post it if final_score > 0: Terminal.inst().notice( "> Strategy %s LONG %s%s at price %.4f on %s" % (self.name, instrument.trade_quantity, instrument.market_id, last_prices[-1], date_str)) else: Terminal.inst().notice( "> Strategy %s SHORT %s%s at price %.4f on %s" % (self.name, instrument.trade_quantity, instrument.market_id, last_prices[-1], date_str)) trader = self.trader() if trader: order = Order(trader, instrument.market_id) order.direction = direction order.price = last_prices[-1] # depends of the instrument and the account, and not always necessary, but always in paper trader order.leverage = instrument.leverage positions = trader.positions(instrument.market_id) current_opposite_qty = 0.0 current_same_qty = 0.0 for position in positions: # strategy does a reversal (and quantity are always positives) if position.direction != direction: # opposit directions ? current_opposite_qty += position.quantity # need to close that else: # or same direction ? current_same_qty += position.quantity # trading quantity + what we have in opposite direction - what we already have in the same direction if self._pyramided >= 1: order.quantity = instrument.trade_quantity + current_opposite_qty - current_same_qty # @todo else: order.quantity = instrument.trade_quantity + current_opposite_qty - current_same_qty if order.quantity > 0: # @todo debug only Terminal.inst().info( "Do order %s %s with %s" % (instrument.market_id, 'SHORT' if direction == Position.SHORT else 'LONG', order.quantity)) trader.create_order(order) # consumes buy sell signals # @todo could put previous scores into history # strategy_trader.scores = [0] strategy_trader.blueskyday = [] strategy_trader.channelbreakout = [] else: # append the next score entry at 0 strategy_trader.scores.append(0) # # charting # if strategy_trader.chart is None and Charting.inst(): # create the chart if necessary strategy_trader.chart = Charting.inst().chart( "%s on %s" % (self.name, instrument.symbol)) rechart = strategy_trader.chart.can_redraw if rechart: longs = [] shorts = [] # take only in depth longs and shorts for long in strategy_trader.longs: if long[0] + depth * Instrument.TF_MIN >= timestamp: longs.append( ((long[0] + depth * Instrument.TF_MIN - timestamp) / Instrument.TF_MIN, long[1])) for short in strategy_trader.shorts: if short[0] + depth * Instrument.TF_MIN >= timestamp: shorts.append( ((short[0] + depth * Instrument.TF_MIN - timestamp) / Instrument.TF_MIN, short[1])) # @todo send a stream with the last values or/and updated ranges/objects strategy_trader.chart.set_range(0, depth) strategy_trader.chart.plot_price_serie(0, last_prices) strategy_trader.chart.plot_price_serie(1, sma) strategy_trader.chart.plot_price_serie(2, ema) strategy_trader.chart.plot_price_serie(3, vwma) strategy_trader.chart.annotate_price(0, longs, 'g^') strategy_trader.chart.annotate_price(1, shorts, 'r^') strategy_trader.chart.plot_serie(1, 0, rsi) strategy_trader.chart.plot_serie(1, 1, [30] * len(rsi)) strategy_trader.chart.plot_serie(1, 2, [70] * len(rsi)) # strategy_trader.chart.plot_serie(2, 0, mmt) strategy_trader.chart.draw()
def close_position(self, position_id, market=True, limit_price=None): if not self._activity: return False result = False self.lock() position = self._positions.get(position_id) if position and position.is_opened(): # market stop order order = Order(self, position.symbol) order.set_position_id(position_id) order.direction = position.close_direction() if market and limit_price: order.order_type = Order.ORDER_LIMIT order.price = limit_price else: order.order_type = Order.ORDER_MARKET order.quantity = position.quantity # fully close order.leverage = position.leverage # same as open order.close_only = True order.reduce_only = True self.unlock() # # price according to order type # market = self.market(order.symbol) bid_price = 0 ofr_price = 0 if order.order_type == Order.ORDER_LIMIT: bid_price = order.price ofr_price = order.price elif order.order_type == Order.ORDER_MARKET: bid_price = market.bid ofr_price = market.ofr # open long are executed on bid and short on ofr, close the inverse if order.direction == Position.LONG: open_exec_price = ofr_price # bid_price close_exec_price = bid_price # ofr_price elif order.direction == Position.SHORT: open_exec_price = bid_price # ofr_price close_exec_price = ofr_price # bid_price else: logger.error("Unsupported direction") return False if not open_exec_price or not close_exec_price: logger.error("No order execution price") return False if self._slippage > 0.0: # @todo return False else: # immediate execution of the order result = exec_margin_order(self, order, market, open_exec_price, close_exec_price) else: self.unlock() result = False return result