Skip to content

Add TradingView indicator + pre-registered FVG design/test study - #1

Draft
mannankhanduja-max wants to merge 16 commits into
mainfrom
claude/new-session-vcw9vd
Draft

mannankhanduja-max wants to merge 16 commits into
mainfrom
claude/new-session-vcw9vd

Conversation

@mannankhanduja-max

@mannankhanduja-max mannankhanduja-max commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

What this adds

1. tradingview/breakout_retrace.pine — a Pine Script v6 indicator that ports the §5a breakout/retracement rule (fxrisk/strategies/breakout_retrace.py and the exit walk in fxrisk/risk/barriers.py) to a live TradingView chart, and plots a BUY/SELL label on the exact bar a trade is confirmed. Every gate (trend, breakout, retrace, confirm, bracket) is ported parameter for parameter, including the pessimistic same-bar tie-break and close-only breakeven arming. tradingview/README.md documents usage and its one simplification versus the vectorised research script.

2. A pre-registered FVG design/test study (§5b in the README), answering §5a's own "obvious next step... not done" — holding out the two fitted-looking free parameters (retracement band, wait) that §5a never tested out-of-sample:

  • fxrisk/strategies/fvg_retrace.py — §5a's gate plus one more AND-condition: the retracement must touch a fair value gap (fxrisk/strategies/smc.py) that was already knowable before the touch.
  • fetch_fvg_raw.py / fxrisk/data/fvg_raw.py — a yearly-chunked Dukascopy XAU/USD 1-minute bid+ask fetcher and reader, with a hard-coded, non-overlapping design (2015–2022) / test (2022–now) split.
  • fvg_config/README.md + fxrisk/research/fvg_subsets.py — optional news-window and stress-window subset breakdowns; neither config file is invented or shipped, since a fabricated calendar would quietly bias the subset it defines.
  • run_fvg_design.py (make run / make run-demo) — the free-to-iterate design-period runner. Writes results/fvg_design_trades.csv, docs/figures/fvg_design.png, RESULTS.md.
  • PREREGISTRATION.md — committed as an unfilled template (deliberately not completed by me — criteria written after seeing a number aren't criteria). It has its own power-arithmetic section and an explicit prompt to address how 2022+ was already partially seen by this repo's earlier intraday work.
  • run_fvg_test.py (make run-test) — the one-shot held-out runner. Mechanically refuses to run until PREREGISTRATION.md no longer contains <<SIGN HERE>> and is committed with no uncommitted diff, and writes a results/fvg_test_DONE.txt marker so it can only run once without --force.
  • FETCH_FVG_DESIGN.md — exact commands for the real download, since this sandbox cannot reach Dukascopy (confirmed 403 policy block on freeserv.dukascopy.com).

What's deliberately left for you to do

  1. Run the real download. python fetch_fvg_raw.py --side both (see FETCH_FVG_DESIGN.md) — I cannot reach Dukascopy from this sandbox.
  2. Run make run on the real data once it's downloaded.
  3. Fill in and sign PREREGISTRATION.md — the success criteria, how you're treating the fact that 2022+ was already seen by this repo's earlier intraday work, and an optional primary variant, are all yours to write, not mine.
  4. Run make run-test once, after committing the signed prereg.

What I verified

  • run_fvg_design.py --demo: runs end-to-end on synthetic bid/ask bars (clearly labelled DEMO_SIMULATED_ throughout) — produces the trades CSV, the figure, and RESULTS.md, and honestly reports a null result (expected: a random walk has no edge by construction).
  • run_fvg_test.py's gates: confirmed it refuses with the correct message when PREREGISTRATION.md still has <<SIGN HERE>>, and again when the prereg has an uncommitted diff — without touching any test-period data in either case.
  • python -m pytest tests/ -q: 339 passed (including 12 + 16 + 8 new tests for the FVG rule, raw-data loader, and subset loaders), 7 pre-existing failures in tests/test_spread.py unrelated to this change (missing cached intraday data, needs fetch_intraday.py + internet).
  • Pine script: not run through a compiler (none available here) — see PR history above for the original caveat, unchanged by this update.

🤖 Generated with Claude Code

https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS

tradingview/breakout_retrace.pine ports fxrisk/strategies/breakout_retrace.py
and the exit walk in fxrisk/risk/barriers.py to Pine Script v6: same
gates (VWAP/EMA trend filter, close-based breakout, retracement band,
confirmation close, stop floor, breakeven arming, pessimistic same-bar
tie-break), parameter for parameter. It plots a BUY/SELL label on the
bar a trade is confirmed (gate 4), optional TP/SL/BE/T-O exit labels,
bracket lines, and two alertcondition()s so a TradingView alert can be
set on a confirmed entry.

One difference from the vectorised research script is unavoidable on a
forward-running chart: at most one setup is tracked at a time, rather
than find_setups() being able to examine a new breakout on any bar and
walk_explicit() dropping overlapping entries after the fact. Documented
in the script's header and in tradingview/README.md, along with the
disclaimer this repo's other strategy files carry - the Python backtest
on this exact rule found no edge.

Not run through a Pine compiler (none is available in this environment);
reviewed line by line for syntax instead. tradingview/README.md says so.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS

Copy link
Copy Markdown
Owner Author

CI is red on pytest (py3.10/3.11/3.12) — the 7 tests/test_spread.py tests that need a cached data/intraday/EURUSD_5m.csv fixture (FileNotFoundError: No cached intraday data for EURUSD). That's not this PR's: main's last three runs (#59, #60, #61, none touching tradingview/ or intraday data) fail on the identical step for the identical reason — there's no committed intraday fixture for CI to read, and fetch_intraday.py needs internet, which CI doesn't have. I confirmed locally too: stashing this PR's diff reproduces the same 7 failures on main as-is.

No fix for it exists yet, and this PR doesn't touch tests/, fxrisk/data/intraday.py, or anything intraday-data-related, so I haven't tried to fix it here — it needs either a committed fixture or a skip-without-cache guard in test_spread.py, which is a decision for that test file, not for a TradingView indicator PR. The no network outside fetch_data.py job passes, and the 247 other tests pass on all three Python versions.


Generated by Claude Code

claude added 8 commits October 4, 2026 03:01
CW10002: ta.cum(nz(volume)) was called inside a conditional expression
(barstate.islast and ...), which Pine flags because the function's
result depends on history and so must execute every bar, not only on
the ones where the surrounding 'and' doesn't short-circuit it away.
Caught by TradingView's own compiler when the file was first pasted
in; moved the call to its own unconditional line per the compiler's
suggested fix.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
A user reported no BUY/SELL (and no BO/armed markers) anywhere in
history on a gold futures 1h chart, even with the trend filter off -
two independent diagnostics ruling out the obvious suspects without
localizing the actual blocker.

Hoists the raw gate-1/2 breakout check (ready/breakoutUp/breakoutDn)
out of the state machine so it runs unconditionally on every bar, adds
unconditional plotchar triangles for it, and exposes hiPrev/loPrev/
sigmaCausal/state/cumulative-volume in the Data Window behind a new
'showDebug' toggle (default on). This decouples 'does a 20-bar
breakout even happen' from the state machine entirely, so the next
report pinpoints whether the bug is in gate 2's inputs or further
down the chain.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
fxrisk/strategies/fvg_retrace.py is breakout_retrace.py with one gate
added: the retracement must also touch a fair value gap that was
already known before the touching bar (smc.fair_value_gaps / in_zone),
not merely fall inside the depth band. This is the same combination
mtf.setups_30m already uses on its 30m leg, built here as its own
single-timeframe rule meant for 1-minute bars, per the planned
design-period / test-period study.

Causality is end-to-end: a future price move after the entry bar
cannot change it, and a zone only known as of the touching bar itself
(not strictly before) is refused, mirroring the guard tests/test_smc.py
already pins for the zone functions in isolation.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
fetch_fvg_raw.py downloads from Dukascopy one calendar year at a time
into data/raw/XAUUSD_1m_{bid,ask}_{year}.csv - resumable (an existing
year's file is skipped, not re-fetched) since an 11-year, two-sided,
1-minute pull is a long-running download against a free endpoint that
deserves patience, not retries. This step needs internet and this
session's egress policy blocks freeserv.dukascopy.com outright (403,
confirmed directly and documented as a policy denial, not a transient
failure) - fetching has to happen on a machine with ordinary internet
access, same as fetch_intraday.py already is for the shorter studies.

fxrisk/data/fvg_raw.py reads what lands: concatenates the yearly files
for one side over a date range, clipped and deduplicated, and raises a
clear FileNotFoundError naming the exact command to run for any
missing year rather than silently loading a shorter window. Also
defines the one split this whole study exists to respect - design
2015-01-01 to 2022-01-01, test 2022-01-01 onward - as the two named
constants everything else reads rather than a date repeated in
several places.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
fxrisk/research/fvg_subsets.py loads fvg_config/news_calendar.csv and
fvg_config/stress_windows.csv if present, returning None (not an
empty frame) when a file is absent, so callers can tell 'not
configured' apart from 'configured, zero events found'. Neither file
exists in this repo - fvg_config/README.md documents the exact format
and says plainly that a news calendar is a claim about real events
and should be sourced, never fabricated to fill the slot.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
Same half-spread-plus-commission semantics as fxrisk.risk.spread.real_cost_bp,
but reading bid/ask frames directly instead of going through
fxrisk.data.intraday's cache, which this study's data does not live in.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
…ign.py, run_fvg_test.py)

