"""Guards of the IBKR order layer (ibkr_trader.py): which accounts it may trade, how much it sizes, and which orders it will send.""" import unittest import ibkr_trader as it class AccountGuard(unittest.TestCase): def test_paper_account_trades_without_flags(self): self.assertFalse(it.check_account(["DU123"], "DU123", live=False, armed=False)) def test_account_must_be_managed_by_the_login(self): with self.assertRaises(SystemExit): it.check_account(["DU123"], "U999", live=True, armed=True) with self.assertRaises(SystemExit): it.check_account(["U999"], "", live=True, armed=True) def test_live_account_needs_flag_and_armed_file(self): with self.assertRaises(SystemExit): it.check_account(["U999"], "U999", live=False, armed=True) with self.assertRaises(SystemExit): it.check_account(["U999"], "U999", live=True, armed=False) self.assertTrue(it.check_account(["U999"], "U999", live=True, armed=True)) def test_read_only_use_skips_the_trading_flags(self): self.assertTrue(it.check_account(["U999"], "U999", live=False, armed=False, trading=False)) def test_live_account_number_is_masked(self): self.assertEqual(it.mask("U1234567"), "U***567") self.assertEqual(it.mask("DU123"), "DU123") class Sizing(unittest.TestCase): def test_orders_are_sized_on_the_capped_equity(self): trades = it.size_orders({"TQQQ": 1.0}, {}, {"TQQQ": 100.0}, nav=972_000.0, resize_band=0.1) self.assertEqual([t["ticker"] for t in trades], ["TQQQ"]) self.assertLessEqual(trades[0]["shares_delta"] * 100.0, it.MAX_EQUITY * (1 - it.CASH_BUFFER)) self.assertGreater(trades[0]["shares_delta"], 95) def test_a_switch_sells_the_old_leg_and_buys_the_new(self): trades = it.size_orders({"GLD": 1.0}, {"TQQQ": 100}, {"TQQQ": 100.0, "GLD": 300.0}, nav=10_000.0, resize_band=0.1) by = {t["ticker"]: t["shares_delta"] for t in trades} self.assertEqual(by["TQQQ"], -100) self.assertLessEqual(by["GLD"] * 300.0, 10_000.0 * (1 - it.CASH_BUFFER)) self.assertGreaterEqual(by["GLD"], 32) def test_missing_price_stops_the_run(self): with self.assertRaises(SystemExit): it.size_orders({"TQQQ": 1.0}, {"GLD": 3}, {"TQQQ": 100.0}, nav=10_000.0, resize_band=0.1) class OrderWhitelist(unittest.TestCase): def test_only_universe_symbols_and_whole_shares(self): with self.assertRaises(SystemExit): it.validate_orders([{"ticker": "AAPL", "shares_delta": 1}], {"TQQQ"}, {}) with self.assertRaises(SystemExit): it.validate_orders([{"ticker": "TQQQ", "shares_delta": 1.5}], {"TQQQ"}, {}) def test_never_sells_more_than_held(self): with self.assertRaises(SystemExit): it.validate_orders([{"ticker": "TQQQ", "shares_delta": -5}], {"TQQQ"}, {"TQQQ": 3}) it.validate_orders([{"ticker": "TQQQ", "shares_delta": -3}], {"TQQQ"}, {"TQQQ": 3}) def test_orders_are_market_on_close(self): o = it.moc_order(-7, "DU123", "ibkr_trader 2026-10-13") self.assertEqual((o.action, o.totalQuantity, o.orderType, o.tif, o.account), ("SELL", 7, "MOC", "DAY", "DU123")) with self.assertRaises(ValueError): it.moc_order(0, "DU123", "x") if __name__ == "__main__": unittest.main()