Strategies we backtested Fibonacci retracement

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

Best test GBP/USD, 4-hour chart +160.7% from 2014 to 2025
Middle test (median): half of the 24 did better, half did worse EUR/USD, 4-hour chart −32.7% from 2014 to 2025

What we found

What the 24 backtests show

  1. 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.

  2. 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).

  3. 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').

  4. 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.

  5. 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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. We traded the Fibonacci levels on their own: no trend filter, no confirmation candle and no other signal.
  9. 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.

Try it free in BacktestingMax

Free account. No credit card needed.

See every strategy we tested Browse strategies shared by traders

Backtest 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.