Completes the design-period runner, the one-shot held-out test runner,
the pre-registration template, the Makefile targets, and the manual
fetch instructions for the full pre-registered design/test split
requested for the FVG study. run_fvg_design.py's --demo mode is
verified end-to-end (trades CSV, figure, RESULTS.md); run_fvg_test.py's
gates (unsigned prereg, uncommitted prereg, one-shot marker) are
verified to refuse correctly in the current, deliberately unsigned
state.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
@mannankhanduja-max mannankhanduja-max changed the title Add a TradingView indicator for the breakout/retracement rule Add TradingView indicator + pre-registered FVG design/test study Oct 5, 2026
It downloads Dukascopy bid/ask bars, same as fetch_intraday.py, and
was missing from the allowed-network-entry-points list, which failed
the "no network outside fetch_data.py" check on the FVG study PR.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS

Copy link
Copy Markdown
Owner Author

pytest (py3.10) (and the matching py3.11/py3.12 jobs) are failing on 7 tests in tests/test_spread.py, all FileNotFoundError: No cached intraday data for EURUSD/USDJPY at data/intraday/... — they need fetch_intraday.py run with network access, which CI doesn't have.

This isn't caused by this PR: the same 7 failures reproduce on main at its current head (d87124f3, run #61, conclusion failure), and locally with this branch's changes stashed. No fix for it exists yet on main to port in. I've re-run the failed jobs once in case it clears, but I don't expect it to since it reproduces deterministically (missing cache files, not a flake).

