Skip to content

feat: replay the 1H Wolfe Wave specification on its own terms - #130

Draft
yanivil wants to merge 2 commits into
mainfrom
claude/current-design-patterns-nuyiap
Draft

yanivil wants to merge 2 commits into
mainfrom
claude/current-design-patterns-nuyiap

Conversation

@yanivil

@yanivil yanivil commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Context / why

An external 1H Bullish Wolfe Wave specification was put next to scan.detect_bullish_wolfe. The two share the geometry and differ on almost everything around it: hourly bars instead of daily, swing points three bars deep instead of five, a fixed 25-session window, a stop half an ATR under point 5 instead of a quarter, the point-4 high as the only target instead of the EPA, a binary exit with a time stop instead of the listing rules, and no reward:risk floor.

None of the scanner's replay evidence transfers to that trade, and scan.py's pipeline (last-bar alignment, the pivot lag, the evaluator) assumes daily bars, so bending it to the specification would test neither. This adds a separate harness that implements the specification as written and logs the seven factors of the accompanying review, so each can be judged by its buckets the way tools/backtest.py judges features.

Summary of changes

tools/backtest_wolfe_spec.py (new): the replay, with its own constants block.

  • Structures: strict three-bar swing points, consecutive swing lows 1-3-5, the highest swing highs between them as 2 and 4, the price hierarchy High(P2) > High(P4) > Low(P1) > Low(P3) > Low(P5), both lines falling with 2-4 the steeper.
  • Trade: entry at the first close back above line 1-3 after point 5 swept it, stop at the point-5 low minus 0.5 ATR(14), target the point-4 high, exit at whichever comes first (a bar touching both is a stop, gaps fill at the open), else a time exit; one position per symbol; no reward:risk filter.
  • Per trade it records the specification's logging schema plus the review's seven factors: trigger volume over the 20-bar average, RSI 14 at point 5 against point 3, the trigger bar's body over its range, the projected reward:risk, the close against a higher-timeframe EMA 50, an earlier swing low within 0.5 ATR of point 5, and SPY against its SMA 50 with the VIX.
  • The report gives the funnel from structures to trades, the headline win rate (TP1 hits over closed trades), the outcome per factor bucket and per year, and states the rules it ran.
  • Where the specification is silent it is read conservatively: the entry is never anticipated (the reclaim counts only from the bar that confirms point 5, with the literal lag kept for comparison), the reclaim must come within 25 bars, the structure must fit the window up to the entry bar, and a lower low before the reclaim makes that low the structure's point 5. The specification's rolling-max pivot sketch would also mark every bar of a flat stretch, so ties are excluded as its prose requires.
  • Runs on any yfinance interval. Yahoo serves intraday bars for the last 730 days only, so a longer --years on 1h is clamped and the report says so.

test_backtest_wolfe_spec.py (new): 19 offline tests on deterministic hourly fixtures, covering the swing rule, each geometry invariant one violation at a time, a fixture yielding exactly one trade with the specification's levels, the non-anticipated entry, every trigger-rejection reason, the exit rules including gaps and the time exit, low-R trades kept and bucketed, one position per symbol, a random-walk ceiling, RSI and ATR equal to scan's, the bucket tables, the report and JSON schema, the intraday clamp and main() through the yfinance stand-in.

.github/workflows/backtest-wolfe-spec.yml (new): runs the tool per interval (default 1h,1d, three years), tees the reports into the job summary and keeps the rows and reports as an artifact.

Docs: README layout and limitations, a [Unreleased] entry in CHANGELOG.md, a dated section on the tuning wiki page with the rules as implemented and the readings above, and rows on the testing page for the new test file and workflow.

No change to the scanner, its rules, the nightly job or any existing output.

Test steps

ruff check --select E,F,W --line-length 120 .
python -m pytest -q
python -m pytest test_backtest_wolfe_spec.py -q -s -k random_walks   # prints the noise rate

Both pass locally on the pinned Python 3.12 environment: lint clean, 183 tests (19 new), and the random-walk rate is 2.27 trades per 1,000 hourly bars against a ceiling of 4.

For real data, this branch's push starts the backtest-wolfe-spec workflow; the job summary then carries the funnel, the win rate and the factor tables for both intervals.

Doc impact

README.md, CHANGELOG.md, docs/wiki/03-Configuration-and-Tuning.md and docs/wiki/04-Testing-and-Contributing.md are updated in the same commit. The tuning page's new section is written to receive the measured results once a run exists; it currently states the rules and the readings only, and claims no figures.


