TICKET-053: Live-rebalance entry point (load trained model → recommended orders)
Status: OPEN
Cycle: 43
Priority: High
Depends on: TICKET-052 (model persistence round-trip)
Target module: new alloc/lib/rebalance.py + alloc/core.py CLI wiring
Summary
The seed's predict mode is a true live-rebalance: it loads a previously
trained actor-critic model, fetches the latest market prices, constructs the
current market state, calls the model's public get_allocation to produce a
recommended allocation, executes the trades against the current portfolio
(transaction costs + shortfall scaling), and emits recommended orders plus the
post-execution portfolio value.
alloc/ has no equivalent. Its --predict CLI flag (alloc/core.py
main) just runs a fresh SimulationRunner.run() and saves
prediction_results.json; it never loads a trained model, never fetches
latest prices to build a live state, and never emits recommended orders from a
trained model.
Evidence
alloc/core.py main (lines 635-745): --predict sets mode_str but the
code path is identical to backtest except it skips saving weights. No model
load, no latest-price fetch, no get_allocation on a live state.
alloc/models/data.py already provides the pieces:
get_multi_asset_data(tickers, client) (line 161),
build_state_vector(multi_freq_data, current_allocation, tickers, n_hourly, n_daily, n_weekly) (line 255), and
fetch_latest_prices(tickers, client) (line 334).
alloc/models/portfolio.py Portfolio.execute_trades(target_allocation, prices) (line 93) already does the rebalance execution with shortfall
scaling and transaction costs.
alloc/models/networks.py ActorCriticNetworks.get_allocation(state)
(line 488) is the public inference entry point.
- The only missing glue is: load model → fetch data → build state →
get_allocation → seed a Portfolio from current positions →
execute_trades → return recommended orders + post-execution value.
Implementation plan
- New module
alloc/lib/rebalance.py with a
rebalance_portfolio(...) function (and a small dataclass or dict result):
- Inputs:
model_path, tickers, positions (dict ticker→dollar value),
client, n_hourly=5, n_daily=5, n_weekly=5, transaction_cost=0.0,
initial_value (optional; derived from positions if omitted).
- Steps:
a. networks = ActorCriticNetworks.load_model(model_path) (TICKET-052).
b. prices = fetch_latest_prices(tickers, client).
c. multi_freq = get_multi_asset_data(tickers, client).
d. Build current_allocation (non-cash weights) from positions +
prices (value / total, cash = remainder).
e. state = build_state_vector(multi_freq, current_allocation, tickers, n_hourly, n_daily, n_weekly).
f. allocation = networks.get_allocation(state).
g. Seed a Portfolio(tickers, initial_cash=initial_value, transaction_cost=...) with shares from positions/prices.
h. target = {t: allocation[i] for i,t in enumerate(tickers)}; target['cash'] = allocation[-1].
i. execution = portfolio.execute_trades(target, prices).
- Return a dict with:
recommended_allocation (ticker→weight incl. cash),
recommended_orders (list of {ticker, action, shares, price, value}),
portfolio_value_before, portfolio_value_after,
total_transaction_costs, scale_factor.
- CLI wiring in
alloc/core.py: add a --rebalance mode (or a
--positions + --model-path predict path) that calls
rebalance_portfolio and logs the recommended orders, mirroring the seed's
predict output. Keep the existing --predict (forward simulation) intact.
- Tests (
tests/test_rebalance.py): use a fake client (patch
fetch_latest_prices/get_multi_asset_data at the module level via
patch.object on the rebalance module's imported references, or inject a
stub client) and a small saved model (via TICKET-052 save_model) to
assert: allocation sums to 1.0, cash >= min_cash, orders are produced,
post-execution value is finite, and transaction costs are applied.
Verification
pytest tests/test_rebalance.py -x -q — all pass.
pytest tests/ -x -q — full suite green.
ruff check alloc/ — clean.
mypy alloc/ --ignore-missing-imports — clean.
Notes
- Semantics reference: read
~/Research/new-trader/trader/core.py
(predict mode, ~lines 863-935) and
~/Research/new-trader/utils/trader_tools/multi_rebalance_helper.py
(rebalance_portfolio, positions_to_allocation) for understanding only.
Nothing is copied; the implementation targets alloc's existing public API
(get_allocation, build_state_vector, fetch_latest_prices,
execute_trades).
TICKET-053: Live-rebalance entry point (load trained model → recommended orders)
Status: OPEN
Cycle: 43
Priority: High
Depends on: TICKET-052 (model persistence round-trip)
Target module: new
alloc/lib/rebalance.py+alloc/core.pyCLI wiringSummary
The seed's predict mode is a true live-rebalance: it loads a previously
trained actor-critic model, fetches the latest market prices, constructs the
current market state, calls the model's public
get_allocationto produce arecommended allocation, executes the trades against the current portfolio
(transaction costs + shortfall scaling), and emits recommended orders plus the
post-execution portfolio value.
alloc/ has no equivalent. Its
--predictCLI flag (alloc/core.pymain) just runs a freshSimulationRunner.run()and savesprediction_results.json; it never loads a trained model, never fetcheslatest prices to build a live state, and never emits recommended orders from a
trained model.
Evidence
alloc/core.pymain(lines 635-745):--predictsetsmode_strbut thecode path is identical to backtest except it skips saving weights. No model
load, no latest-price fetch, no
get_allocationon a live state.alloc/models/data.pyalready provides the pieces:get_multi_asset_data(tickers, client)(line 161),build_state_vector(multi_freq_data, current_allocation, tickers, n_hourly, n_daily, n_weekly)(line 255), andfetch_latest_prices(tickers, client)(line 334).alloc/models/portfolio.pyPortfolio.execute_trades(target_allocation, prices)(line 93) already does the rebalance execution with shortfallscaling and transaction costs.
alloc/models/networks.pyActorCriticNetworks.get_allocation(state)(line 488) is the public inference entry point.
get_allocation→ seed aPortfoliofrom current positions →execute_trades→ return recommended orders + post-execution value.Implementation plan
alloc/lib/rebalance.pywith arebalance_portfolio(...)function (and a small dataclass or dict result):model_path,tickers,positions(dict ticker→dollar value),client,n_hourly=5, n_daily=5, n_weekly=5,transaction_cost=0.0,initial_value(optional; derived from positions if omitted).a.
networks = ActorCriticNetworks.load_model(model_path)(TICKET-052).b.
prices = fetch_latest_prices(tickers, client).c.
multi_freq = get_multi_asset_data(tickers, client).d. Build
current_allocation(non-cash weights) frompositions+prices(value / total, cash = remainder).e.
state = build_state_vector(multi_freq, current_allocation, tickers, n_hourly, n_daily, n_weekly).f.
allocation = networks.get_allocation(state).g. Seed a
Portfolio(tickers, initial_cash=initial_value, transaction_cost=...)with shares frompositions/prices.h.
target = {t: allocation[i] for i,t in enumerate(tickers)}; target['cash'] = allocation[-1].i.
execution = portfolio.execute_trades(target, prices).recommended_allocation(ticker→weight incl. cash),recommended_orders(list of {ticker, action, shares, price, value}),portfolio_value_before,portfolio_value_after,total_transaction_costs,scale_factor.alloc/core.py: add a--rebalancemode (or a--positions+--model-pathpredict path) that callsrebalance_portfolioand logs the recommended orders, mirroring the seed'spredict output. Keep the existing
--predict(forward simulation) intact.tests/test_rebalance.py): use a fake client (patchfetch_latest_prices/get_multi_asset_dataat the module level viapatch.objecton the rebalance module's imported references, or inject astub client) and a small saved model (via TICKET-052
save_model) toassert: allocation sums to 1.0, cash >= min_cash, orders are produced,
post-execution value is finite, and transaction costs are applied.
Verification
pytest tests/test_rebalance.py -x -q— all pass.pytest tests/ -x -q— full suite green.ruff check alloc/— clean.mypy alloc/ --ignore-missing-imports— clean.Notes
~/Research/new-trader/trader/core.py(predict mode, ~lines 863-935) and
~/Research/new-trader/utils/trader_tools/multi_rebalance_helper.py(
rebalance_portfolio,positions_to_allocation) for understanding only.Nothing is copied; the implementation targets alloc's existing public API
(
get_allocation,build_state_vector,fetch_latest_prices,execute_trades).