🤖 Generated with Claude Code

https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS


Generated by Claude Code

claude added 6 commits October 5, 2026 16:10
… option

The prior debug layer relied on spotting tiny triangles across the whole
chart, which is exactly the kind of check that's easy to get wrong by
hand. Added a single label at the latest bar with running counts (bars
processed, bars ready, up/down breakouts seen) so "did a breakout ever
fire" is one number to read instead of a visual scan.

Also added a "Stop floor method" input (EWMA sigma / ATR), matching the
stop_mode="atr" convention already used in fxrisk/strategies/mtf.py, as
a selectable alternative to the EWMA-sigma floor.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
The breakout count confirmed gate 1/2 fires constantly (1188 breakouts
over 10,391 bars on the user's chart), so a report of "no BUY/SELL
anywhere" needed a count further down the funnel to localize it: is
gate 3 (retrace) or gate 4 (confirm) where it's dying, or are entries
actually happening but off-screen on the zoomed-in view? The debug
label now also reports armedCount (retrace qualified) and
entriesCount (confirmed BUY+SELL), moved to draw after the state
machine runs so it reflects the current bar too.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
… to the debug label

Once a configuration produces enough entries to be worth watching play
out (e.g. widening maxFraction took this from 1 to 216 confirmed
entries on a user's gold chart), the next question is win quality, not
signal count. The debug label now tallies how each closed trade
exited and a win rate (TP+BE over closed trades) - the same "barrier
win rate" framing the Python backtest uses, gross of cost, not a
claim about net profitability.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
… label

A label.new(bar_index, low, ...) sits on top of the latest candles and
drifts as the chart scrolls, overlapping price action. Switched to a
table.new(position.middle_left, ...) pinned to the chart pane's left
edge - fixed screen position, always current (updates every bar
instead of only at barstate.islast), never covers a candle.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
…trace-band widening

SetupConfig has supported max_fraction since this strategy was
written; breakout_test.py just never exposed it on the CLI, hardcoding
config.RETRACE_MAX_FRACTION (1.0) instead. Needed to actually test, in
Python, the same retrace-band widening (1.0 -> 1.5) that unlocked
entries on the TradingView side of this rule - without it there was no
way to point the backtest at that configuration at all.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015QrXJAsc5JGieSpZvyUUXS
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.

2 participants