The IGLN gold-sleeve 'priced but no order' bug. scaled_weights sizes orders to
the paper envelope (envelope*within_weight), but _plan's entry-floor/hysteresis
threshold used entry_floor*nlv (the full $1M account NLV) — so the effective
floor was ~entry_floor*(nlv/envelope) of the envelope (~5%), silently dropping
every sleeve below it. A 3% gold sleeve at a $100k envelope on a $1M account
skipped. FIX: rebalance_weights takes sizing_capital (the envelope); the floor
is entry_floor*min(sizing_capital,nlv). Sizing + recording unchanged. Regression
test: a 3% sleeve survives WITH the envelope basis, drops without it. 2005 green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
execute-multistrat --venue ucits was unrunnable and mis-sized:
- place_order hardcoded Stock(symbol, SMART, USD) so LSE-listed UCITS ETFs
(CSPX/IBTM/SGLN/ICOM/DBMF) failed IBKR resolution (Error 200);
- apply_ucits_map reused the US ticker's Yahoo price for the UCITS ticker, so
shares = weight*envelope/price was wrong;
- any single unmapped sleeve refused the whole (PRIIPs-legal) rebalance.
Fix:
- Order carries optional exchange/currency/sec_id_type/sec_id (US path keeps
SMART/USD defaults, byte-unchanged). IbkrBroker resolves UCITS orders via
Contract(secIdType=ISIN, secId, currency=USD) + qualifyContracts; an
unresolved contract logs loudly and is SKIPPED (no crash, no wrong order).
- IbkrBroker.market_price fetches the REAL UCITS USD price via delayed market
data (reqMarketDataType(3) + reqMktData snapshot); the UCITS route sizes from
it, not the US Yahoo price. Modeled US weights unchanged.
- route_ucits routes sleeves that map+resolve+price and loudly logs+skips the
rest; survivors keep their own weight (book NOT rescaled), skipped $ reported.
- UcitsSettings.map now carries verified ISINs (CSPX IE00B5BMR087, IBTM
IE00B1FZS798, SGLN IE00B4ND3602, ICOM IE00BDFL4P12) and DBMF is mapped to the
real iMGP DBi Managed Futures UCITS ETF (LU2951555585, USD line) with a
liquidity caveat comment.
TDD mocks the IB client (no live broker). Full suite: 1986 passed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CRITICAL: ib_async Order.lmtPrice defaults to the IBAPI sentinel UNSET_DOUBLE
(1.79e308, truthy), which every MarketOrder carries — capture_fills treated it
as a real intended price and fabricated ~-10000 bps slippage on EVERY real market
fill. Now treat None-or-UNSET_DOUBLE as "no intended price" -> honest 0.0.
Minor 1: wrap the capture migration in its own try/except so a broken capture
migration can never block a real rebalance (falls back to no capture).
Minor 2: tests exercising capture_fills against a real MarketOrder sentinel and a
raising account_repo/broker driven all the way through plan_and_record.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>