🤖 Generated with Claude Code

https://claude.ai/code/session_01H6cvDsVigeuGGxgEMF7zEy


Generated by Claude Code

tools/backtest_wolfe_spec.py implements an external 1H Bullish Wolfe Wave
specification as written, separately from scan.py's detector because it
differs on the timeframe, the swing depth (3 bars), the window (25
sessions), the stop (0.5 ATR under point 5), the target (the point-4 high),
the exit (stop, target or a time exit after 12 sessions) and the absence
of a reward:risk filter.  Every trade is logged with the specification's
schema plus the seven review factors (volume ratio, RSI divergence between
points 3 and 5, candle body ratio, projected reward:risk, higher-timeframe
EMA trend, nearby support, SPY regime and VIX); the report gives the funnel
from structures to trades, the win rate (TP1 hits over closed trades) and
the outcome per factor bucket and per year.  Where the specification is
silent the tool reads it conservatively (no anticipated entry, a 25-bar
reclaim window, the structure inside the window up to the entry) and the
report states the rules it ran.  Yahoo serves hourly bars for the last 730
days only; a longer request is clamped and reported.

The backtest-wolfe-spec workflow runs it on the runner's open internet on
the intervals asked for (default 1h and 1d, three years) and keeps the rows
and reports as artifacts.  test_backtest_wolfe_spec.py covers the rules on
deterministic hourly fixtures; README, CHANGELOG and the wiki describe the
tool, the readings and where the results go.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6cvDsVigeuGGxgEMF7zEy
Run 35362213916 over the 503 current constituents: hourly bars for the last
729 days (Yahoo's intraday limit) and daily bars for the full three years.

Hourly: 6225 structures, 3443 trades, TP1 1956 of 3430 closed, a 57.0 % win
rate at +0.03 R per trade (+104.20 R).  Daily: 1051 structures, 428 trades,
TP1 229 of 420 closed, 54.5 % at +0.09 R (+38.83 R).

The win rate comes from a target nearer than the stop: 2100 of the 3443
hourly trades carried a projected reward:risk below 1.0, won 67.8 % of the
time and paid +0.02 R each, while the above-2.0 bucket won 29.9 % and paid
+0.08.  That settles the specification's own question about impulse candles
with a low initial R:R: they do win more often, and not by enough.

None of the seven review factors separates outcomes on both windows.  The
SPY regime, the VIX and the higher-timeframe EMA trend reverse sign between
hourly and daily; RSI divergence is inert on the hourly set (57.1 % against
57.0 %); nearby support is mildly negative on both; volume alone points the
same way twice and weakly, the "a feature, not a gate" verdict the volume
z-score already got.  The hourly rule fires 1.97 times per 1,000 bars
against 2.27 on synthetic noise, different generating processes but the
same order of magnitude.

No scanner rule changes.  Wiki 03 carries the tables and the reading;
CHANGELOG records the headline figures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6cvDsVigeuGGxgEMF7zEy

yanivil commented Sep 18, 2026

Copy link
Copy Markdown
Owner Author

github-advanced-security is red, and it is not this PR's failure. Standing down on it; here is the evidence.

The job never analysed the diff. It failed while creating its own agent session:

Error creating PR review request: SessionModelError: Execution failed:
CAPIError: 400 The requested model is not supported.
COPILOT_AGENT_MODEL: sweagent-capi:claude-opus-5[ReasoningEffort=medium]

That is GitHub's own code-scanning agent asking its API for a model the API rejects. It is not reachable from repository content, and the run ends before any file is read.

It is also not new. The check has failed identically on the last eight pull requests in this repository, over nine days, including every one that merged into main:

Run PR Conclusion
35362266175 #130 (this one) failure
35265663195 #128 failure
35260821453 #127 failure
35258088021 #125 failure
35257143981 #124 failure
35236119696 #123 failure
34977667092 #122 failure
34330445863 #120 failure

No fix exists to port: the failure is in a GitHub-hosted agent's model selection, outside this repository's code and workflows. I have not re-run it, because eight identical failures across unrelated diffs are stronger evidence than a ninth would be, and a re-run spends Actions minutes on a known-broken third-party agent. If you want the check green, it needs raising with GitHub Advanced Security support rather than a change here.

Everything this PR does own is green on the current head: tests passes (lint, 183 tests, coverage), and backtest-wolfe-spec completed successfully, with its reports in the job summary and the rows kept as an artifact.


Generated by Claude Code

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