Connects to IB Gateway through ib_async and trades the S&P 500 with the UpCap+MomGap factor combo ported from quant-trading's fc_up_cap_mom_gap_daily: signal on opens through today's open, equal weight top 10, MOC orders filled at today's close, 10% resize band. - make universe/bars/check/plan/submit/fills for the daily loop; refuses non-paper accounts unless allow_live, open orders, stale bars, and orders outside 09:31-15:45 ET - make backtest replays the live loop day by day with plan_orders and IBKR Fixed commissions; selection uses each day's index members - make bars fails fast when the Gateway's historical farm is down Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
1.4 KiB
Python
44 lines
1.4 KiB
Python
import pytest
|
|
|
|
from ibkr_quant.rebalance import plan_orders
|
|
|
|
|
|
def test_closes_dropped_names_and_sells_before_buys():
|
|
orders = plan_orders(
|
|
target_weights={"AAPL": 0.5, "MSFT": 0.5},
|
|
positions={"AAPL": 10, "NVDA": 7},
|
|
prices={"AAPL": 100.0, "MSFT": 300.0, "NVDA": 50.0},
|
|
investable=10_000,
|
|
min_trade_value=200,
|
|
)
|
|
assert [(o.symbol, o.delta) for o in orders] == [("NVDA", -7), ("AAPL", 40), ("MSFT", 16)]
|
|
|
|
|
|
def test_skips_small_adjustments_but_not_full_exits():
|
|
orders = plan_orders(
|
|
target_weights={"AAPL": 1.0},
|
|
positions={"AAPL": 99, "KO": 1},
|
|
prices={"AAPL": 100.0, "KO": 60.0},
|
|
investable=10_000,
|
|
min_trade_value=200,
|
|
)
|
|
assert [(o.symbol, o.delta) for o in orders] == [("KO", -1)]
|
|
|
|
|
|
def test_refuses_to_plan_without_prices():
|
|
with pytest.raises(ValueError, match="NVDA"):
|
|
plan_orders({"AAPL": 1.0}, {"NVDA": 5}, {"AAPL": 100.0}, 10_000, 0)
|
|
|
|
|
|
def test_resize_band_keeps_near_target_holdings():
|
|
orders = plan_orders(
|
|
target_weights={"AAPL": 0.5, "MSFT": 0.5},
|
|
positions={"AAPL": 46, "MSFT": 10},
|
|
prices={"AAPL": 100.0, "MSFT": 300.0},
|
|
investable=10_000,
|
|
min_trade_value=50,
|
|
resize_band=0.10,
|
|
)
|
|
# AAPL is 8% under target and stays; MSFT is 40% under and tops up.
|
|
assert [(o.symbol, o.delta) for o in orders] == [("MSFT", 6)]
|