fix(turtle): drop the daily bar only when it is really forming - #155
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 lastONE_DAYbar whenever anONE_HOURkey was present. That is the right guard for the account simulator:
sim.portfolio_simiterateshourly 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) passesONE_HOURtoo, anddata.market_feedpersists onlyCLOSED candles, so its newest daily bar has already closed. The presence of
ONE_HOURwasstanding 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 on2026-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_simslices its daily series withbisect_right(daily_ts, t)against the current hourly bart, so the last daily bar alwayscontains 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-26to the newest closedday,
2026-07-27.Tests
Three new tests in
TestCompletedDailyBarIsUsedInTheLiveAgentPath, written first and watched fail:None)False)No behaviour change for the edge backtester, which passes no
ONE_HOURkey at all.🤖 Generated with Claude Code