The finding
Split out of #442. keel's live exits ride ONE native Coinbase trigger-bracket placed at entry (keel/execution/executor.py::_bracket_order_configuration → trigger_bracket_gtc, built as a raw dict against the pre-port CoinbaseClient). Moving a stop means cancel-and-replace of that bracket (_roll_stop), and a partial exit means resizing it.
The broker port has no bracket/OCO order kind at all: OrderSpec is MarketIOCByQuote / MarketIOCByBase / LimitGTC / StopLimitGTC (packages/keel-broker-coinbase/keel_broker_coinbase/translate.py::to_order_configuration, assert_never on anything else). The bracket reaches the venue only because the executor bypasses the port with a raw configuration dict — so the three live exit primitives (trail_stop_atr, roll_to_break_even, scale_out) have no port-clean path to production. #442 wired the exit POLICY (ratchet-only ATR trailing, break-even roll) on the sim/backtest engines only and left the live primitives deliberately unwired pending this issue.
scale_out additionally carries its own prerequisites, pinned by the tripwire test tests/execution/test_executor.py::test_scale_out_has_no_production_caller: before it may be wired it must (1) cancel/resize the resting bracket that commits the FULL position (a partial SELL against it is rejected, or fills and leaves an oversized bracket able to sell more than is held), and (2) record a trade_outcomes row for the partial exit — otherwise rail 16 counts a net winner as a loss.
Why it matters
Reading executor.py in isolation still overstates what keel does live: the module implements and unit-tests stop management that nothing in the agent cycle calls. The honest docstring now says so, but the honest FIX is a port that can express the orders a managed position needs.
Scope
- Add a bracket/OCO
OrderSpec kind to keel-broker-api + the Coinbase adapter's to_order_configuration translation (and the other adapters' explicit refusal, where they cannot support it).
- A live per-cycle stop-management step in
agent.run_once that calls trail_stop_atr/roll_to_break_even per rule family — the per-family params (trail_atr_mult, be_roll_rr on pullback_continuation/rsi_meanrev) already exist and are wired through the sim/backtest engines; turtle stays on its Donchian exit by choice.
scale_out: bracket resize + trade_outcomes recording, then remove the tripwire test.
The finding
Split out of #442. keel's live exits ride ONE native Coinbase trigger-bracket placed at entry (
keel/execution/executor.py::_bracket_order_configuration→trigger_bracket_gtc, built as a raw dict against the pre-portCoinbaseClient). Moving a stop means cancel-and-replace of that bracket (_roll_stop), and a partial exit means resizing it.The broker port has no bracket/OCO order kind at all:
OrderSpecisMarketIOCByQuote/MarketIOCByBase/LimitGTC/StopLimitGTC(packages/keel-broker-coinbase/keel_broker_coinbase/translate.py::to_order_configuration,assert_neveron anything else). The bracket reaches the venue only because the executor bypasses the port with a raw configuration dict — so the three live exit primitives (trail_stop_atr,roll_to_break_even,scale_out) have no port-clean path to production. #442 wired the exit POLICY (ratchet-only ATR trailing, break-even roll) on the sim/backtest engines only and left the live primitives deliberately unwired pending this issue.scale_outadditionally carries its own prerequisites, pinned by the tripwire testtests/execution/test_executor.py::test_scale_out_has_no_production_caller: before it may be wired it must (1) cancel/resize the resting bracket that commits the FULL position (a partial SELL against it is rejected, or fills and leaves an oversized bracket able to sell more than is held), and (2) record atrade_outcomesrow for the partial exit — otherwise rail 16 counts a net winner as a loss.Why it matters
Reading
executor.pyin isolation still overstates what keel does live: the module implements and unit-tests stop management that nothing in the agent cycle calls. The honest docstring now says so, but the honest FIX is a port that can express the orders a managed position needs.Scope
OrderSpeckind tokeel-broker-api+ the Coinbase adapter'sto_order_configurationtranslation (and the other adapters' explicit refusal, where they cannot support it).agent.run_oncethat callstrail_stop_atr/roll_to_break_evenper rule family — the per-family params (trail_atr_mult,be_roll_rronpullback_continuation/rsi_meanrev) already exist and are wired through the sim/backtest engines; turtle stays on its Donchian exit by choice.scale_out: bracket resize +trade_outcomesrecording, then remove the tripwire test.