def test_simulate_trade_mix_trades(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=1, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=1, symbol='a2') f1 = Fund('f1', {'a1': 10}, 100, 1, 1) f2 = Fund('f2', {'a2': 10}, 100, 1, 1) mi_calc = MarketImpactCalculator() mi_calc.get_updated_price = MagicMock(return_value=1.5) network = AssetFundNetwork.AssetFundsNetwork(funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2 }, mi_calc=mi_calc, limit_trade_step=False) network.submit_sell_orders([Sell('a2', 2)]) network.submit_buy_orders([Buy('a1', 2)]) log = network.simulate_trade() calls = [call(2, a2, -1), call(2, a1, 1)] mi_calc.get_updated_price.assert_has_calls(calls, any_order=True) self.assertDictEqual({'a1': '1->1.5', 'a2': '2->1.5'}, log) self.assertFalse(network.buy_orders) self.assertFalse(network.sell_orders)
def test_simulate_trade_buy_equals_sell(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=1, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=1, symbol='a2') f1 = Fund('f1', {'a1': 10}, 100, 1, 1) f2 = Fund('f2', {'a2': 10}, 100, 1, 1) mi_calc = MarketImpactCalculator() mi_calc.get_updated_price = MagicMock() network = AssetFundNetwork.AssetFundsNetwork(funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2 }, mi_calc=mi_calc, limit_trade_step=False) network.submit_buy_orders([Buy('a1', 3)]) network.submit_sell_orders([Sell('a1', 3)]) log = network.simulate_trade() mi_calc.get_updated_price.assert_not_called() self.assertFalse(log) self.assertFalse(network.buy_orders) self.assertFalse(network.sell_orders) self.assertTrue(a1.price == 1) self.assertTrue(a2.price == 2)
def test_run_intraday_simulation_raises_exception_for_price_reduction( self): a0 = Asset(price=1, daily_volume=40, volatility=1.5, symbol='a0') a1 = Asset(price=2, daily_volume=40, volatility=1.5, symbol='a1') f0 = Fund('f0', {'a0': 10}, initial_capital=2, initial_leverage=8, tolerance=2) f1 = Fund('f1', { 'a0': 10, 'a1': 1 }, initial_capital=1, initial_leverage=1, tolerance=3) network = AssetFundsNetwork({ 'f0': f0, 'f1': f1 }, { 'a0': a0, 'a1': a1 }, MockMarketImpactTestCalculator()) with self.assertRaises(ValueError): network.run_intraday_simulation(0.8, 0.7)
def test_funds_under_risk(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=100, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=200, symbol='a2') f1 = Fund('f1', {'a1': 10, 'a2': 10, 'a3': 10}, 100, 1, 1) f2 = Fund('f2', {'a1': 10}, 100, 1, 1) network = AssetFundNetwork.AssetFundsNetwork( funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2 }, mi_calc=MockMarketImpactTestCalculator()) network.reset_order_books = MagicMock() network.simulate_trade = MagicMock() network.submit_sell_orders = MagicMock() network.get_funds_in_margin_calls = MagicMock(return_value=['f1']) actions_mgr = ActionsManager(network.assets, 0.1) actual_funds = actions_mgr._ActionsManager__funds_under_risk(network) self.assertListEqual(actual_funds, ['f1']) network.reset_order_books.assert_called_once() network.submit_sell_orders.assert_called_once_with( [Sell('a1', 10), Sell('a2', 20)]) network.simulate_trade.assert_called_once() network.get_funds_in_margin_calls.assert_called_once()
def test_get_possible_defenses_integ(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=100, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=100, symbol='a2') a3 = AssetFundNetwork.Asset(price=3, daily_volume=100, symbol='a3') a4 = AssetFundNetwork.Asset(price=1, daily_volume=100, symbol='a4') f1 = Fund('f1', {'a1': 10, 'a2': 10, 'a3': 10}, 100, 1, 1) f2 = Fund('f2', {'a4': 10}, 100, 1, 1) network = AssetFundNetwork.AssetFundsNetwork( funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2, 'a3': a3, 'a4': a4 }, mi_calc=MockMarketImpactTestCalculator()) actions_mgr = ActionsManager(network.assets, 0.1) history = {BUY: {'a1': 2}, SELL: {'a1': 1, 'a2': 2}} budget = 20 actions_mgr._ActionsManager__funds_under_risk = MagicMock( return_value=['f1']) actual_defenses = actions_mgr.get_possible_defenses( network, budget, history) self.assertListEqual(actual_defenses, [([Buy('a2', 10)], 20), ([], 0)]) actions_mgr._ActionsManager__funds_under_risk.assert_called_once_with( network)
def test_simulate_trade_sell_more_than_buy(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=1, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=1, symbol='a2') f1 = Fund('f1', {'a1': 10}, 100, 1, 1) f2 = Fund('f2', {'a2': 10}, 100, 1, 1) mi_calc = MarketImpactCalculator() mi_calc.get_updated_price = MagicMock(return_value=0.5) network = AssetFundNetwork.AssetFundsNetwork(funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2 }, mi_calc=mi_calc, limit_trade_step=False) network.submit_buy_orders([Buy('a1', 2)]) network.submit_sell_orders([Sell('a1', 3)]) log = network.simulate_trade() self.assertDictEqual({'a1': '1->0.5'}, log) mi_calc.get_updated_price.assert_called_once_with(1, a1, -1) self.assertFalse(network.buy_orders) self.assertFalse(network.sell_orders) self.assertTrue(a1.price == 0.5) self.assertTrue(a2.price == 2)
def test_simulate_trade_sell_orders_in_buy_command(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=1, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=1, symbol='a2') f1 = Fund('f1', {'a1': 10}, 100, 1, 1) f2 = Fund('f2', {'a2': 10}, 100, 1, 1) mi_calc = MarketImpactCalculator() mi_calc.get_updated_price = MagicMock() network = AssetFundNetwork.AssetFundsNetwork(funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2 }, mi_calc=mi_calc, limit_trade_step=False) exception = False try: network.submit_buy_orders([Buy('a1', 2), Sell('a1', 2)]) except TypeError: exception = True mi_calc.get_updated_price.assert_not_called() self.assertTrue(exception)
def test_get_possible_attacks(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=10, symbol='a1') a1.set_price(3) a2 = AssetFundNetwork.Asset(price=2, daily_volume=4, symbol='a2') a2.set_price(4) a3 = AssetFundNetwork.Asset(price=7, daily_volume=2, symbol='a3') f1 = Fund('f1', {'a1': 10, 'a2': 10, 'a3': 10}, 100, 1, 1) f2 = Fund('f2', {'a1': 10}, 100, 1, 1) SysConfig.set("STEP_ORDER_SIZE", 0.5) network = AssetFundNetwork.AssetFundsNetwork( funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2, 'a3': a3 }, mi_calc=MockMarketImpactTestCalculator()) actual_orders = get_possible_attacks(network, 10) expected_orders = [] expected_orders.append(([Sell('a1', 5)], 5)) expected_orders.append(([Sell('a2', 2)], 4)) expected_orders.append(([Sell('a3', 1)], 7)) expected_orders.append(([Sell('a1', 5), Sell('a2', 2)], 9)) expected_orders.append(([], 0)) self.assertEqual(actual_orders, expected_orders)
def test_get_orders(self): assets = { 'XXX': Asset(1, 20, 1.5, 'XXX'), 'YYY': Asset(1, 20, 1.5, 'yyy') } fund = Fund('F1', {'XXX': 5, 'YYY': 4}, 5, 2, 0.25) self.assertEqual(fund.get_orders(assets), [])
def test_get_canonical_form(self): a0 = Asset(price=1, daily_volume=40, volatility=1.5, symbol='a0') a1 = Asset(price=2, daily_volume=40, volatility=1.5, symbol='a1') f0 = Fund('f0', {'a0': 10}, initial_capital=2, initial_leverage=8, tolerance=2) f1 = Fund('f1', { 'a0': 10, 'a1': 10 }, initial_capital=1, initial_leverage=1, tolerance=3) network = AssetFundsNetwork({ 'f0': f0, 'f1': f1 }, { 'a0': a0, 'a1': a1 }, MockMarketImpactTestCalculator()) expected_canonical_form = np.array([[10., 0.], [10., 20.]]) actual_canonical_form = network.get_canonical_form() self.assertTrue( np.array_equal(expected_canonical_form, actual_canonical_form))
def test_get_possible_defenses(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=10, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=4, symbol='a2') a3 = AssetFundNetwork.Asset(price=7, daily_volume=2, symbol='a3') f1 = Fund('f1', {'a1': 10, 'a2': 10, 'a3': 10}, 100, 1, 1) f2 = Fund('f2', {'a1': 10}, 100, 1, 1) SysConfig.set("STEP_ORDER_SIZE", 0.5) network = AssetFundNetwork.AssetFundsNetwork( funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2, 'a3': a3 }, mi_calc=MockMarketImpactTestCalculator()) actual_orders = get_possible_defenses(network, 10) expected_orders = [] expected_orders.append(([Buy('a1', 5)], 5)) expected_orders.append(([Buy('a2', 2)], 4)) expected_orders.append(([Buy('a3', 1)], 7)) expected_orders.append(([Buy('a1', 5), Buy('a2', 2)], 9)) expected_orders.append(([], 0)) actual_orders.sort(key=operator.itemgetter(1)) expected_orders.sort(key=operator.itemgetter(1)) self.assertEqual(len(actual_orders), len(expected_orders)) for i in range(0, len(actual_orders)): actual_orders[i][0].sort(key=lambda x: x.asset_symbol) expected_orders[i][0].sort(key=lambda x: x.asset_symbol) self.assertListEqual(actual_orders[i][0], expected_orders[i][0]) self.assertEqual(actual_orders[i][1], expected_orders[i][1])
def test_compute_compute_curr_leverage(self): assets = { 'XXX': Asset(1, 20, 1.5, 'XXX'), 'YYY': Asset(4, 20, 1.5, 'yyy') } fund = Fund('F1', {'XXX': 10, 'YYY': 10}, 5, 2, 3) self.assertEqual(0.25, fund.compute_curr_leverage(assets))
def dont_test_get_possible_defenses(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=10, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=4, symbol='a2') a3 = AssetFundNetwork.Asset(price=7, daily_volume=2, symbol='a3') f1 = Fund('f1', {'a1': 10, 'a2': 10, 'a3': 10}, 100, 1, 1) f2 = Fund('f2', {'a1': 10}, 100, 1, 1) SysConfig.set("ORDER_SIZES", [0.5, 1]) network = AssetFundNetwork.AssetFundsNetwork( funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2, 'a3': a3 }, mi_calc=MockMarketImpactTestCalculator()) actual_orders = get_possible_defenses(network, 10) expected_orders = [] expected_orders.append(([Buy('a1', 5)], 5)) expected_orders.append(([Buy('a1', 10)], 10)) expected_orders.append(([Buy('a2', 2)], 4)) expected_orders.append(([Buy('a2', 4)], 8)) expected_orders.append(([Buy('a3', 1)], 7)) expected_orders.append(([Buy('a1', 5), Buy('a2', 2)], 9)) expected_orders.append(([], 0)) self.assertEqual(actual_orders, expected_orders)
def test_marginal_call_true(self): assets = { 'XXX': Asset(1, 20, 1.5, 'XXX'), 'YYY': Asset(1, 20, 1.5, 'yyy') } fund = Fund('F1', {'XXX': 10, 'YYY': 10}, 5, 2, 3) self.assertTrue(True, fund.marginal_call(assets))
def test_compute_portfolio_value(self): assets = { 'XXX': Asset(1, 20, 1.5, 'XXX'), 'YYY': Asset(4, 20, 1.5, 'yyy') } fund = Fund('F1', {'XXX': 10, 'YYY': 10}, 5, 2, 3) self.assertEqual(50, fund.compute_portfolio_value(assets))
def test_gen_liquidation_orders(self): SysConfig.set("MINUTE_VOLUME_LIMIT", 0.1) assets = { 'XXX': Asset(2, 3900, 1.5, 'XXX'), 'YYY': Asset(1, 7900, 1.5, 'yyy'), 'ZZZ': Asset(1, 7900, 1.5, 'yyy') } fund = Fund('F1', {'XXX': 10, 'YYY': 11, 'ZZZ': 2}, 5, 2, 0.25) expected_orders = [Sell('XXX', 1), Sell('YYY', 2), Sell('ZZZ', 2)] expected_portfolio = {'XXX': 9, 'YYY': 9} orders = fund.gen_liquidation_orders(assets) self.assertEqual(orders, expected_orders) self.assertEqual(fund.portfolio, expected_portfolio)
def test_is_liquidated(self): fund = Fund('F1', {'XXX': 10, 'YYY': 10}, 5, 2, 3) self.assertFalse(fund.is_in_margin_call()) fund.is_liquidating = True self.assertTrue(fund.is_in_margin_call()) fund.is_liquidating = False self.assertFalse(fund.is_in_margin_call())
def test_default(self): fund = Fund('F1', {'XXX': 10, 'YYY': 10}, 5, 2, 3) self.assertFalse(fund.default()) fund.is_in_default = True self.assertTrue(fund.default()) fund.is_in_default = False self.assertFalse(fund.default())
def dont_test_get_possible_defenses_unit(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=100, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=100, symbol='a2') a3 = AssetFundNetwork.Asset(price=3, daily_volume=100, symbol='a3') a4 = AssetFundNetwork.Asset(price=1, daily_volume=100, symbol='a4') f1 = Fund('f1', {'a1': 10, 'a2': 10, 'a3': 10}, 100, 1, 1) f2 = Fund('f2', {'a4': 10}, 100, 1, 1) network = AssetFundNetwork.AssetFundsNetwork( funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2, 'a3': a3, 'a4': a4 }, mi_calc=MockMarketImpactTestCalculator()) actions_mgr = ActionsManager(network.assets, 0.1) actions_mgr.funds_under_risk = MagicMock(return_value=['f1']) actions_mgr.get_single_orders = MagicMock( return_value=[Buy('a1', 10), Buy('a2', 10), Buy('a3', 10)]) expected_order_set = [[Buy('a1', 10)]] actions_mgr.get_defenses_in_budget = MagicMock( return_value=[(expected_order_set, 10)]) history = {BUY: {'a1': 2}, SELL: {'a1': 1, 'a2': 2}} budget = 60 actual_defenses = actions_mgr.get_possible_defenses( network, budget, history) self.assertListEqual(actual_defenses, [(expected_order_set, 10), ([], 0)]) actions_mgr.funds_under_risk.assert_called_once_with(network) defense_assets = { 'a2': a2, 'a1': a1, 'a3': a3, } actions_mgr.get_single_orders.assert_called_once_with(defense_assets) filtered_defenses = [Buy('a2', 10), Buy('a3', 10)] actions_mgr.get_defenses_in_budget.assert_called_once_with( defense_assets, filtered_defenses)
def test_tree(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=100, symbol='a1') f1 = Fund('f1', {'a1': 10}, 100, 1, 1) f2 = Fund('f2', {'a1': 20}, 100, 1, 1) mi_calc = MarketImpactCalculator() mi_calc.get_updated_price = MagicMock() mi_calc.get_updated_price.side_effect = update_price_side_effects network = AssetFundNetwork.AssetFundsNetwork(funds={ 'f1': f1, 'f2': f2 }, assets={'a1': a1}, mi_calc=mi_calc, limit_trade_step=False) action_manager = ActionsManager(network.assets, 0.5, 1, [50, 30]) SysConfig.set("STEP_ORDER_SIZE", 0.5) f1.marginal_call = MagicMock(return_value=False) f2.marginal_call = MagicMock() f2.marginal_call.side_effect = f1_margin_call_side_effect actual_tree = PortfolioFlashCrashRootChanceGameState( action_manager, af_network=network, defender_budget=50) expected_tree = self.gen_tree() self.assertEqual(actual_tree.chance_prob(), {'p1': 0.75, 'p2': 0.25}) self.assertEqual(actual_tree.tree_size, 8) self.cmp_tree(expected_tree, actual_tree)
def test_reset_books(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=1, symbol='a1') a2 = AssetFundNetwork.Asset(price=2, daily_volume=1, symbol='a2') f1 = Fund('f1', {'a1': 10}, 100, 1, 1) f2 = Fund('f2', {'a2': 10}, 100, 1, 1) network = AssetFundNetwork.AssetFundsNetwork( funds={ 'f1': f1, 'f2': f2 }, assets={ 'a1': a1, 'a2': a2 }, mi_calc=MockMarketImpactTestCalculator(), limit_trade_step=True) network.submit_buy_orders([Buy('a1', 2)]) network.submit_sell_orders([Sell('a1', 2)]) self.assertTrue(network.sell_orders) self.assertTrue(network.buy_orders) network.reset_order_books() self.assertFalse(network.sell_orders) self.assertFalse(network.buy_orders)
def dont_test_get_possible_attacks_single_asset_per_attack(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=2, symbol='a1') f1 = Fund('f1', {'a1': 10}, 100, 1, 1) SysConfig.set("ORDER_SIZES", [0.5, 1]) network = AssetFundNetwork.AssetFundsNetwork( funds={'f1': f1}, assets={'a1': a1}, mi_calc=MockMarketImpactTestCalculator()) actual_sell_orders = get_possible_attacks(network, 10) expected_sell_orders = [] expected_sell_orders.append(([Sell('a1', 2)], 2)) expected_sell_orders.append(([Sell('a1', 1)], 1)) expected_sell_orders.append(([], 0)) self.assertEqual(actual_sell_orders, expected_sell_orders)
def test_update_state_margin_only(self): assets = { 'XXX': Asset(1, 20, 1.5, 'XXX'), 'YYY': Asset(1, 20, 1.5, 'yyy') } fund = Fund('F1', {'XXX': 10, 'YYY': 10}, 5, 2, 0.25) fund.update_state(assets) self.assertTrue(fund.is_in_margin_call()) self.assertFalse(fund.default())
def test_run_intraday_simulation_price_rises(self): a0 = Asset(price=1, daily_volume=40, volatility=1.5, symbol='a0') a1 = Asset(price=2, daily_volume=40, volatility=1.5, symbol='a1') f0 = Fund('f0', {'a0': 10}, initial_capital=2, initial_leverage=8, tolerance=2) f1 = Fund('f1', { 'a0': 10, 'a1': 1 }, initial_capital=1, initial_leverage=1, tolerance=3) network = AssetFundsNetwork({ 'f0': f0, 'f1': f1 }, { 'a0': a0, 'a1': a1 }, MockMarketImpactTestCalculator()) network.run_intraday_simulation(1.5, 1) self.assertTrue(a0.price >= 1) self.assertTrue(a1.price >= 2)
def test_simulate_trade_limit_trade_step(self): a1 = AssetFundNetwork.Asset(price=1, daily_volume=1000, symbol='a1') f1 = Fund('f1', {'a1': 10}, 100, 1, 1) mi_calc = MarketImpactCalculator() mi_calc.get_updated_price = MagicMock(return_value=1.5) network = AssetFundNetwork.AssetFundsNetwork(funds={'f1': f1}, assets={'a1': a1}, mi_calc=mi_calc) SysConfig.set('TIME_STEP_MINUTES', 1) SysConfig.set('DAILY_PORTION_PER_MIN', 0.001) network.submit_buy_orders([Buy('a1', 2)]) log = network.simulate_trade() self.assertDictEqual({'a1': '1->1.5'}, log) mi_calc.get_updated_price.assert_called_once_with(1, a1, 1) self.assertEqual(network.buy_orders['a1'], 1)
def test_run_intraday_simulation_goal_leverage_reached(self): a0 = Asset(price=1, daily_volume=40, volatility=1.5, symbol='a0') a1 = Asset(price=2, daily_volume=40, volatility=1.5, symbol='a1') f0 = Fund('f0', {'a0': 10}, initial_capital=2, initial_leverage=8, tolerance=2) f1 = Fund('f1', { 'a0': 10, 'a1': 1 }, initial_capital=1, initial_leverage=1, tolerance=3) assets = {'a0': a0, 'a1': a1} network = AssetFundsNetwork({ 'f0': f0, 'f1': f1 }, assets, MockMarketImpactTestCalculator()) network.run_intraday_simulation(2, 0.8) self.assertTrue(f0.compute_curr_leverage(assets) <= 0.8) self.assertTrue(f1.compute_curr_leverage(assets) <= 0.8)
def test_update_funds(self): assets = { 'XXX': Asset(1, 20, 1.5, 'XXX'), 'YYY': Asset(1, 20, 1.5, 'yyy') } f1 = Fund('F1', {'XXX': 10, 'YYY': 10}, 5, 2, 0.25) f2 = Fund('F1', {'XXX': 5, 'YYY': 4}, 5, 2, 0.25) f3 = Fund('F1', {'XXX': 20, 'YYY': 4}, 5, 2, 4) network = AssetFundsNetwork({ 'f1': f1, 'f2': f2, 'f3': f3 }, assets, MockMarketImpactTestCalculator()) network.update_funds() self.assertTrue(f1.is_in_margin_call()) self.assertFalse(f1.default()) self.assertTrue(f2.is_in_margin_call()) self.assertTrue(f2.default()) self.assertFalse(f3.is_in_margin_call()) self.assertFalse(f3.default()) """a0 = Asset(price=1, daily_volume=40, volatility=1.5, symbol='a0')