def _on_executed_order(self, order: Order): qty = order.qty price = order.price # TODO: detect reduce_only order, and if so, see if you need to adjust qty and price (above variables) self.exchange.charge_fee(qty * price) # order opens position if self.qty == 0: change_balance = order.type == order_types.MARKET self._open(qty, price, change_balance) # order closes position elif (sum_floats(self.qty, qty)) == 0: self._close(price) # order increases the size of the position elif self.qty * qty > 0: self._increase(qty, price) # order reduces the size of the position elif self.qty * qty < 0: # if size of the order is big enough to both close the # position AND open it on the opposite side if abs(qty) > abs(self.qty): logger.info( 'Executed order is big enough to not close, but flip the position type. Order QTY: {}, Position QTY: {}' .format(qty, self.qty)) diff_qty = sum_floats(self.qty, qty) self._close(price) self._open(diff_qty, price) else: self._reduce(qty, price) if self.strategy: self.strategy._on_updated_position(order)
def _increase(self, qty: float, price: float) -> None: if not self.is_open: raise OpenPositionError( 'position must be already open in order to increase its size') qty = abs(qty) size = qty * price # if self.exchange: # self.exchange.decrease_futures_balance(size) self.entry_price = jh.estimate_average_price(qty, price, self.qty, self.entry_price) if self.type == trade_types.LONG: self.qty = sum_floats(self.qty, qty) elif self.type == trade_types.SHORT: self.qty = subtract_floats(self.qty, qty) info_text = 'INCREASED position: {}, {}, {}, {}, ${}'.format( self.exchange_name, self.symbol, self.type, self.qty, round(self.entry_price, 2)) if jh.is_debuggable('position_increased'): logger.info(info_text) if jh.is_live( ) and config['env']['notifications']['events']['updated_position']: notifier.notify(info_text)
def _reduce(self, qty: float, price: float) -> None: if self.is_open is False: raise EmptyPosition('The position is closed.') # just to prevent confusion qty = abs(qty) estimated_profit = jh.estimate_PNL(qty, self.entry_price, price, self.type) if self.exchange: # self.exchange.increase_futures_balance(qty * self.entry_price + estimated_profit) self.exchange.add_realized_pnl(estimated_profit) self.exchange.temp_reduced_amount[jh.base_asset( self.symbol)] += abs(qty * price) if self.type == trade_types.LONG: self.qty = subtract_floats(self.qty, qty) elif self.type == trade_types.SHORT: self.qty = sum_floats(self.qty, qty) info_text = 'REDUCED position: {}, {}, {}, {}, ${}'.format( self.exchange_name, self.symbol, self.type, self.qty, round(self.entry_price, 2)) if jh.is_debuggable('position_reduced'): logger.info(info_text) if jh.is_live( ) and config['env']['notifications']['events']['updated_position']: notifier.notify(info_text)
def test_sum_floats(): assert utils.sum_floats(9.71, 9.813) == 19.523 assert utils.sum_floats(-1.123, -1.2) == -2.323 assert utils.sum_floats(1.19, -1.2) == -0.01 assert utils.sum_floats(-1.19, 1.2) == 0.01