V3.9-C deployed — stop-loss now cancels pending limit orders
V3.9-C deployed — stop-loss now cancels pending limit orders
A live incident today exposed a conflict between V3.9-B's DCA exit ladder and the stop-loss logic. When BTC dropped toward the stop-loss threshold, the bot tried to fire a market sell. Binance rejected it. The BTC was already reserved by an open limit order placed by V3.9-B. V3.9-C fixes this: stop-loss now cancels the pending limit order before placing the market sell. PR #1353 merged at 18:43 UTC, about two hours after the incident fired.
Key takeaways
- Live incident at 16:27 UTC: stop-loss market sell rejected by Binance with "insufficient balance."
- Root cause: V3.9-B places a limit sell order when a DCA position opens. That order reserves the BTC. The stop-loss path did not cancel it before placing a market sell — Binance sees no free BTC to sell.
- V3.9-C fix: cancel the pending limit order before firing the market stop-loss sell. If cancel fails (position already filled), the market sell is still attempted.
- PR #1353 merged 2026-06-30T18:43Z. 302/302 tests pass. 4 new tests added for the cancel-before-stop-loss path.
- BTC at $58,674. DCA[0] stop-loss threshold: $58,260. Gap: ~$414. Fix is live before the threshold is reached.
The incident
At 16:27 UTC, BTC dropped to $58,474. The DCA accumulator checked its stop-loss thresholds and tried to exit the largest position, bought at $68,541.
The market sell failed immediately:
2026-06-30T16:27:50Z DCA | sell failed (reason=STOP_LOSS, buy=68541.40) — fail-open: binance Account has insufficient balance for requested action.
The bot logged a fail-open and kept running, but the stop-loss did not fire. The position stayed open.
BTC was at $58,474 at incident time. The stop-loss threshold for that position is $58,260. That left a $214 gap before the next attempt would fire. Not a lot of runway, so the fix went in immediately.
Root cause
V3.9-B, deployed earlier today, changed how DCA positions are managed. When a position opens, the bot now places a limit sell order on Binance at the calculated target price. That order gets logged as sell_order_id on the position.
Binance reserves the BTC against that limit order. The exchange treats that BTC as committed and will not release it for another sell without an explicit cancel.
The stop-loss path in check_dca_exits fires a market sell when price drops through the threshold. Before V3.9-C, it did this without checking whether a limit order was already sitting on that position. It called the market sell, Binance rejected it, and the fail-open handler logged the error and moved on.
V3.9-B created the conditions for the bug. Before the DCA exit ladder, there were no limit orders on any DCA position, so the stop-loss path never had to deal with one. V3.9-B introduced them, and the stop-loss path was not updated to account for them.
The fix
The fix is in bots/dca_accumulator.py. When the stop-loss path fires and sell_order_id is set, the bot now cancels the limit order first. Then it places the market sell.
If the cancel call raises (for example, because the limit order already filled at a better price), the market sell is still attempted. The bot doesn't abort on a cancel failure. Stop-loss is treated as the override: it always tries to exit, regardless of what happened to the limit order.
The TARGET exit path is unchanged. That path was already skipped when sell_order_id is set (the limit order handles target exits). Only the STOP_LOSS path needed updating.
Four new tests cover the cases: cancel succeeds and market sell fires, cancel fails and market sell still fires, no sell_order_id set (original path unchanged), and the target exit path unaffected.
Current state
| Bot | Status | Notes |
|---|---|---|
| Krypto V3.7 grid | Bear regime, no entries | 35 trades, 35W / 0L, $3.29 realized. ADX and Fear & Greed still blocking. |
| Krypto DCA sleeve | 8 open positions | Bought at $66,288–$68,541. Stop-loss now operational. Sell targets at $67,614–$69,912. |
| BTC price | $58,674 | Stop-loss threshold for DCA[0]: $58,260. Gap: ~$414. |
V3.9-C is the third patch today. V3.9-A fixed the ESCAPE_REINIT sequence, V3.9-B added the DCA exit ladder, and V3.9-C closes the gap that V3.9-B left in the stop-loss path. The DCA sleeve is now functioning as intended: limit orders manage target exits, stop-loss overrides them when needed.
Read about the V3.9-A and V3.9-B patches deployed earlier today.