Skip to content

BUG: Preserve stop-loss value in stats._trades when SL is gapped through#1369

Merged
kernc merged 3 commits into
kernc:masterfrom
nyxst4ck:fix/sl-value-gapped-through
Jul 20, 2026
Merged

BUG: Preserve stop-loss value in stats._trades when SL is gapped through#1369
kernc merged 3 commits into
kernc:masterfrom
nyxst4ck:fix/sl-value-gapped-through

Conversation

@nyxst4ck

Copy link
Copy Markdown
Contributor

Problem

When a trade is closed by its stop-loss, the SL value is sometimes missing (NaN) in stats._trades["SL"], even though an SL was explicitly set. This happens specifically when the price gaps through the stop: the bar opens beyond the stop price, so the fill price is worse than the stop.

This is the still-unfixed part of #1288 reported in #1340.

Root cause

When a stop order is hit, the stop becomes a market order and its stop_price is cleared:

order._replace(stop_price=None)

Since the trade reads its SL from trade._sl_order.stop, clearing it drops the value from the trades data frame. The previous fix (#1288) restored it, but only when the fill price equalled the stop exactly:

if price == stop_price:
    trade._sl_order._replace(stop_price=stop_price)

On a gap-through, the order fills at the (worse) open price, so price != stop_price and the SL is never restored.

Fix

Restore the recorded SL whenever the executed order is the trade's own stop-loss order, regardless of the fill price. The TP/trade.close() paths are unaffected (those orders carry no stop price).

Test

Added test_sl_value_in_trades_df_when_gapped_through, which enters a long position whose SL (99.5) is gapped through on the next bar's open (99.19). The exit price is below the stop, but the SL value must still be recorded.

  • Red on master: AssertionError: None != 99.5
  • Green with this change.

Existing SL/TP regression tests (test_sl_tp_values_in_trades_df, test_sl_always_before_tp, test_stop_entry_and_tp_in_same_bar) still pass.

Fixes #1340

When a stop-loss order triggers, its stop price is cleared as the stop
becomes a market order. The value was only restored on stats._trades["SL"]
when the fill price equalled the stop price exactly. If the bar gapped past
the stop (fill price worse than the stop), the SL column was left empty (NaN).

Restore the recorded SL whenever the executed order is the trade's own
stop-loss order, regardless of the fill price. Adds a regression test.

Fixes kernc#1340
@nyxst4ck
nyxst4ck marked this pull request as ready for review July 14, 2026 02:09
@nyxst4ck

Copy link
Copy Markdown
Contributor Author

Marked ready for review. I do not see any checks reported on this branch yet.

Comment thread backtesting/test/_test.py Outdated
Make the regression explicitly verify that a stop-loss gapped through at the open still fills at 99.19 while retaining the original 99.5 SL in trade statistics.

Co-Authored-By: claude-flow <ruv@ruv.net>
@kernc

kernc commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Many thanks! If you find any other similarly neat fixes, they are welcome!

@kernc
kernc merged commit b0f55cf into kernc:master Jul 20, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stop Loss value being (still sometimes) erased when reached

2 participants