def test_imbalance(mocker): """ Test imbalance calculation """ mocker.patch('rlmarket.environment.exchange_elements.pickle.load', return_value=[]) mocker.patch('builtins.open', mocker.mock_open()) env = Exchange('', 0, indicators=[]) ind = Imbalance(2, decay=0) assert ind.dimension == 1 env.book.add_limit_order(LimitOrder(1, 1, 'B', 10000, 100)) env.book.add_limit_order(LimitOrder(2, 2, 'S', 12000, 100)) assert ind.update(env) == (0, ) env.book.add_limit_order(LimitOrder(3, 3, 'S', 11000, 100)) assert ind.update(env) == (-100 / 300, ) env.book.match_limit_order(MarketOrder(4, 3, 'B', 50)) assert ind.update(env) == (-50 / 250, ) env.book.add_limit_order(LimitOrder(4, 4, 'B', 9000, 100)) assert ind.update(env) == (50 / 350, ) # We only use the first two levels env.book.add_limit_order(LimitOrder(5, 5, 'B', 8000, 100)) assert ind.update(env) == (50 / 350, ) ind = Imbalance(2, decay=1) bid_vol = 100 + 100 * np.exp(1) ask_vol = 100 + 50 * np.exp(1) assert abs(ind.update(env)[0] - (bid_vol - ask_vol) / (bid_vol + ask_vol)) < 1E-10
def test_pnl_calculation(): """ Test private method _calculate_pnl * Buy and sell * Same side no execution. Queue increases * Opposite side * shares < queued shares * shares == queued shares * shares > queued shares * Multiple shares """ exchange = NewExchange(files=[''], indicators=[Position(), Imbalance(1, decay=0)], reward_lb=-1000, reward_ub=1000, start_time=start_time, end_time=end_time, latency=delta, order_size=50, position_limit=100) # Case 1 - shares < queued shares assert exchange._calculate_pnl(Execution(1, 100, 100)) == 0 assert exchange._calculate_pnl(Execution(2, 120, -50)) == 1000 assert len(exchange._open_positions) == 1 assert exchange._open_positions[0].price == 100 assert exchange._open_positions[0].shares == 50 # Case 2 - shares == queued shares assert exchange._calculate_pnl(Execution(3, 90, -50)) == -500 assert len(exchange._open_positions) == 0 # Case 3 - same side assert exchange._calculate_pnl(Execution(4, 100, -100)) == 0 assert exchange._calculate_pnl(Execution(5, 110, -100)) == 0 assert exchange._calculate_pnl(Execution(6, 120, -100)) == 0 assert len(exchange._open_positions) == 3 # Case ? - FIFO assert exchange._calculate_pnl(Execution(7, 110, 50)) == -500 # Case 4 - shares > queued shares assert exchange._calculate_pnl(Execution( 8, 90, 200)) == 10 * 50 + 20 * 100 + 30 * 50 assert len(exchange._open_positions) == 1 assert exchange._open_positions[0].price == 120 assert exchange._open_positions[0].shares == -50
def test_block_exchange(mocker): """ * Test if the correct reward and metric are outputted * Test liquidation """ mocker.patch('rlmarket.environment.exchange_elements.pickle.load', return_value=deepcopy(tape)) mocker.patch('builtins.open', mocker.mock_open()) exchange = NewExchange(files=[''], indicators=[Position(), Imbalance(1, decay=0)], reward_lb=-2000, reward_ub=2000, start_time=start_time, end_time=end_time, latency=delta, order_size=50, position_limit=100) assert exchange.state_dimension == 2 state = exchange.reset() assert exchange.book.quote == (10000, 12000) assert state == (0, 50 / 250) state, reward, pnl1, done = exchange.step(3) # Buy 50 @ 10000 assert state == (50, -75 / 125) assert reward == 0 assert pnl1 == 0 assert not done state, reward, pnl2, done = exchange.step(3) # Sell 50 @ 12000 assert state == (0, -75 / 125) assert reward == 10 assert pnl2 == 10 assert not done state, reward, pnl3, done = exchange.step(3) # Buy 50 @ 9000 assert state == (50, -50 / 150) assert reward == 0 assert pnl3 == 0 assert not done state, reward, pnl4, done = exchange.step( 3) # Buy 50 @ 8000 and liquidate 20 @ 6000 assert state == (80, -50 / 150) assert reward == -20 # Two times of reward lower bound because of liquidation assert pnl4 == -6 assert not done state, reward, pnl5, done = exchange.step(3) # Sell 50 @ 13000 assert state == (30, 25 / 75) assert reward == 10 # Reach upper bound assert pnl5 == 30 * 0.4 + 20 * 0.5 assert not done state, reward, pnl6, done = exchange.step(3) # Sell 50 @ 14000 assert state == (-20, 0) assert reward == 10 # Reach upper bound assert pnl6 == 30 * 0.6 assert not done # Total total_pnl = pnl1 + pnl2 + pnl3 + pnl4 + pnl5 + pnl6 assert total_pnl == -50 * 1 + 50 * 1.2 - 50 * 0.9 - 50 * 0.8 + 20 * 0.6 + 50 * 1.3 + 30 * 1.4 # Finishing assert not exchange.book.empty exchange.clean_up() assert exchange.book.empty # Test restart. Should output the same stats mocker.patch('rlmarket.environment.exchange_elements.pickle.load', return_value=deepcopy(tape)) state = exchange.reset() assert exchange.book.quote == (10000, 12000) assert state == (0, 50 / 250) _, _, metric, _ = exchange.step(3) assert metric == 0 _, _, metric, _ = exchange.step(3) assert metric == 10 _, _, metric, _ = exchange.step(3) assert metric == 0 _, _, metric, _ = exchange.step(3) assert metric == -6 _, _, metric, _ = exchange.step(3) assert metric == 22 _, _, metric, _ = exchange.step(3) assert metric == 18
environment.clean_up() print(f'Pnl: {total_pnl} / Reward: {total_reward}') if __name__ == '__main__': # Parameters order_size = 50 position_limit = 1000 liquidation_ratio = 0.2 reward_lb = -0.004 reward_ub = 0.002 indicators = [ MidPriceDeltaSign(3), Imbalance(), NormalizedPosition(position_limit) ] env = RelativeExchange(files=[ 'AAPL_20170201', 'AAPL_20170202', 'AAPL_20170203', 'AAPL_20170206' ], indicators=indicators, reward_lb=reward_lb, reward_ub=reward_ub, start_time=34230000000000, end_time=57540000000000, order_size=order_size, position_limit=position_limit, liquidation_ratio=liquidation_ratio)
def test_block_exchange(mocker): """ * Test if the correct reward and metric are outputted * Test liquidation """ mocker.patch('rlmarket.environment.exchange_elements.pickle.load', return_value=deepcopy(tape)) mocker.patch('builtins.open', mocker.mock_open()) exchange = BlockExchange(files=[''], indicators=[Position(), Imbalance(1, decay=0)], start_time=start_time, end_time=end_time, latency=delta, order_size=50, position_limit=100, block_size=2) assert exchange.state_dimension == 2 state = exchange.reset() assert exchange.book.quote == (10000, 12000) assert state == (0, 50 / 250) # ====== Block 1 ====== state, reward, metric, done = exchange.step(0) # Buy 50 @ 10000 assert state == (50, -75 / 125) assert reward is None assert metric is None assert not done state, reward, metric, done = exchange.step(0) # Sell 50 @ 12000 assert state == (0, -75 / 125) assert reward is None assert metric is None assert not done state, reward, metric1, done = exchange.step(0) # Buy 50 @ 9000 assert state == (50, -50 / 150) assert reward == 0.25 + (2.5 + 5) # last spread profit is not count assert metric1 == 2.5 + (2.5 + 5 + 7.5) assert not done # ====== Block 2 ====== state, reward, metric, done = exchange.step(0) # Buy 50 @ 8000 assert state == (80, -50 / 150) assert reward is None assert metric is None assert not done state, reward, metric, done = exchange.step(0) # Sell 50 @ 13000 assert state == (30, 25 / 75) assert reward is None assert metric is None assert not done state, reward, metric2, done = exchange.step(0) # Sell 50 @ 14000 assert state == (-20, 0) assert reward == (-50 * 1.05 - 50 * 1 + 20 * 0.95 + 50 * 1 + 30 * 1.1) + (10 - 7 + 15) assert metric2 == (-50 * 1.05 - 50 * 1 + 20 * 0.95 + 50 * 1 + 30 * 1.1) + (10 - 7 + 15 + 15) assert not done # Total assert metric1 + metric2 == -50 * 1 + 50 * 1.2 - 50 * 0.9 - 50 * 0.8 + 20 * 0.6 + 50 * 1.3 + 50 * 1.4 - 20 * 1.1 # Finishing assert not exchange.book.empty exchange.clean_up() assert exchange.book.empty # Test restart. Should output the same stats mocker.patch('rlmarket.environment.exchange_elements.pickle.load', return_value=deepcopy(tape)) state = exchange.reset() assert exchange.book.quote == (10000, 12000) assert state == (0, 50 / 250) _, _, metric, _ = exchange.step(0) assert metric is None _, _, metric, _ = exchange.step(0) assert metric is None _, _, metric1, _ = exchange.step(0) assert metric1 == 2.5 + (2.5 + 5 + 7.5)
def test_exchange(mocker): mocker.patch('rlmarket.environment.exchange_elements.pickle.load', return_value=deepcopy(tape)) mocker.patch('builtins.open', mocker.mock_open()) position_limit = 100 exchange = AbsoluteExchange( files=[''], indicators=[Position(), Imbalance(1, decay=0)], reward_lb=-0.2, reward_ub=0.3, # Bounds in percentage start_time=start_time, end_time=end_time, latency=delta, order_size=50, position_limit=position_limit) assert exchange.observation_space.shape == (2, ) state = exchange.reset() assert exchange.book.quote == (10000, 12000) assert_almost_equal(state, (0, 50 / 250)) total_pnl = 0 state, reward, done, info = exchange.step(3) # Buy 50 @ 10000 assert_almost_equal(state, (50, -75 / 125)) assert reward == 0 assert info['pnl'] == 0 assert not done total_pnl += info['pnl'] state, reward, done, info = exchange.step(3) # Sell 50 @ 12000 assert_almost_equal(state, (0, -75 / 125)) assert reward == 10 assert info['pnl'] == 10 assert not done total_pnl += info['pnl'] state, reward, done, info = exchange.step(3) # Buy 50 @ 9000 assert_almost_equal(state, (50, -50 / 150)) assert reward == 0 assert info['pnl'] == 0 assert not done total_pnl += info['pnl'] state, reward, done, info = exchange.step( 3) # Buy 50 @ 8000 and liquidate 20 @ 6000 assert_almost_equal(state, (80, -50 / 150)) assert reward == -4 # Two times of reward lower bound because of liquidation assert info['pnl'] == -6 assert not done total_pnl += info['pnl'] state, reward, done, info = exchange.step(3) # Sell 50 @ 13000 assert_almost_equal(state, (30, 25 / 75)) assert reward == 15 # Reach upper bound assert info['pnl'] == 30 * 0.4 + 20 * 0.5 assert not done total_pnl += info['pnl'] state, reward, done, info = exchange.step(3) # Sell 50 @ 14000 assert_almost_equal(state, (-20, 0)) assert reward == 9 # Close out 30 shares at a profit of 0.36 -> 0.3 * 30 = 9 assert info['pnl'] == 30 * 0.6 assert not done total_pnl += info['pnl'] # Total assert total_pnl == -50 * 1 + 50 * 1.2 - 50 * 0.9 - 50 * 0.8 + 20 * 0.6 + 50 * 1.3 + 30 * 1.4 # Finishing assert not exchange.book.empty exchange.clean_up() assert exchange.book.empty # Test restart. Should output the same stats mocker.patch('rlmarket.environment.exchange_elements.pickle.load', return_value=deepcopy(tape)) state = exchange.reset() assert exchange.book.quote == (10000, 12000) assert_almost_equal(state, (0, 50 / 250)) _, _, _, info = exchange.step(3) assert info['pnl'] == 0 _, _, _, info = exchange.step(3) assert info['pnl'] == 10 _, _, _, info = exchange.step(3) assert info['pnl'] == 0 _, _, _, info = exchange.step(3) assert info['pnl'] == -6 _, _, _, info = exchange.step(3) assert info['pnl'] == 22 _, _, _, info = exchange.step(3) assert info['pnl'] == 18
def test_basic_exchange(mocker): """ * Test order placement with latency * Test that once an order is executed, another will be cancelled * Test liquidation """ mocker.patch('rlmarket.environment.exchange_elements.pickle.load', return_value=tape) mocker.patch('builtins.open', mocker.mock_open()) exchange = Exchange(files=[''], indicators=[Position(), Imbalance(1, decay=0)], start_time=start_time, end_time=end_time, latency=delta, order_size=50, position_limit=100) state = exchange.reset() assert exchange.state_dimension == 2 assert exchange.book.quote == (10000, 12000) assert state == (0, 50 / 250) # Test order placement state, reward, metric, done = exchange.step( 0) # Placed order at 10000 and 12000 assert state == (50, -75 / 125 ) # Real level is already move to the 9000 level assert reward == 0 assert metric == 0 assert not done assert exchange.book.bid_book.user_order_info is None assert exchange.book.ask_book.user_order_info is None # Order is cancelled # Test order placement - complete an update full cycle to output rewards state, reward, metric, done = exchange.step( 0) # Placing order at 9000 and 12000 assert exchange.book.quote == (9000, 13000) assert state == (0, -75 / 125 ) # Real level is already move to the 9000 level assert reward == 2.5 + 2.5 * 0.1 # Last reward assert metric == 2.5 + 2.5 assert not done # Last cycle finishes. Clean start assert exchange.book.bid_book.user_order_info is None assert exchange.book.ask_book.user_order_info is None # Test liquidation state, reward, metric, done = exchange.step( 0) # Placing order at 9000 and 13000 assert exchange.book.quote == (8000, 13000) assert state == (50, -50 / 150) # Real level is at 9000 and 12000 assert reward == 5 # No position pnl because position was 0 assert metric == 5 assert not done state, reward, metric, done = exchange.step( 0) # Placing order at 8000 and 13000 assert exchange.book.quote == (6000, 14000) # Order 7 is cancelled print(exchange.book.get_depth(5)) assert state == ( 80, 0) # Liquidation. Also, Order 5 of 50 shares vs Order 8 of 50 assert reward == 7.5 - 5 assert metric == 7.5 - 5 assert not done # Market is cleared state, reward, metric, done = exchange.step(0) assert state == (30, 0) assert reward == 7.5 - 8 + 13 * 0.1 assert metric == 7.5 - 8 + 13 assert not done assert not exchange.book.empty # Final cleanup exchange.clean_up() assert exchange.book.empty