Tested by BacktestingMax
Fibonacci retracement 61.8% strategy backtest
Does trading the 61.8% Fibonacci retracement make money?
No, not in our test. A Fibonacci retracement measures how far price moves back after a rise or a fall, as a percentage of that move. After every rise of at least 3 ATR (3 times the size of an average candle), we placed a buy order at the 61.8% level, where price has fallen back 61.8% of the rise. After every fall of that size, we placed a sell order at the 61.8% level of the fall. The stop-loss was at the 78.6% level and the take-profit at the end of the move. We ran 24 backtests from 2014 to 2025: 8 markets (EUR/USD, GBP/USD, USD/JPY, AUD/USD, gold, the S&P 500, the Nasdaq 100 and the DAX), each on 1-hour, 4-hour and daily charts. Before trading costs, the trades broke even: together they made almost exactly zero. They reached the take-profit about as often as they would if price were as likely to go up as down. After the trading costs we charged, only 2 of the 24 tests made money and had enough trades to judge (at least 100): GBP/USD on 4-hour charts and the Nasdaq 100 on daily charts.
24 backtests 2014–2025 Trading costs included Tested 12 October 2026
Where it worked 24 backtests- Made money
- 2 of 24 tests, using the 61.8% entry and 78.6% stop-loss
- Made money in both periods
- 1 2014–2021 and again 2022–2025
- Best backtest
- +161% GBP/USD, 4-hour chart: account growth 2014–2025
- Stop-loss at the start of the move (100% level)
- 1 tests made money in both periods, compared with 1 using the 61.8% entry and 78.6% stop-loss
Made money in both periods
- GBP/USD, 4-hour
Lost money on every market
- 1-hour charts
The results
Results on every market
Each box shows one backtest of the Fibonacci retracement using the 61.8% entry and 78.6% stop-loss, from 2014 to 2025, after trading costs: the % result, and a small chart of the account balance. The solid line is the account balance and the dashed line is the starting balance. Green results made money; red results lost money. Under each result: whether it made money in both 2014–2021 and 2022–2025, or passed all four of our checks (see "How a test passes" further down).
| Market | 1-hour | 4-hour | daily |
|---|---|---|---|
| EUR/USD | −77% Lost money | −33% Lost money | −5% Too few trades |
| GBP/USD | −64% Lost money | +161% Made money in both periods | +15% Too few trades |
| USD/JPY | −47% Lost money | −43% Lost money | +21% Too few trades |
| AUD/USD | −85% Lost money | −24% Lost money | +7% Too few trades |
| Gold | −82% Lost money. Account down 90% by May 2023 | −13% Lost money | −8% Too few trades |
| S&P 500 | −90% Lost money. Account down 90% by Nov 2024 | −40% Lost money | −32% Lost money |
| Nasdaq 100 | −88% Lost money. Account down 90% by Jan 2023 | −49% Lost money | +7% Made money overall, lost in one period |
| DAX | −82% Lost money | −40% Lost money | −22% Lost money |
All the numbers, test by test
| Market | Chart | Trades | Win rate | Profit factor | Result | Max drawdown | 2014–2021 | 2022–2025 | Monte Carlo drawdown | Trading costs |
|---|---|---|---|---|---|---|---|---|---|---|
| EUR/USD | 1-hour | 2,667 | 21.3% | 0.95 | −76.5% | −86.1% | −23.3% | −69.4% | −90.9% | $5,963 |
| EUR/USD | 4-hour | 663 | 20.8% | 0.93 | −32.7% | −49.3% | −6.6% | −27.9% | −63.7% | $899 |
| EUR/USD | daily | 92 | 20.7% | 0.93 | −5.1% | −13.4% | +2.8% | −7.6% | −25.1% | $52 |
| GBP/USD | 1-hour | 2,676 | 21.8% | 0.93 | −64.1% | −79.8% | −65.6% | +4.4% | −88.5% | $4,217 |
| GBP/USD | 4-hour | 640 | 25.3% | 1.20 | +160.7% | −22.5% | +58.5% | +64.5% | −38.0% | $1,842 |
| GBP/USD | daily | 97 | 24.7% | 1.17 | +14.8% | −19.0% | +28.5% | −10.7% | −20.4% | $69 |
| USD/JPY | 1-hour | 2,488 | 21.9% | 0.97 | −46.5% | −72.8% | −51.5% | +10.4% | −85.0% | $5,346 |
| USD/JPY | 4-hour | 610 | 20% | 0.88 | −42.7% | −51.7% | −37.9% | −7.7% | −64.9% | $692 |
| USD/JPY | daily | 79 | 27.8% | 1.36 | +21.2% | −10.0% | +8.4% | +11.8% | −16.9% | $44 |
| AUD/USD | 1-hour | 2,616 | 21.1% | 0.90 | −84.9% | −89.3% | −64.8% | −57.0% | −93.6% | $4,771 |
| AUD/USD | 4-hour | 625 | 21.3% | 0.95 | −24.1% | −43.3% | +17.2% | −35.3% | −60.1% | $1,384 |
| AUD/USD | daily | 93 | 23.7% | 1.11 | +7.4% | −16.9% | +9.4% | −1.8% | −22.2% | $71 |
| Gold | 1-hour | 2,501 | 21.4% | 0.88 | −81.9% | −92.8% | −82.4% | +2.7% | −91.8% | $4,897 |
| Gold | 4-hour | 617 | 21.9% | 0.97 | −12.5% | −47.8% | −8.7% | −4.1% | −54.8% | $1,465 |
| Gold | daily | 88 | 20.5% | 0.88 | −7.6% | −12.9% | −1.2% | −6.5% | −24.6% | $59 |
| S&P 500 | 1-hour | 2,943 | 20.5% | 0.92 | −90.0% | −92.3% | −80.1% | −49.8% | −95.7% | $8,979 |
| S&P 500 | 4-hour | 760 | 20.7% | 0.93 | −39.9% | −51.9% | −15.3% | −29.1% | −66.1% | $1,513 |
| S&P 500 | daily | 117 | 14.5% | 0.60 | −32.4% | −34.6% | −28.4% | −5.5% | −41.5% | $81 |
| Nasdaq 100 | 1-hour | 3,027 | 20.6% | 0.86 | −88.0% | −92.8% | −86.9% | −8.9% | −94.5% | $6,633 |
| Nasdaq 100 | 4-hour | 756 | 20.1% | 0.88 | −48.8% | −56.2% | −28.1% | −28.7% | −69.6% | $1,337 |
| Nasdaq 100 | daily | 110 | 23.6% | 1.08 | +6.6% | −16.2% | +16.3% | −8.4% | −23.0% | $101 |
| DAX | 1-hour | 2,955 | 20.1% | 0.95 | −81.6% | −90.5% | −69.8% | −38.8% | −92.9% | $4,812 |
| DAX | 4-hour | 783 | 20.4% | 0.90 | −40.0% | −54.5% | −41.6% | +2.9% | −65.6% | $446 |
| DAX | daily | 109 | 16.5% | 0.70 | −21.7% | −25.6% | −23.3% | +2.1% | −32.4% | $29 |
Profit factor is the money won divided by the money lost. Above 1 means the test made money. Max drawdown is the biggest fall from the highest balance. 2014–2021 and 2022–2025 show the result in each period on its own. Monte Carlo drawdown: we shuffled the trades into a random order 1,000 times; in 95% of those runs, the worst drawdown was this number or less. Result is the change in the account, with the risk of each trade set to 1% of the account at that time.
The account balance
The best test and the middle test
What we found
What the 24 backtests show
Across all 24 tests, the trades won about as often as they would if price moved at random. A leg is the move that the Fibonacci levels are drawn on, from the 100% level to the 0% level. With the entry at 61.8%, the stop-loss at 78.6% is 16.8% of the leg away, and the take-profit at 0% is 61.8% of the leg away. If price were as likely to go up as down, it would reach the take-profit first 16.8 ÷ (16.8 + 61.8) = 21.4% of the time. In our tests, 21.1% of the 28,112 trades won. We also ran the same tests with no trading costs. There, a winning trade made 3.63R on average and a losing trade lost 0.97R, where R is the money a trade risks (1% of the account, a little less after the trade size is rounded down). So the average trade lost 0.001R, almost exactly zero: before costs, the 61.8% level gave no advantage.
Before costs, other entry levels and a stop-loss further away did no better. We tried three changes: entering at the 50% level, entering at the 38.2% level, and moving the stop-loss to the start of the leg (the 100% level). Each change made the trades win more often, but each win paid less compared with the money risked. In every version, the share of trades that won (the win rate) was within about 1 percentage point of what random price moves would give. Before costs, every version made almost exactly zero or lost a little (see the table below).
After trading costs, the average trade with the standard rules (61.8% entry, 78.6% stop-loss) lost 0.037R, and on 1-hour charts the strategy lost money on all 8 markets. The main trading cost is the spread: the gap between the buying price and the selling price. With the stop-loss at 78.6%, the stop is only 16.8% of the leg away from the entry, so the spread is a large part of the money each trade risks. Our test charged only part of the spread: half of it, and only when a stop-loss closed a trade. Even with that smaller cost, the S&P 500 test on 1-hour charts lost 90.0% of its $10,000 account: its 2,943 trades lost $21 before costs and paid $8,979 in costs. Real trading would cost more (see 'How the spread was charged' under 'What the Fibonacci retracement is').
Only 2 of the 24 tests made money and had at least 100 trades, enough to judge. GBP/USD on 4-hour charts made +160.7% from 2014 to 2025, the best backtest. It made money in both 2014–2021 and 2022–2025, and it also made money from 2014 to 2025 with each of the three changes we tried. But it is 1 test out of 24, and the 24 tests together broke even before costs, so this one result could be luck. The Nasdaq 100 on daily charts made +6.6%, but it lost money in 2022–2025. Daily charts gave few trades: 79 to 117 per market in 12 years, so 5 of the 8 daily tests had fewer than 100 trades. 3 of those 5 made money. They show in green in the results, but with so few trades we don't count them.
Bigger moves did not make the 61.8% level work better. When the leg was less than 8 ATR long, 21.2% to 21.4% of the trades won, about the 21.4% that random price moves would give. When the leg was 8 to 12 ATR long, 19.7% won. After the biggest moves, of 12 ATR or more, only 13.9% of the 280 trades won, fewer than random price moves would give. 238 of those 280 trades were on 1-hour charts (see the chart below).
Is 61.8% a special level?
No: at every level, the trades won about as often as they would if price moved at random
Each row counts the trades of all 24 tests of one version, from 2014 to 2025. 'Won' is the share of trades that reached the take-profit. 'If price moved at random' is the share that would win if price were as likely to go up as down: the distance from the entry to the stop-loss, divided by the distance from the stop-loss to the take-profit. 'Needed to break even' is the win rate at which the money won equals the money lost, after costs. R is the money a trade risks: 1% of the account.
| Version | Trades | Won | If price moved at random | Needed to break even | Average trade |
|---|---|---|---|---|---|
| Enter at 61.8%, stop-loss at 78.6% (the standard rules) | 28,112 | 21.1% | 21.4% | 21.9% | −0.037R |
| Enter at 50%, stop-loss at 78.6% | 26,804 | 35.3% | 36.4% | 36.6% | −0.034R |
| Enter at 38.2%, stop-loss at 78.6% | 26,732 | 50.3% | 51.4% | 51.4% | −0.019R |
| Enter at 61.8%, stop-loss at 100% | 20,976 | 37.8% | 38.2% | 38.3% | −0.012R |
With no trading costs, the average trade lost 0.001R with the standard rules, lost 0.017R entering at 50%, lost 0.010R entering at 38.2%, and made 0.000R with the stop-loss at 100%. After costs, the versions with the stop-loss further from the entry lost less. With the stop-loss further away, the trade is smaller, because it still risks only 1% of the account, so it pays less in trading costs.
Big moves and small moves
After the biggest moves, fewer trades won
Each bar shows the share of trades that won, grouped by the size of the leg that the Fibonacci levels were drawn on. The size is in ATR (how far price moves in an average candle), measured when the trade opened. Each bar counts the trades of all 24 tests using the standard rules, from 2014 to 2025. All five groups lost money after costs.
- Under 4 ATR11,762 trades 21.2%
- 4 to 6 ATR10,337 trades 21.4%
- 6 to 8 ATR3,894 trades 21.3%
- 8 to 12 ATR1,839 trades 19.7%
- 12 ATR or more280 trades 13.9%
To make money after costs, the trades needed to win more than 21.9% of the time. If price moved at random, 21.4% would win.
The strategy
What the Fibonacci retracement is
A Fibonacci retracement measures how far price moves back after a move, as a percentage of that move. Traders draw it from the start of a move to its end. The end is the 0% level and the start is the 100% level. The levels in between are 23.6%, 38.2%, 50%, 61.8% and 78.6%. For example, say EUR/USD rises 100 pips, from 1.1000 to 1.1100 (a pip is 0.0001). The 61.8% level is 1.1038. At that price, EUR/USD has fallen back 61.8% of the rise. Many traders see 61.8% as the most important level. It comes from the golden ratio: 1 ÷ 1.618 = 0.618. A common way to trade it: buy when price falls back to the 61.8% level, put the stop-loss at the 78.6% level (1.1021 in the example), and take profit at the top of the move (1.1100). That trade risks 16.8 pips to make 61.8 pips. Traders pick the start and the end of a move by looking at the chart, and two traders often pick different points. So in our test, a ZigZag indicator picks them with a fixed rule (see the rules).
- Swings
- Found by a ZigZag indicator that turns after price moves 3 × ATR(14) the other way
- Entry
- Limit order at the 61.8% level (the order waits there until price reaches it)
- Stop-loss
- The 78.6% level
- Take-profit
- The 0% level, the end of the move. Before costs, a winning trade makes 3.7 times the money it risks.
- Risk per trade
- 1% of the account
- How the spread was charged
- Our backtest filled entries and take-profits (limit orders) at the order price, with no spread (the gap between the buying price and the selling price). A trade closed by its stop-loss paid half the spread. A real broker charges the full spread on every trade, so real trading would cost more than this test.
- Overnight fees
- Not included. Brokers charge a fee (a swap), or sometimes pay one, for each night a trade stays open. This matters most on daily charts: half of the daily trades stayed open longer than 4.7 days, and 302 of the 785 daily trades stayed open for more than a week.
The rules we tested
- ATR (average true range) is an indicator of how far price moves in an average candle, measured over the last 14 candles. We find the swings, the turning points of price, with a ZigZag indicator. It joins each swing high to the next swing low with a straight line and ignores smaller moves. After a rise, the ZigZag marks the highest price as a swing high once a candle's low is 3 ATR or more below that high. After a fall, it marks the lowest price as a swing low once a candle's high is 3 ATR or more above that low.
- An up-leg is the rise from a swing low to the highest price after it. We draw the Fibonacci levels on it: 100% at the swing low and 0% at the top. A down-leg is the fall from a swing high to the lowest price after it, with 100% at the swing high and 0% at the bottom. Every leg is at least 3 ATR long.
- Buy: as soon as the ZigZag marks a swing low, place a buy limit order at the 61.8% level of the up-leg that starts there. A buy limit order waits below the price and fills only if price comes down to it. While the up-leg makes new highs, the 61.8% level moves up, and the order moves with it. We update the orders each time a candle closes.
- Sell (go short): as soon as the ZigZag marks a swing high, place a sell limit order at the 61.8% level of the down-leg that starts there. A sell limit order waits above the price and fills only if price comes up to it. While the down-leg makes new lows, the order moves down with the 61.8% level.
- Put the stop-loss at the 78.6% level and the take-profit at the 0% level: the top of the up-leg for a buy, and the bottom of the down-leg for a sell. Once the trade opens, the stop-loss and the take-profit do not move.
- On an up-leg longer than about 5 ATR, the 61.8% level is more than 3 ATR below the top. So price reaches the buy order only after the ZigZag has already marked a swing high. The buy order stays in place when that happens. When the ZigZag marks the next swing low, the buy order moves to the new up-leg. Sell orders follow the same rule in the other direction.
- A buy order and a sell order can wait at the same time, but only one trade can be open at a time. When one order fills, we cancel the other one, and we place it again when the trade closes, if its leg is still the newest one. Each leg gets at most one trade. If a candle closes below an up-leg's 61.8% level (or above a down-leg's) while no order is waiting there, for example because another trade is open, we skip that leg.
- We traded the Fibonacci levels on their own: no trend filter, no confirmation candle and no other signal.
- Size every trade so that, if the stop-loss is hit, the trade loses 1% of the account, plus the trading cost.
The method
How we tested it
The test
- Markets
- EUR/USD, GBP/USD, USD/JPY, AUD/USD, Gold, S&P 500, Nasdaq 100 and DAX
- Charts
- 1-hour, 4-hour and daily candles
- Dates
- January 2014 to December 2025
- Account
- $10,000, risking 1% of the account on each trade
- Trading costs
- Included. Every trade pays that market's normal trading cost: the spread, which is the gap between the buy price and the sell price.
How a test passes
We call a test passed only if it meets all four checks. A strategy can make money in one backtest and still fail one of these checks.
- At least 100 trades. With fewer trades, a good result could be luck.
- It made money from 2014 to 2021 and again from 2022 to 2025. This shows whether the strategy kept working in the newer years, not only in the older ones.
- A profit factor (the money won divided by the money lost) of at least 1.2 from 2022 to 2025, after trading costs.
- In 95% of 1,000 random shuffles of the trades, the account must not fall more than 30% from its highest point.
Improvements
Can the Fibonacci retracement be improved?
Traders argue about which Fibonacci level to enter at, and where to put the stop-loss. We tested three common changes, one at a time, on the same 8 markets and 3 charts: entering at the 50% level, entering at the 38.2% level, and moving the stop-loss to the start of the leg (the 100% level). In all three changes, the take-profit stays at the end of the leg. If we picked the best change and judged it on the same years, it would look better than it really is, because we picked it for doing well in those years. So we picked the best change using 2014–2021 only, then checked it on 2022–2025, the years we did not use to pick it.
| Version | Made money 2014–2021years used to pick the best version | Made money 2022–2025years not used to pick it | Made money in both periods | Passed all four checks |
|---|---|---|---|---|
| Standard: enter at 61.8%, stop-loss at 78.6% The rules listed under 'The rules we tested'. Before costs, a winning trade makes 3.7 times the money it risks. | 7 of 24middle test −23.3% | 7 of 24middle test −7.7% | 1 | 0 |
| Enter at the 50% level Place the order at the 50% level, halfway back along the leg, instead of at 61.8%. The stop-loss stays at 78.6% and the take-profit at the end of the leg, so before costs a winning trade makes 1.7 times the money it risks. | 6 of 24middle test −12.7% | 8 of 24middle test −7.0% | 1 | 0 |
| Enter at the 38.2% level Place the order at the 38.2% level, a smaller move back, instead of at 61.8%. The stop-loss stays at 78.6% and the take-profit at the end of the leg, so before costs a winning trade makes 0.95 times the money it risks, a little less than a losing trade loses. | 7 of 24middle test −8.3% | 11 of 24middle test −2.4% | 2 | 1 |
| Stop-loss at the start of the move (100% level)Best on 2014–2021 Enter at 61.8% as in the standard rules, but put the stop-loss exactly at the 100% level instead of at 78.6%: at the swing low for a buy, and at the swing high for a sell. Before costs, a winning trade makes 1.6 times the money it risks. | 9 of 24middle test −4.9% | 7 of 24middle test −3.0% | 1 | 0 |
No. None of the three changes made the strategy make money on most tests. On 2014–2021, the years we used to pick the best change, the stop-loss at the start of the leg (100%) did best: 9 of 24 tests made money with it, compared with 7 with the standard rules. On 2022–2025, the years we kept for the check, it did no better: 7 of 24 tests made money, the same as with the standard rules. In 2022–2025, its middle test (the median of the 24) lost less: −3.0%, compared with −7.7%. With the 100% stop-loss, only 1 test made money in both periods: GBP/USD on 4-hour charts, the same test as with the standard rules. Entering at 38.2% did best on 2022–2025 (11 of 24 tests), but on 2014–2021 it made money in only 7 of 24, so we can't tell whether the 38.2% entry will keep doing better. After costs, every change lost a little less per trade than the standard rules. Each change put more distance between the entry and the stop-loss, so each trade was smaller and paid less in trading costs.
Questions
Questions traders ask
Does the Fibonacci retracement strategy work?
No, not in our test. We backtested a simple, common way to trade it: buy when price falls back 61.8% of a rise, or sell when price rises back 61.8% of a fall. The stop-loss was at the 78.6% level and the take-profit at the end of the move, with no trend filter and no confirmation candle. We used 8 markets, each on 1-hour, 4-hour and daily charts, from 2014 to 2025. Before trading costs, the trades made almost exactly zero. After costs, only 2 of the 24 tests made money and had at least 100 trades, enough to judge: GBP/USD on 4-hour charts and the Nasdaq 100 on daily charts.
Is 61.8% the best Fibonacci level to trade?
No. In our test, no entry level made money on average after costs, and the 61.8% entry lost the most per trade. We also tried entering at the 50% and 38.2% levels, with the stop-loss still at 78.6% and the take-profit still at the end of the move. At every level, the trades won about as often as they would if price moved at random. At 61.8%, 21.1% of trades won, against 21.4% for random price moves. At 50%, 35.3% won, against 36.4%. At 38.2%, 50.3% won, against 51.4%. An entry further back along the move wins less often but makes more on each win, so before costs all three made almost exactly zero or lost a little. After costs, the 38.2% entry lost the least: 0.019R per trade, compared with 0.037R at 61.8%. R is the money a trade risks. At 38.2%, the entry is further from the stop-loss, so the trade is smaller and pays less in trading costs.
Where should you put the stop-loss on a Fibonacci trade?
Neither stop-loss made money on average in our test, but the stop-loss at the start of the move (the 100% level) lost less. After costs, it lost 0.012R per trade, compared with 0.037R with the stop-loss at 78.6%. R is the money a trade risks. With the stop-loss at 100%, 37.8% of trades won instead of 21.1%, but before costs a winning trade makes 1.6 times the money it risks instead of 3.7 times. So before costs, both made almost exactly zero. The 100% stop-loss lost less after costs because it is further from the entry: the trade is smaller, so it pays less in trading costs. In 2014–2021, it made money in more tests than any other version we tried. In 2022–2025, it made money in 7 of 24 tests, the same as the 78.6% stop-loss.
What is the best timeframe for Fibonacci retracements?
None of the three timeframes we tested made money on most markets. On 1-hour charts, the strategy lost money on all 8 markets: the stop-loss is close to the entry, so trading costs are a large part of the money each trade risks. On 4-hour charts, it made money only on GBP/USD. On daily charts, it made money on 4 of the 8 markets. But daily charts gave only 79 to 117 trades per market in 12 years, and 3 of those 4 markets had fewer than 100 trades, too few to judge. On every timeframe, about 21% of the trades won, close to the 21.4% that random price moves would give.
The strategy code we ran
This is the exact code from the BacktestingMax strategy engine. Paste it into the strategy editor in the app to run it on any market.
class FibonacciRetracement618(Strategy):
"""Buy the 61.8% Fibonacci retracement of an up-leg; sell the 61.8% retracement of a down-leg.
Swings come from a ZigZag, so nobody has to pick them by eye. The ZigZag turns down when
price falls 3 x ATR(14) below the highest high of a rise, and turns up when price rises
3 x ATR(14) above the lowest low of a fall. An up-leg runs from a swing low (the 100%
level) to the highest price after it (the 0% level); a down-leg is the mirror. Every leg is
at least 3 ATR long.
Buy: a limit order at the 61.8% level of the newest up-leg, the stop-loss at the 78.6% level
and the take-profit at the top of the leg (0%). Sell: the mirror, on the newest down-leg.
Orders are updated at each candle close. A buy order moves up while its leg makes new
highs; it stays when the ZigZag turns down, until it fills or the ZigZag marks the next
swing low (then the next up-leg takes over). A leg whose level a candle closes past before
the order fills is skipped. One trade per leg and one trade at a time: when one order
fills, the other is pulled until the trade is over. Each trade is sized to lose 1% of the
account at the stop.
The changes, one at a time:
entry_level = 0.5 or 0.382 enter at the 50% or the 38.2% level instead of 61.8%
stop_level = 1.0 stop-loss at the start of the leg (100%) instead of 78.6%
"""
params = {"zigzag_atr": Param(type=float, default=3.0, min=1.0, max=10.0),
"entry_level": Param(type=float, default=0.618, min=0.2, max=0.75),
"stop_level": Param(type=float, default=0.786, min=0.5, max=1.0)}
lookback = 20
def init(self, ctx):
self.atr = ctx.atr(period=14)
self.dir = 0 # the ZigZag: +1 rising, -1 falling, 0 before the first candle
self.start = None # where the current leg started (its 100% level)
self.end = None # the furthest price of the current leg so far (its 0% level)
self.back = None # the furthest price back the other way since self.end was set
self.leg = 0 # leg number; leg 0 has no confirmed start and is never traded
self.newest = {1: None, -1: None} # newest up-leg and down-leg: (number, start, end)
self.done = {1: 0, -1: 0} # per side: the last leg that was traded or skipped
self.orders = {1: None, -1: None} # per side: (order, leg number, levels)
def pull(self, ctx, side):
if self.orders[side] is not None:
ctx.cancel_order(self.orders[side][0].order_id)
self.orders[side] = None
def on_bar(self, ctx):
a = self.atr.value
if a is None:
return
hi, lo = ctx.high[0], ctx.low[0]
turn = ctx.params.zigzag_atr * a
# 1. The ZigZag, updated with the candle that just closed.
if self.dir == 0:
self.dir, self.start, self.end = 1, lo, hi
elif self.dir == 1:
if hi > self.end:
self.end, self.back = hi, None # the rise makes a new high
else:
self.back = lo if self.back is None else min(self.back, lo)
if self.back <= self.end - turn: # price fell 3 ATR: the high is a swing high
self.dir, self.start, self.end, self.back = -1, self.end, self.back, None
self.leg += 1
else:
if lo < self.end:
self.end, self.back = lo, None # the fall makes a new low
else:
self.back = hi if self.back is None else max(self.back, hi)
if self.back >= self.end + turn: # price rose 3 ATR: the low is a swing low
self.dir, self.start, self.end, self.back = 1, self.end, self.back, None
self.leg += 1
if self.leg > 0:
self.newest[self.dir] = (self.leg, self.start, self.end)
# 2. An order that is no longer waiting has filled: its leg is done.
waiting = [o.order_id for o in ctx.orders]
for side in (1, -1):
if self.orders[side] is not None and self.orders[side][0].order_id not in waiting:
self.done[side] = self.orders[side][1]
self.orders[side] = None
in_trade = ctx.position is not None
# 3. A buy order for the newest up-leg and a sell order for the newest down-leg.
for side in (1, -1):
newest = self.newest[side]
if not ctx.gate("leg_not_used_yet", newest is not None and newest[0] != self.done[side]):
self.pull(ctx, side)
continue
number, start, end = newest
size_of_leg = abs(end - start)
entry = end - side * ctx.params.entry_level * size_of_leg
stop = end - side * ctx.params.stop_level * size_of_leg
if not ctx.gate("close_not_past_level", (ctx.close[0] - entry) * side > 0):
self.done[side] = number # price got there first: skip this leg
self.pull(ctx, side)
continue
if not ctx.gate("no_open_trade", not in_trade):
self.pull(ctx, side) # one trade at a time
continue
levels = (entry, stop, end)
if self.orders[side] is not None and self.orders[side][1] == number and self.orders[side][2] == levels:
continue # nothing changed: the order stays
self.pull(ctx, side)
size = ctx.size_by_risk_pct(0.01, stop=stop, entry=entry)
if size <= 0:
continue
if side == 1:
order = ctx.buy(size=size, limit=entry, sl=stop, tp=end, tag="fib_buy")
else:
order = ctx.sell(size=size, limit=entry, sl=stop, tp=end, tag="fib_sell")
if order is not None:
self.orders[side] = (order, number, levels)
Your turn
Test the Fibonacci retracement yourself
Change the settings, the market or the stop-loss and see the result in seconds. Ask the BacktestingMax AI: Backtest a 61.8% Fibonacci retracement on GBP/USD, 4-hour chart, with the stop-loss at 78.6% and the take-profit at the end of the move
.
Free account. No credit card needed.
See every strategy we tested Browse strategies shared by tradersBacktest on historical data with trading costs, run by BacktestingMax. Past results do not guarantee future results, and nothing here is financial advice. Updated 12 October 2026.