Puts the adaptive multi-strat ETF book on the clean execution port:
- multistrat.target_weights(closes): exposes the final-day per-instrument weights
(L*tw*volnorm_scale) that book_series applies but only collapses into a return.
Refactored _volnorm via a shared _volnorm_scale so book_series stays byte-identical.
Tested: sum(w*R[last]) reconstructs book_series's last booked return exactly.
- ExecutionService.rebalance_weights(weights, prices): a direct pre-computed-weights
entry beside rebalance(book), sharing one _plan engine (gates + fractional sizing).
Caller owns data<->broker symbol mapping.
- AlpacaBroker crypto-aware: a slash symbol (BTC/USD) -> time_in_force gtc; equities
stay day. So the book's BTC-USD leg trades on Alpaca crypto alongside the 5 ETFs.
- CLI fxhnt execute-multistrat (maps BTC-USD -> BTC/USD); the alpaca-rebalancer
CronJob now runs it (suspended until paper keys).
Full suite green (1832); +5 tests. Alpaca-crypto position-symbol form validated on
first paper run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Foundation for a 2nd, uncorrelated execution venue alongside the Bybit crypto book:
- AlpacaBroker (httpx REST, Broker port): account_state + place_order, FRACTIONAL
market+day orders, is_paper from base_url, supports_fractional=True. httpx test
seam (MockTransport) — no network.
- ExecutionService fractional-aware: sizes float shares when broker.supports_fractional
(Alpaca) — precise weights at small capital — else whole shares (IBKR, unchanged).
- AlpacaSettings (paper base_url default; live gated by allow_live). CLI
.
- Suspended CronJob + credentials scaffold (arm after paper keys, like the Bybit
testnet leg). Runs the survivor book end-to-end.
The multi-strat ETF book on Alpaca is a documented follow-up (its position logic
isn't on the clean port yet). Full suite green (1827); 6 new tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>