def _add_market_order(self, order: MarketOrder) -> bool: """ Add a MARKET order. :param order: (Order) New order to be used for updating existing order or placing a new order """ if self.full_inventory: LOGGER.debug(' %s inventory max' % order.side) return False # Create a hypothetical average execution price incorporating a fixed slippage order.average_execution_price = order.price order.executed = order.DEFAULT_SIZE # Update position inventory attributes self.cancel_limit_order() # remove any unfilled limit orders self.positions.append(order) # execute and save the market order self.total_exposure += order.average_execution_price self.average_price = self.total_exposure / self.position_count self.full_inventory = self.position_count >= self.max_position_count self.total_trade_count += 1 # deduct transaction fees whenever an order gets filled if self.transaction_fee: self.realized_pnl -= MARKET_ORDER_FEE # update statistics self.statistics.market_orders += 1 LOGGER.debug(' %s @ %.2f | step %i' % (order.side, order.average_execution_price, order.step)) return True
def test_case_three(self): print('\nTest_Case_Three') test_position = Broker(5) midpoint = 100. for i in range(10): order_open = MarketOrder(ccy='BTC-USD', side='long', price=midpoint - i, step=i) test_position.add(order=order_open) self.assertEqual(5, test_position.long_inventory.position_count) self.assertEqual(0, test_position.short_inventory.position_count) print('Confirm we have 5 positions: %i' % test_position.long_inventory.position_count) for i in range(10): order_open = MarketOrder(ccy='BTC-USD', side='long', price=midpoint + i, step=i) test_position.remove(order=order_open) self.assertEqual(0, test_position.long_inventory.position_count) self.assertEqual(0, test_position.short_inventory.position_count)
def test_case_two(self): print('\nTest_Case_Two') test_position = Broker() midpoint = 100. fee = .003 order_open = MarketOrder(ccy='BTC-USD', side='short', price=midpoint, step=1) test_position.add(order=order_open) self.assertEqual(1, test_position.short_inventory.position_count) self.assertEqual(0, test_position.long_inventory.position_count) self.assertEqual( 0., test_position.long_inventory.get_unrealized_pnl(price=midpoint)) print('SHORT Unrealized_pnl: %f' % test_position.short_inventory.get_unrealized_pnl(price=midpoint)) order_close = MarketOrder(ccy='BTC-USD', side='short', price=midpoint - (midpoint * fee * 15), step=100) test_position.remove(order=order_close) self.assertEqual(0, test_position.short_inventory.position_count) self.assertEqual(0, test_position.long_inventory.position_count) self.assertEqual( 0., test_position.long_inventory.get_unrealized_pnl(price=midpoint)) print('SHORT Unrealized_pnl: %f' % test_position.short_inventory.get_unrealized_pnl(price=midpoint)) print('SHORT Realized_pnl: %f' % test_position.realized_pnl)
def test_case_one(self): print('\nTest_Case_One') test_position = Broker() midpoint = 100. fee = .003 order_open = MarketOrder(ccy='BTC-USD', side='long', price=midpoint, step=1) test_position.add(order=order_open) self.assertEqual(1, test_position.long_inventory.position_count) print('LONG Unrealized_pnl: %f' % test_position.long_inventory.get_unrealized_pnl( midpoint=midpoint)) self.assertEqual(0, test_position.short_inventory.position_count) self.assertEqual(0., test_position.short_inventory.get_unrealized_pnl( midpoint=midpoint)) order_close = MarketOrder(ccy='BTC-USD', side='long', price=midpoint + (midpoint * fee * 5), step=100) test_position.remove(order=order_close) self.assertEqual(0, test_position.long_inventory.position_count) print('LONG Unrealized_pnl: %f' % test_position.long_inventory.get_unrealized_pnl( midpoint=midpoint)) self.assertEqual(test_position.short_inventory.position_count, 0) self.assertEqual( test_position.short_inventory.get_unrealized_pnl(midpoint=midpoint), 0.) print('LONG Realized_pnl: %f' % test_position.realized_pnl)
def flatten_inventory(self, price: float) -> float: """ Flatten all positions held in inventory. :param price: (float) current bid or ask price :return: (float) PnL from flattening inventory """ LOGGER.debug('{} is flattening inventory of {}'.format( self.side, self.position_count)) if self.position_count < 1: return -ENCOURAGEMENT pnl = 0. # Need to reverse the side to reflect the correct direction of # the flatten_order() side = 'long' if self.side == 'short' else 'short' while self.position_count > 0: order = MarketOrder(ccy=None, side=side, price=price) pnl += self.remove(netting_order=order) self.total_trade_count += 1 # Deduct transaction fee based on order type if self.transaction_fee: pnl -= MARKET_ORDER_FEE # Update statistics self.statistics.market_orders += 1 return pnl
def map_action_to_broker(self, action: int) -> Tuple[float, float]: """ Create or adjust orders per a specified action and adjust for penalties. :param action: (int) current step's action :return: (float) reward """ action_penalty_reward = pnl = 0.0 if action == 0: # do nothing action_penalty_reward += ENCOURAGEMENT elif action == 1: # buy # Deduct transaction costs if self.broker.transaction_fee: pnl -= MARKET_ORDER_FEE if self.broker.short_inventory_count > 0: # Net out existing position order = MarketOrder(ccy=self.symbol, side='short', price=self.best_ask, step=self.local_step_number) pnl += self.broker.remove(order=order) elif self.broker.long_inventory_count >= 0: order = MarketOrder(ccy=self.symbol, side='long', price=self.best_ask, step=self.local_step_number) if self.broker.add(order=order) is False: action_penalty_reward -= ENCOURAGEMENT else: raise ValueError( ('gym_trading.get_reward() Error for action #{} - ' 'unable to place an order with broker').format(action)) elif action == 2: # sell # Deduct transaction costs if self.broker.transaction_fee: pnl -= MARKET_ORDER_FEE if self.broker.long_inventory_count > 0: # Net out existing position order = MarketOrder(ccy=self.symbol, side='long', price=self.best_bid, step=self.local_step_number) pnl += self.broker.remove(order=order) elif self.broker.short_inventory_count >= 0: order = MarketOrder(ccy=self.symbol, side='short', price=self.best_bid, step=self.local_step_number) if self.broker.add(order=order) is False: action_penalty_reward -= ENCOURAGEMENT else: raise ValueError( ('gym_trading.get_reward() Error for action #{} - ' 'unable to place an order with broker').format(action)) else: raise ValueError( ('Unknown action to take in get_reward(): ' 'action={} | midpoint={}').format(action, self.midpoint)) return action_penalty_reward, pnl
def map_action_to_broker(self, action: int): """ Create or adjust orders per a specified action and adjust for penalties. :param action: (int) current step's action :return: (float) reward """ reward = pnl = 0.0 discouragement = 0.000000000001 if action == 0: # do nothing reward += discouragement elif action == 1: # buy if self.broker.short_inventory_count > 0: order = MarketOrder(ccy=self.sym, side='short', price=self.midpoint, step=self.local_step_number) pnl += self.broker.remove(order=order) elif self.broker.long_inventory_count >= 0: order = MarketOrder( ccy=self.sym, side='long', price=self.midpoint, # price_fee_adjusted, step=self.local_step_number) if self.broker.add(order=order) is False: reward -= discouragement else: print(( 'gym_trading.get_reward() Error for action #{} - unable to place ' 'an order with broker').format(action)) elif action == 2: # sell if self.broker.long_inventory_count > 0: order = MarketOrder(ccy=self.sym, side='long', price=self.midpoint, step=self.local_step_number) pnl += self.broker.remove(order=order) elif self.broker.short_inventory_count >= 0: order = MarketOrder(ccy=self.sym, side='short', price=self.midpoint, step=self.local_step_number) if self.broker.add(order=order) is False: reward -= discouragement else: print(( 'gym_trading.get_reward() Error for action #{} - unable to place ' 'an order with broker').format(action)) else: print(( 'Unknown action to take in get_reward(): action={} | midpoint={}' ).format(action, self.midpoint)) return reward, pnl