USD/JPY Tokyo fix fade
t 7.52, twelve green years, and a bug that read the future. Corrected: t −1.52.
Why it failed: Look-ahead: the filter used a price from 22.5 hours after the entry. See the scorecard
Cumulative result
R per trade (net of spread + 0.5 pip). The causal version: the pre-fix filter uses only prices known at the 00:55 UTC entry.
Show the data as a table
| Year | Trades | Sum R | Mean R |
|---|---|---|---|
| 2015 | 132 | +7.2 | +0.054 |
| 2016 | 116 | −14.6 | −0.126 |
| 2017 | 151 | −0.7 | −0.005 |
| 2018 | 134 | −13.0 | −0.097 |
| 2019 | 136 | −7.4 | −0.054 |
| 2020 | 127 | +23.1 | +0.182 |
| 2021 | 147 | −5.1 | −0.035 |
| 2022 | 141 | −4.9 | −0.035 |
| 2023 | 139 | −9.4 | −0.068 |
| 2024 | 150 | −24.6 | −0.164 |
| 2025 | 125 | +4.3 | +0.035 |
| 2026 | 84 | −21.5 | −0.256 |
The claim
A well-known FX story: Japanese importers buy dollars into the 09:55 JST Tokyo fix, so if USD/JPY has risen since 08:30 JST, sell it at the fix and hold until 15:00 JST.
Our first backtest: 1,124 trades, win rate 56%, +326R, t 7.52, 12 of 12 years positive.
Source: Idea discussed publicly by FX traders; first coded and backtested by one of our own research agents
What we tested
- Condition: USD/JPY at 09:55 JST is above its price at 08:30 JST the same morning.
- Entry: short at the bid at 09:55 JST (00:55 UTC).
- Stop: 20 pips. Exit: at the ask at 15:00 JST (06:00 UTC).
- Every Tokyo morning, no day-of-month filter.
Costs and fills
- Spread from the bid/ask file plus 0.5 pip of extra friction per trade.
Data
- OANDA USD/JPY minute bid/ask
- HistData USD/JPY minute mid (second vendor)
What went wrong
The first script grouped minute bars by UTC calendar date. The 08:30 JST reference price is 23:30 UTC, which falls on the previous UTC date. Inside one UTC date, the 23:30 bar comes 22.5 hours after the 00:55 entry.
So the filter 'price rose into the fix' was really 'price will fall later today'. Keeping only the days where the dollar later fell produces a beautiful backtest. The rejected days are the mirror image: −0.377R a trade, t −17.4.
The corrected test
Using 23:30 UTC of the day before (08:30 JST on the actual morning), the same rule makes −0.042R a trade over 1,582 trades. Filtered and unfiltered days are the same (difference +0.010R, t 0.26). On a second vendor's data from 2008 it is flat (t 0.28).
Moving the entry by −60, −5, −1, +1, +5 or +60 minutes does not rescue it: every variant is flat or negative (t from −2.69 to −0.08).
Why we publish our own mistakes
This is the most common way a backtest lies: a filter that quietly uses information from after the decision. A one-line rule produced a t-statistic of 7.5. We found the bug because the lab's standard treats any simple rule with t above 5 as a bug until the clock and leak tests pass.
The 12-gate scorecard
0 passed · 4 failed · 8 not run or not reached. A gate is "not reached" when the strategy had already failed a veto: there is nothing left for it to test.
Is the backtest real?
Absolute veto. These gates look for bugs and physical limits, not for statistical evidence, so one failure ends the test.
The filter read 23:30 UTC of the same UTC date, 22.5 hours after the entry. Lag test: filtered minus rejected days +0.667R (t 15.2) with the leak, +0.010R (t 0.26) without it.
Is the edge more than luck?
G12, one pre-registered holdout, is the only statistical veto. G1 to G5 and the regime test G6 are always reported; G6 vetoes only a regime that is significantly negative. A strategy with no edge after costs never reaches G12, because there is nothing to confirm.
Corrected rule: t −1.52 on OANDA, +0.28 on HistData.
Shorting every Tokyo morning without the filter: t −2.30. The filter adds nothing (t 0.26).
Entry shifted by −60 to +60 minutes: every variant flat or negative.
Can it survive a prop-firm account?
Absolute veto, for strategies meant for funded accounts. The account rules are simulated event by event, not at the end of the day.
Group by the market's clock, never by the calendar of your file
Any rule that compares 'this morning' with 'last night' across a date boundary can leak. Test every filter at a lag of one and two days: a real effect survives, a leak disappears.
Receipts
Every number on this page comes from one of these files: the test script, its saved output, the trade list and, where the test was pre-registered, the registration and its hash lock. Download them and check our work. Numbers that also appear in the chart are recomputed from the trade list when this page is built, and the build fails if they disagree.
| File | Kind | Size | Status | sha256 |
|---|---|---|---|---|
| TOKYO_FIX_GOTOBI_USDJPY_RESEARCH.md docs/TOKYO_FIX_GOTOBI_USDJPY_RESEARCH.md | Report | 7 KB | 13 lines withheld (private strategy) | b0a8719eef96 |
| _audit_tokyo_fix_20261010.py pillar2_hunt/_audit_tokyo_fix_20261010.py | Script | 7 KB | Complete | c5b9133d679d |
| _audit_tokyo_fix_20261010.out pillar2_hunt/_audit_tokyo_fix_20261010.out | Saved output | 4 KB | Complete | 94682a18e7ea |
| _audit_tokyo_fix_clock_20261010.out pillar2_hunt/_audit_tokyo_fix_clock_20261010.out | Saved output | 1 KB | Complete | 866733132eed |
| PILLAR2_HUNT_REPORT_2026-10-10.md pillar2_hunt/PILLAR2_HUNT_REPORT_2026-10-10.md | Report | Withheld: most of the report is about the lab's private live strategy | ||
| _tokyo_fix_causal_trades.csv pillar2_hunt/_tokyo_fix_causal_trades.csv | Trade list | 42 KB | Complete | d11b3d9f972f |
Price data is not included: the vendors' licences do not allow it, so the scripts run only with your own copy of the data, and the trade lists show dates, direction, R and costs, not prices. Lines that refer to the lab's private live strategy are replaced by a marker; the receipts page explains the rules and lists the sha256 of every original file.
Related tests
Machine-learning intraday forecaster
70 features, gradient boosting, a promising IC. The signal was oil prices read five hours early.
Opening Volatility Stretch on DAX, Bund and Nasdaq
The DAX and Bund results came from a frozen pre-open quote. Nasdaq is positive but unproven.