Skip to content

fix(turtle): drop the daily bar only when it is really forming - #155

Merged
eaitbrahim merged 1 commit into
mainfrom
fix/turtle-forming-bar-guard
Jul 28, 2026
Merged

fix(turtle): drop the daily bar only when it is really forming#155
eaitbrahim merged 1 commit into
mainfrom
fix/turtle-forming-bar-guard

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

The live agent was deciding on a daily bar up to 48h old — a full day of lag on every Turtle
breakout entry and channel exit.

TurtleBreakout.detect()/exit_signal() dropped the last ONE_DAY bar whenever an ONE_HOUR
key was present. That is the right guard for the account simulator: sim.portfolio_sim iterates
hourly and hands the rule a daily series whose last bar is the current, still-forming day, whose
stored OHLC is the completed day — consuming it intraday is lookahead.

But the live agent (agent.run_once) passes ONE_HOUR too, and data.market_feed persists only
CLOSED candles, so its newest daily bar has already closed. The presence of ONE_HOUR was
standing in for "this is the sim", and in the live path it silently threw away a completed day.

Observed on the paper-forward deployment on 2026-07-28: the newest stored daily bar was
2026-07-27, and the rule was deciding on 2026-07-26.

The fix

Decide by where the hourly series sits, not by whether it exists: the newest daily bar is still
forming unless the newest hourly bar opens at or after that day's close.

This leaves the sim's behaviour provably unchanged. portfolio_sim slices its daily series with
bisect_right(daily_ts, t) against the current hourly bar t, so the last daily bar always
contains that hourly bar — the new condition is never true there. In the live agent it is true
from the first full hour of the next UTC day.

Against the live paper database this moves the decision bar from 2026-07-26 to the newest closed
day, 2026-07-27.

Tests

Three new tests in TestCompletedDailyBarIsUsedInTheLiveAgentPath, written first and watched fail:

  • a breakout on the newest closed daily bar fires (was None)
  • an exit on the newest closed daily bar fires (was False)
  • the account-sim shape still drops its forming bar — the regression guard for the sim

No behaviour change for the edge backtester, which passes no ONE_HOUR key at all.

🤖 Generated with Claude Code

The forming-bar guard keyed off the mere PRESENCE of an ONE_HOUR key. That is
the account sim's shape (portfolio_sim hands the rule a hourly window inside the
current, still-forming day), but the live agent passes ONE_HOUR too -- and
market_feed persists only CLOSED candles, so its newest daily bar has already
closed. The agent was therefore discarding a completed day and deciding on a bar
up to 48h old: a full day of lag on every breakout entry and channel exit.

Decide by where the hourly series sits instead of whether it exists: the newest
daily bar is forming unless the newest hourly bar opens at or after that day's
close. In the sim that is never true -- it slices daily with
bisect_right(daily_ts, t), so its hourly bar is by construction inside the last
daily bar -- so the sim's guard is provably unchanged.

Against the live paper DB this moves the decision bar from 2026-07-26 to the
newest closed day, 2026-07-27.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@eaitbrahim
eaitbrahim merged commit d837abd into main Jul 28, 2026
1 check passed
@eaitbrahim
eaitbrahim deleted the fix/turtle-forming-bar-guard branch July 28, 2026 23:56
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.

1 participant