Tested by BacktestingMax
Stochastic RSI crossover strategy backtest
Does the Stochastic RSI crossover strategy work?
No, not in our backtest. We ran 36 tests from 2019 to 2025: 9 markets (4 currency pairs, gold, silver and 3 stock indices), each on 15-minute, 1-hour, 4-hour and daily charts. After trading costs, 32 of the 36 lost money. The Stochastic RSI (Stoch RSI) starts from RSI, an indicator that scores how hard price has moved, from 0 to 100. It then shows where RSI sits between its highest and lowest values of the last 14 candles. The strategy buys when %K, the main line, crosses above %D, its slower average, with both lines below 20. It sells short (sells first, to profit if price falls) when %K crosses below %D with both lines above 80. A trade closes when the lines cross the other way, or at a stop-loss that loses 1% of the account. Only 2 tests made money in both 2019–2022 and 2023–2025: the Nasdaq 100 on the 4-hour chart and GBP/USD daily. The Stoch RSI compares RSI with its own last 14 values, so at a buy signal RSI itself was rarely below 30. On 1-hour, 4-hour and daily charts, that was true for only 11.1% of the buys. None of the three changes we tried made it work on most tests.
36 backtests 2019–2025 Trading costs included Tested 2 November 2026
Where it worked 36 backtests- Made money
- 4 of 36 tests, using the standard rules
- Made money in both periods
- 2 2019–2022 and again 2023–2025
- Best backtest
- +26% Nasdaq 100, 4-hour chart: account growth 2019–2025
- With a later entry: %K back above 20 or below 80
- 5 tests made money in both periods, compared with 2 using the standard rules
Made money in both periods
- GBP/USD, daily
- Nasdaq 100, 4-hour
Lost money on every market
- 15-minute charts
- 1-hour charts
The results
Results on every market
Each box shows one backtest of the Stochastic RSI crossover using the standard rules, from 2019 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 2019–2022 and 2023–2025, or passed all four of our checks (see "How a test passes" further down).
| Market | 15-minute | 1-hour | 4-hour | daily |
|---|---|---|---|---|
| EUR/USD | −100% Lost money. Account down 90% by Dec 2019 | −70% Lost money | −48% Lost money | −13% Lost money |
| GBP/USD | −100% Lost money. Account down 90% by Aug 2019 | −93% Lost money. Account down 90% by Feb 2025 | −16% Lost money | +6% Made money in both periods |
| USD/JPY | −100% Lost money. Account down 90% by Oct 2019 | −94% Lost money. Account down 90% by May 2024 | −5% Lost money | −8% Lost money |
| AUD/USD | −100% Lost money. Account down 90% by Aug 2019 | −97% Lost money. Account down 90% by Feb 2023 | −42% Lost money | +7% Made money overall, lost in one period |
| Gold | −99% Lost money. Account down 90% by Jul 2019 | −88% Lost money | −19% Lost money | −5% Lost money |
| Silver | −99% Lost money. Account down 90% by Feb 2019 | −94% Lost money. Account down 90% by Apr 2021 | −51% Lost money | −2% Lost money |
| Nasdaq 100 | −99% Lost money. Account down 90% by Oct 2019 | −71% Lost money | +26% Made money in both periods | −5% Lost money |
| S&P 500 | −100% Lost money. Account down 90% by Jan 2020 | −86% Lost money | −28% Lost money | −8% Lost money |
| DAX | −97% Lost money. Account down 90% by Aug 2021 | −84% Lost money | +5% Made money overall, lost in one period | −9% Lost money |
All the numbers, test by test
| Market | Chart | Trades | Win rate | Profit factor | Result | Max drawdown | 2019–2022 | 2023–2025 | Monte Carlo drawdown | Trading costs |
|---|---|---|---|---|---|---|---|---|---|---|
| EUR/USD | 15-minute | 5,130 | 31% | 0.78 | −99.6% | −99.7% | −99.4% | −35.7% | −99.7% | $13,026 |
| EUR/USD | 1-hour | 3,650 | 35.3% | 0.91 | −70.4% | −74.0% | −51.8% | −38.6% | −82.4% | $8,595 |
| EUR/USD | 4-hour | 983 | 34.9% | 0.79 | −48.2% | −53.1% | −52.6% | +9.4% | −58.7% | $1,202 |
| EUR/USD | daily | 147 | 34% | 0.76 | −12.5% | −18.3% | +2.5% | −14.7% | −21.5% | $102 |
| GBP/USD | 15-minute | 4,301 | 30.6% | 0.69 | −99.5% | −99.6% | −99.4% | −26.3% | −99.6% | $7,775 |
| GBP/USD | 1-hour | 3,692 | 34.2% | 0.80 | −92.9% | −93.3% | −80.9% | −62.9% | −94.4% | $5,368 |
| GBP/USD | 4-hour | 941 | 37.1% | 0.95 | −16.3% | −29.2% | −18.1% | +2.2% | −43.3% | $1,780 |
| GBP/USD | daily | 144 | 39.6% | 1.11 | +5.8% | −13.3% | +1.4% | +4.3% | −14.4% | $114 |
| USD/JPY | 15-minute | 4,143 | 31.8% | 0.70 | −99.7% | −99.7% | −99.6% | −13.4% | −99.7% | $9,698 |
| USD/JPY | 1-hour | 3,783 | 33.3% | 0.79 | −93.9% | −94.3% | −86.0% | −56.2% | −95.3% | $5,684 |
| USD/JPY | 4-hour | 960 | 37.2% | 0.98 | −4.8% | −29.3% | −16.2% | +13.5% | −41.5% | $1,512 |
| USD/JPY | daily | 136 | 33.8% | 0.83 | −8.2% | −15.0% | +0.5% | −8.6% | −18.6% | $87 |
| AUD/USD | 15-minute | 3,361 | 30.4% | 0.67 | −99.6% | −99.6% | −99.5% | −21.6% | −99.7% | $10,314 |
| AUD/USD | 1-hour | 3,716 | 33.3% | 0.74 | −96.9% | −96.9% | −87.5% | −75.3% | −97.4% | $5,584 |
| AUD/USD | 4-hour | 953 | 34.9% | 0.84 | −42.3% | −50.6% | −38.2% | −6.7% | −56.0% | $1,892 |
| AUD/USD | daily | 143 | 35.7% | 1.15 | +6.7% | −15.0% | −3.5% | +10.6% | −12.7% | $149 |
| Gold | 15-minute | 2,208 | 29.2% | 0.56 | −98.6% | −98.7% | −98.5% | −8.4% | −98.8% | $9,080 |
| Gold | 1-hour | 3,088 | 34.2% | 0.77 | −88.3% | −89.4% | −80.7% | −39.2% | −90.5% | $5,553 |
| Gold | 4-hour | 955 | 35.7% | 0.93 | −19.1% | −29.0% | −11.9% | −8.1% | −42.4% | $1,681 |
| Gold | daily | 140 | 33.6% | 0.88 | −4.5% | −8.3% | −4.1% | −0.4% | −13.8% | $83 |
| Silver | 15-minute | 744 | 16.1% | 0.15 | −99.1% | −99.1% | −99.1% | 0.0% | −99.1% | $8,926 |
| Silver | 1-hour | 1,152 | 26.7% | 0.37 | −94.0% | −94.3% | −93.5% | −8.4% | −94.5% | $6,948 |
| Silver | 4-hour | 921 | 34.2% | 0.74 | −50.7% | −53.9% | −41.4% | −15.8% | −57.7% | $3,499 |
| Silver | daily | 137 | 35% | 0.95 | −2.0% | −12.2% | −6.9% | +5.3% | −13.4% | $209 |
| Nasdaq 100 | 15-minute | 3,719 | 31.1% | 0.65 | −98.8% | −98.8% | −98.7% | −9.3% | −99.0% | $7,593 |
| Nasdaq 100 | 1-hour | 3,467 | 33.7% | 0.88 | −70.7% | −76.9% | −71.8% | +4.1% | −82.0% | $4,931 |
| Nasdaq 100 | 4-hour | 943 | 35.3% | 1.06 | +26.3% | −16.0% | +24.6% | +1.3% | −35.3% | $1,328 |
| Nasdaq 100 | daily | 129 | 34.1% | 0.86 | −5.4% | −15.0% | −7.3% | +2.0% | −16.1% | $40 |
| S&P 500 | 15-minute | 6,118 | 32.6% | 0.78 | −99.7% | −99.7% | −99.5% | −45.9% | −99.8% | $10,721 |
| S&P 500 | 1-hour | 3,549 | 33% | 0.79 | −86.0% | −89.1% | −80.3% | −28.8% | −90.5% | $3,487 |
| S&P 500 | 4-hour | 909 | 32.5% | 0.91 | −28.3% | −37.6% | −11.9% | −18.6% | −49.6% | $1,139 |
| S&P 500 | daily | 136 | 33.1% | 0.84 | −7.7% | −19.5% | −9.8% | +2.2% | −20.2% | $57 |
| DAX | 15-minute | 9,932 | 34.6% | 0.88 | −97.1% | −97.7% | −95.3% | −37.6% | −98.2% | $9,702 |
| DAX | 1-hour | 3,398 | 32.4% | 0.83 | −84.4% | −85.0% | −68.3% | −50.8% | −88.5% | $2,346 |
| DAX | 4-hour | 909 | 37.3% | 1.02 | +4.6% | −22.6% | −8.1% | +13.8% | −35.3% | $613 |
| DAX | daily | 129 | 26.4% | 0.77 | −8.9% | −15.9% | −1.0% | −8.0% | −17.7% | $30 |
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. 2019–2022 and 2023–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 36 backtests show
All 18 tests on 15-minute and 1-hour charts lost money: 70.4% to 96.9% of the account on 1-hour charts, and more than 97% on 15-minute charts. On 4-hour and daily charts, 4 of the 18 tests made money. On 4-hour charts, they were the Nasdaq 100 (+26.3%) and the DAX (+4.6%), and on daily charts AUD/USD (+6.7%) and GBP/USD (+5.8%). Only the Nasdaq 100 4-hour and GBP/USD daily made money in both 2019–2022 and 2023–2025, and neither passed all four of our checks. R is the amount a trade loses if price reaches its stop-loss: 1% of the account when the trade opens, so $100 on the starting $10,000. Before trading costs, the average trade of each chart type (the 9 markets together) already lost a little, between 0.002R and 0.022R. Trading costs then made it worse. On 15-minute charts, the average trade lost 0.008R before costs and 0.109R after them. On daily charts, it lost 0.021R before costs and 0.028R after them.
To see what the RSI step changes, we ran the same rules on the regular stochastic (14, 3, 3). It shows where the close sits between the highest and lowest prices of the last 14 candles. %K is averaged over 3 candles, and %D is the average of 3 %K values. This version keeps this page's exits and start date: a trade closes only at the opposite cross, and trading starts after 200 candles. So its numbers differ from our stochastic crossover (14, 3, 3) page, where a trade also closes when %K reaches the other zone. On 1-hour charts, %K and %D crossed about 92,000 times with each indicator, across the 9 markets. But on these charts, 36% of the Stoch RSI's crosses were trade signals, compared with 27% of the regular stochastic's. A signal is a cross up with both lines below 20, or a cross down with both lines above 80. So on 1-hour, 4-hour and daily charts, the Stoch RSI made 39,210 trades, compared with 31,301. Per trade, the two lost about the same: 0.054R and 0.052R, about $5 a trade on a $10,000 account. With more trades, the Stoch RSI lost more than the regular stochastic on 8 of the 9 markets on 1-hour charts. Each made money in 4 of the 36 tests. So the RSI step did not make the strategy better: it gave more trades, with about the same loss per trade (see the first table below).
%K, the Stoch RSI's main line, was below 20 or above 80 on 48% to 55% of all candles, on every market and chart. RSI, the indicator it is built from, was below 30 or above 70 on only 7% to 16% of the candles. The reason is the stochastic step. The Stoch RSI does not measure whether RSI is low. It measures whether RSI is low compared with its own last 14 values. So a Stoch RSI buy signal rarely meant that RSI was oversold. On 1-hour, 4-hour and daily charts, RSI was below 30 at only 2,100 out of 18,918 buys (11.1%). It was 50 or higher at 5,842 of them (30.9%). The typical (median) RSI was 44.1 at a buy, and 58.4 at a sell.
Trades where RSI was also below 30 or above 70 were not reliably better. On 1-hour, 4-hour and daily charts, 5,033 trades opened with RSI below 30 (buys) or above 70 (sells). They lost 0.060R per trade on average, and the other 34,177 trades lost 0.053R. In 2019–2022, these trades did worse than the others: they lost 0.096R per trade, compared with 0.068R. In 2023–2025, they did better: they lost 0.012R, compared with 0.033R. So in this test, RSI below 30 or above 70 was not a reliable sign of a better trade. These trades lost money in both periods (see the second table below).
We tried three changes, one at a time: the regular stochastic instead of the Stoch RSI, a 200 EMA trend filter, and a later entry. The 200 EMA is a moving average of the last 200 closes, and the filter only buys above it and only sells short below it. The later entry does not trade the cross inside the zone (below 20 for a buy, above 80 for a sell). It buys when %K closes back above 20, and sells short when %K closes back below 80. Only the later entry lost less per trade on 1-hour, 4-hour and daily charts in both 2019–2022 and 2023–2025. On these charts together, it lost 0.042R per trade, compared with 0.054R with the standard rules. On 4-hour charts, its average trade was about break-even (+0.002R), and 4 of the 9 markets made money, from +25.9% (the Nasdaq 100) to +79.6% (USD/JPY). But in 2023–2025, fewer tests made money with it than with the standard rules: 8 of 36, compared with 11. On 1-hour, 4-hour and daily charts together, the 200 EMA filter cut the number of trades in half, and the average trade stayed about the same: a loss of 0.056R.
Stoch RSI against the regular stochastic
The Stoch RSI made more trades than the regular stochastic, with about the same result per trade
We ran the same rules on two indicators that use the same formula. The Stoch RSI applies it to RSI, and the regular stochastic (14, 3, 3) applies it to price. Each row is one indicator on one chart, with the 9 markets from 2019 to 2025. The average trade puts together all the trades of the 9 markets. Results are in R (1% of the account when the trade opened), after trading costs.
| Chart | Indicator | Time in the zones (lowest to highest market) | Trades a year on a typical market | Average trade | Tests that made money |
|---|---|---|---|---|---|
| 1-hour | Stoch RSI | 49.5% to 52.9% | 510 | −0.064R | 0 of 9 |
| 1-hour | Regular stochastic | 34.4% to 42.1% | 404 | −0.063R | 0 of 9 |
| 4-hour | Stoch RSI | 51.9% to 54.9% | 138 | −0.024R | 2 of 9 |
| 4-hour | Regular stochastic | 37.1% to 46.0% | 108 | −0.020R | 1 of 9 |
| Daily | Stoch RSI | 49.2% to 53.8% | 23 | −0.028R | 2 of 9 |
| Daily | Regular stochastic | 38.6% to 55.6% | 19 | −0.027R | 3 of 9 |
Time in the zones is the share of all candles with %K below 20 or above 80, with or without a trade open. For comparison, RSI was below 30 or above 70 on 10.6% to 15.5% of the 1-hour candles. On 4-hour candles it was 9.8% to 14.5%, and on daily candles 7.1% to 13.8%. A typical market is the middle (median) one of the 9. The regular stochastic was in its zones more often than the Stoch RSI on only two charts, the Nasdaq 100 and S&P 500 daily. That is why its daily range goes up to 55.6%. These are this page's rules, so the regular stochastic's numbers differ from our stochastic crossover (14, 3, 3) page, where a trade also closes when %K reaches the other zone. We leave out the 15-minute charts: both indicators lost money on all 9 markets there, and most accounts lost 90% early and then skipped most signals.
Stoch RSI against RSI
Trades with RSI also below 30 or above 70: worse in 2019–2022, better in 2023–2025
A common way to read RSI on its own: below 30 is oversold, and above 70 overbought. This table sorts the trades of the standard rules by RSI on the candle that gave the entry. It covers 1-hour, 4-hour and daily charts, from 2019 to 2025. The win rate is the share of trades that made money. Results are in R (1% of the account when the trade opened), after trading costs.
| RSI on the candle that gave the entry | Share of the trades | Win rate | Average trade, 2019–2025 | Average trade, 2019–2022 | Average trade, 2023–2025 |
|---|---|---|---|---|---|
| Buys with RSI below 30, sells with RSI above 70 | 12.8% | 36.1% | −0.060R | −0.096R | −0.012R |
| Buys with RSI from 30 to under 50, sells with RSI above 50 up to 70 | 60.1% | 33.8% | −0.053R | −0.069R | −0.029R |
| Buys with RSI at 50 or higher, sells with RSI at 50 or lower | 27.1% | 33.0% | −0.055R | −0.066R | −0.040R |
The table covers 39,210 trades: 18,918 buys and 20,292 sells. The typical (median) RSI was 44.1 at a buy and 58.4 at a sell. In the last row, %K was below 20 while RSI was 50 or higher, or above 80 while RSI was 50 or lower.
The strategy
What the Stochastic RSI crossover is
Tushar Chande and Stanley Kroll described the Stochastic RSI (Stoch RSI) in 1994, in their book The New Technical Trader. The regular stochastic oscillator shows where the close sits between the highest and lowest prices of the last 14 candles. The Stoch RSI does the same with RSI instead of price. RSI is an indicator that scores how hard price has moved, from 0 to 100. So the Stoch RSI compares RSI with its own highest and lowest values of the last 14 candles. 100 means RSI is at its highest of those 14 candles, and 0 means it is at its lowest. For example, say RSI moved between 45 and 60 over the last 14 candles, and is now at 45. Then this reading is 0, even though RSI is in the middle of its 0 to 100 scale, far from the usual oversold level of 30. The usual settings draw two lines. %K is the reading averaged over the last 3 candles. %D, the signal line, is the average of the last 3 %K values, so it moves more slowly. A common way to trade it: below 20 is oversold, so you look for a buy, and above 80 is overbought, so you look for a sell. The crossover strategy buys when %K crosses above %D with both lines below 20, and sells short when %K crosses below %D with both lines above 80.
- Stochastic RSI
- 3, 3, 14, 14, in TradingView's order. %K is averaged over 3 candles, and %D is the average of 3 %K values. RSI uses 14 candles, and the stochastic looks at the last 14 RSI values. The levels are 20 and 80. These are TradingView's default settings.
- Entry
- %K crosses above %D with both lines below 20 (buy), or below %D with both lines above 80 (sell short). The trade opens at the next candle's open.
- Exit
- The opposite cross: %K crosses back below %D (for a buy) or above %D (for a sell), at any level. Or the stop-loss, if price reaches it first.
- Stop-loss
- 1.5 × ATR(14) from the close of the candle that gave the entry. ATR(14) is the size of an average candle over the last 14 candles. The stop-loss does not move. We did not test other stop-loss distances.
- Take-profit
- None. The opposite cross closes the trade.
- Trading costs on each market
- Each trade pays the market's spread, the gap between the buy and the sell price. A pip is a price move of 0.0001 on EUR/USD, GBP/USD and AUD/USD, and of 0.01 on USD/JPY. We used these spreads: 0.8 pips on EUR/USD, 1.2 pips on GBP/USD, 0.9 pips on USD/JPY and 1.0 pip on AUD/USD. The spread was $0.30 an ounce on gold and $0.020 an ounce on silver. It was 1.5 points on the Nasdaq 100, 0.4 points on the S&P 500 and 1.0 point on the DAX. For silver, the Nasdaq 100 and the DAX, these are wider than our backtest engine's default spreads, to match a typical retail broker. Every trade opens at the next candle's open, and closes at the next candle's open or at the stop-loss. Each opening and each closing pays half the spread. There is no commission.
- Risk per trade
- 1% of the account at the time of the trade, measured from the close of the candle that gave the entry to the stop-loss. In the results, we call this amount R. Each test started with $10,000. Two things change the real risk a little. The trade opens at the next candle's open, not at that close. And its size is rounded down to a size the market allows.
- Smallest trade size
- The smallest trade size is 1,000 units of a currency, 1 ounce of gold, 50 ounces of silver, or 0.1 of an index contract. On an index, 0.1 of a contract makes or loses $0.10 (€0.10 on the DAX) for each point the index moves. If a trade that risks 1% would be smaller, the test skips the signal. With the standard rules on 4-hour and daily charts, it skipped 52 out of the 9,769 signals that came while no trade was open. All 52 were on gold, silver, the Nasdaq 100 and the DAX. 2 more came on the last candle of 2025, so their trades never opened. On 1-hour charts, it skipped 2,763 out of 32,258. 2,292 of them were on silver, where the account had lost 90% by April 2021. On 15-minute charts, most accounts lost 90% in the first year. After that, 1% of what was left was usually below the smallest trade size, and the test skipped 88,890 out of 128,577 signals. The engine also did not open 31 more orders on EUR/USD, most of them from June 2024, when that account had almost nothing left.
- Overnight (swap) fees
- Not included. Brokers charge (or sometimes pay) a fee for each night a trade stays open. With the standard rules, half of the trades stayed open 1 hour or less on 15-minute charts, and 4 hours or less on 1-hour charts. On 4-hour charts, half stayed open 18 hours or less, and on daily charts 6 days or less. On 4-hour and daily charts, a trade was open 37% to 44% of the time. So these fees matter most for the 4-hour and daily tests.
- Price data
- We used 1-minute prices from January 2019 to December 2025, and built 15-minute, 1-hour, 4-hour and daily candles from them. 4-hour and daily candles start at 17:00 New York time. We start in 2019 because our index prices before mid-2018 often did not move outside stock exchange hours. Because every version waits for the first 200 candles, the daily tests trade from October 2019. Our S&P 500 and DAX data also has a few tiny candles just after the Friday close (13 and 29 in these years), which the strategy skips.
The rules we tested
- The Stoch RSI (3, 3, 14, 14) is worked out in three steps. First, we calculate RSI over the last 14 candles, from 0 to 100. Then we find where this RSI sits between its highest and lowest values of the last 14 candles, from 0 to 100. Last, %K is the average of the last 3 of these readings, and %D is the average of the last 3 %K values. We check each candle when it closes.
- Buy when %K crosses above %D and both lines are below 20. A cross means that %K was at or below %D when the previous candle closed, and is above %D when this candle closes. The trade opens at the next candle's open.
- Sell short (sell first, to make money if price falls) when %K crosses below %D and both lines are above 80. The trade opens at the next candle's open.
- Close a buy when %K crosses back below %D, and a sell when %K crosses back above %D, at any level, not only below 20 or above 80. We call this the opposite cross. The trade closes at the next candle's open.
- Sometimes the opposite cross is also a signal the other way: for example, a buy is open and %K crosses below %D with both lines above 80. Then the buy closes at the next candle's open, and a sell opens one candle later.
- ATR (Average True Range) is an indicator of how far price moves in an average candle, measured over the last 14 candles. Put the stop-loss 1.5 times the ATR away from the close of the candle that gave the entry: below it for a buy, above it for a sell. The stop-loss does not move. If price gaps past it (opens beyond it), the trade closes at that worse price. After a trade closes at its stop-loss, the strategy waits for a new signal.
- Only one trade is open at a time. Size every trade so that, if the stop-loss is hit, the trade loses 1% of the account. If that trade would be smaller than the smallest trade size the market allows, skip it.
- We skip two kinds of candles. The first has no price movement at all (a market holiday in our price data). The second is a tiny candle that opens after the Friday close at 17:00 New York time. Skipped candles do not count in the indicators, and they give no signal.
- One of the changes we tested, the 200 EMA trend filter, needs 200 candles of history. So every version, the standard rules and the three changes, starts after the first 200 candles of each chart. That way, all versions trade the same dates.
The method
How we tested it
The test
- Markets
- EUR/USD, GBP/USD, USD/JPY, AUD/USD, Gold, Silver, Nasdaq 100, S&P 500 and DAX
- Charts
- 15-minute, 1-hour, 4-hour and daily candles
- Dates
- January 2019 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 2019 to 2022 and again from 2023 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 2023 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 Stochastic RSI crossover be improved?
Not in our test. We tried three changes, one at a time, on the same 9 markets and 4 charts. The first replaces the Stoch RSI with the regular stochastic (14, 3, 3), to see what the RSI step changes. The second trades only in the direction of the trend, using the 200 EMA. The third enters later: it waits for %K to leave the zone (below 20 for a buy, above 80 for a sell). Traders do this to wait until price starts to turn. If you pick the best change on some years and judge it on the same years, it will almost always look good. So we picked the best one using 2019–2022 only, by the number of tests that made money, and then checked it on 2023–2025.
| Version | Made money 2019–2022years used to pick the best version | Made money 2023–2025years not used to pick it | Made money in both periods | Passed all four checks |
|---|---|---|---|---|
| Standard rules The rules under 'The rules we tested', with nothing changed. | 4 of 36middle test −52.2% | 11 of 36middle test −8.5% | 2 | 0 |
| The regular stochastic instead of the Stoch RSI The same rules on the regular stochastic (14, 3, 3). It uses the same formula on price instead of on RSI: where the close sits between the highest and lowest prices of the last 14 candles. This takes away the RSI step, so it shows what that step changes. Unlike on our stochastic crossover (14, 3, 3) page, a trade closes only at the opposite cross. | 5 of 36middle test −27.6% | 9 of 36middle test −10.2% | 2 | 0 |
| With a 200 EMA trend filter The 200 EMA is a moving average of the last 200 closing prices that gives more weight to recent candles. Only buy when the candle that gives the entry closes above the 200 EMA, and only sell short when it closes below it. | 7 of 36middle test −26.3% | 11 of 36middle test −7.5% | 1 | 0 |
| With a later entry: %K back above 20 or below 80Best on 2019–2022 This version does not trade the cross inside the zone (below 20 for a buy, above 80 for a sell). It buys when %K closes back above 20, after closing at 20 or lower on the candle before, and %K is above %D. It sells short when %K closes back below 80, after closing at 80 or higher on the candle before, and %K is below %D. The exits and the stop-loss stay the same. | 8 of 36middle test −42.0% | 8 of 36middle test −8.6% | 5 | 3 |
With the standard rules, 4 of 36 tests made money in 2019–2022 and 11 of 36 in 2023–2025. The later entry did best in 2019–2022, the years we used to pick: 8 of 36 tests made money with it. By the same measure, it did not hold up in 2023–2025, the years we kept for the check. In those years, 8 of 36 tests made money with it, compared with 11 with the standard rules. In 2023–2025, the middle test (half of the 36 did better, half did worse) was about the same: −8.6% with the later entry and −8.5% without it. With the later entry, 5 tests made money in both periods, compared with 2 with the standard rules. 3 of the 5 passed all four of our checks: USD/JPY on the 4-hour chart, and GBP/USD and silver on the daily chart. But that is only 3 of 36 tests, so it could be luck. The 200 EMA filter made money in both periods on 1 test only, the Nasdaq 100 on the 4-hour chart. On daily charts, it left only 50 to 75 trades per market, fewer than the 100 we need to judge a test. The regular stochastic made money in both periods on 2 tests, the same number as the Stoch RSI. So none of the three changes made the strategy make money on most tests.
Passed all four checks with a later entry: %K back above 20 or below 80
- GBP/USD, daily
- USD/JPY, 4-hour
- Silver, daily
Questions
Questions traders ask
Does the Stochastic RSI crossover strategy work?
No, not in our backtest. From 2019 to 2025, after trading costs, the standard rules lost money in 32 of 36 tests: 9 markets, each on 15-minute, 1-hour, 4-hour and daily charts. The standard rules use the Stoch RSI's default settings (3, 3, 14, 14) with no extra filter. They buy when %K (the main line) crosses above %D (its slower average) with both lines below 20. They sell short when %K crosses below %D with both lines above 80. A trade closes when the two lines cross the other way, or at its stop-loss. Only 2 tests made money in both 2019–2022 and 2023–2025: the Nasdaq 100 on the 4-hour chart and GBP/USD on the daily chart.
Is the Stochastic RSI better than the stochastic oscillator?
Not in our test. We ran the same rules on the regular stochastic (14, 3, 3), which shows where the close sits between the highest and lowest prices of the last 14 candles. These rules close a trade only at the opposite cross. So the results differ from our stochastic crossover (14, 3, 3) page, which also closes a trade when %K reaches the other zone. Each indicator made money in 4 of 36 tests, and only 2 of those made money in both 2019–2022 and 2023–2025. R is the amount a trade loses at its stop-loss: 1% of the account when the trade opens. On 1-hour, 4-hour and daily charts, the Stoch RSI lost 0.054R per trade, and the regular stochastic 0.052R. The Stoch RSI made 25% more trades, because more of its crosses came below 20 or above 80. With more trades and the same loss per trade, it lost more than the regular stochastic on 8 of the 9 markets on 1-hour charts.
What is the difference between the Stochastic RSI and RSI?
RSI scores how hard price has moved over the last 14 candles, from 0 to 100. The Stoch RSI shows where RSI sits between its highest and lowest values of the last 14 candles, also from 0 to 100. So the Stoch RSI is low whenever RSI is near its recent low, even when RSI itself is at 45. In our test, the Stoch RSI's %K was below 20 or above 80 on 48% to 55% of the candles. RSI was below 30 or above 70 on 7% to 16%. At the Stoch RSI's buys on 1-hour, 4-hour and daily charts, RSI was below 30 only 11.1% of the time. R is the amount a trade loses at its stop-loss: 1% of the account when the trade opens. Over 2019–2025, the trades where RSI was also below 30 (buys) or above 70 (sells) did no better: they lost 0.060R per trade, compared with 0.053R for the others. In 2023–2025 alone, they lost less.
What is the best timeframe for the Stochastic RSI?
In our test, 4-hour and daily charts lost the least, but no timeframe made money on most markets. All 9 tests on 15-minute charts and all 9 on 1-hour charts lost money. On 4-hour charts, 2 of 9 made money, and on daily charts 2 of 9. R is the amount a trade loses at its stop-loss: 1% of the account when the trade opens. Per trade, after trading costs, the Stoch RSI lost 0.109R on 15-minute charts, 0.064R on 1-hour charts, 0.024R on 4-hour charts and 0.028R on daily charts. Daily charts made the fewest trades: about 23 a year on a typical market.
Keep exploring
Related strategies we tested
Stochastic Stochastic oscillator crossover (14, 3, 3) backtest Made money in 3 of 36 tests, 1 of them in both periods. Best: AUD/USD, daily, +6% RSI RSI overbought/oversold strategy backtest Made money in 4 of 24 tests, 2 of them in both periods. Best: DAX, 1-hour, +92%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 StochasticRsiCrossover(Strategy):
"""The Stochastic RSI crossover (RSI 14, stochastic 14, %K 3, %D 3, levels 20 and 80), as
most traders learn it, plus three changes traders make.
The Stochastic RSI is the stochastic formula applied to RSI instead of to price. It is
worked out here, on the candles the strategy uses (see "Skipped candles"):
RSI = Wilder's RSI of the last 14 closes, from 0 to 100
raw = 100 x (RSI - lowest RSI of the last 14 candles)
/ (highest RSI of the last 14 candles - lowest RSI of the last 14 candles)
%K = the average of the last 3 raw values
%D = the average of the last 3 %K values (the signal line)
This is the Stoch RSI that charting platforms show as 3, 3, 14, 14.
Standard (all switches off):
Buy when %K crosses above %D and both lines are below 20 (oversold).
Sell short when %K crosses below %D and both lines are above 80 (overbought).
Close a buy when %K crosses below %D, and a sell when %K crosses above %D: the opposite
cross, wherever the two lines are. Entries and these exits fill at the next candle's open.
If the cross that closes a trade is also a signal the other way (in a buy, a cross below
%D with both lines above 80), the opposite trade opens one candle later, once the old
trade has closed. After a stop-loss, a new trade needs a new signal.
Stop-loss 1.5 x ATR(14) from the close of the candle that gave the entry. It does not move.
Size: 1% of the account lost at the stop. One trade at a time.
Every version starts trading once the 200 EMA has 200 candles, so all versions trade the
same dates (and the RSI has settled by then).
Skipped candles: a candle that opens on a Friday at 17:00 New York time or later, and a
flat candle (high = low, a market holiday or a closed hour). The markets in this test are
closed on Friday evenings, but some index and silver data has a few minutes of prices after
the close, which make a tiny extra candle. A skipped candle does not go into the RSI, the
stochastic, the ATR or the 200 EMA, and gives no signal and no exit. That is why the
indicators are worked out here instead of with the built-in ones. On a market that trades
at the weekend (crypto), remove the Friday skip.
The changes, one at a time:
price_stoch = 1 the regular stochastic (14, 3, 3) instead of the Stoch RSI: the same
formula on price, raw = 100 x (close - lowest low of the last 14
candles) / (highest high - lowest low). Everything else stays the same
trend_filter = 1 only buy when the entry candle closes above the 200 EMA, only sell
short when it closes below it
leave_zone = 1 wait for %K to leave the zone: buy when %K closes back above 20 (it was
20 or lower on the candle before) and is above %D; sell short when %K
closes back below 80 and is below %D. The exits stay the same
"""
params = {"rsi_period": Param(type=int, default=14, min=2, max=100),
"stoch_period": Param(type=int, default=14, min=2, max=100),
"k_smooth": Param(type=int, default=3, min=1, max=20),
"d_period": Param(type=int, default=3, min=1, max=20),
"oversold": Param(type=float, default=20.0, min=1.0, max=49.0),
"overbought": Param(type=float, default=80.0, min=51.0, max=99.0),
"atr_period": Param(type=int, default=14, min=2, max=100),
"atr_mult": Param(type=float, default=1.5, min=0.5, max=5.0),
"ema_period": Param(type=int, default=200, min=2, max=500),
"price_stoch": Param(type=int, default=0, min=0, max=1),
"trend_filter": Param(type=int, default=0, min=0, max=1),
"leave_zone": Param(type=int, default=0, min=0, max=1)}
lookback = 2
def init(self, ctx):
self.ny = ctx.clock("America/New_York")
self.prev_close = None
self.atr = None # Wilder's average of the true range, as the built-in ATR
self.atr_count = 0
self.avg_gain = None # Wilder's averages of the up and the down moves, for the RSI
self.avg_loss = None
self.moves = 0
self.ema = None # the 200 EMA, started from the average of the first 200 closes
self.ema_seed = []
self.rsis = [] # the last 14 RSI values
self.highs = [] # highs and lows of the last 14 candles (price_stoch)
self.lows = []
self.raw = [] # the last 3 raw values
self.slow_k = [] # the last 3 %K values
self.prev_k = None # %K and %D on the previous candle used
self.prev_d = None
self.reverse_to = None # "long" / "short": open this once the closing trade is gone
def on_bar(self, ctx):
# A tiny candle after the Friday close, or a flat candle (see above): ignore it.
if self.ny.weekday == 4 and self.ny.hour >= 17:
return
high, low, close = ctx.high[0], ctx.low[0], ctx.close[0]
if high <= low:
return
p = ctx.params
# ATR and RSI (both Wilder), on the candles used.
if self.prev_close is None:
true_range = high - low
else:
true_range = max(high - low, abs(high - self.prev_close), abs(low - self.prev_close))
gain = max(close - self.prev_close, 0.0)
loss = max(self.prev_close - close, 0.0)
if self.avg_gain is None:
self.avg_gain, self.avg_loss = gain, loss
else:
self.avg_gain += (gain - self.avg_gain) / p.rsi_period
self.avg_loss += (loss - self.avg_loss) / p.rsi_period
self.moves += 1
self.prev_close = close
self.atr = true_range if self.atr is None else self.atr + (true_range - self.atr) / p.atr_period
self.atr_count += 1
# 200 EMA, on the candles used.
if self.ema is None:
self.ema_seed.append(close)
if len(self.ema_seed) == p.ema_period:
self.ema = sum(self.ema_seed) / p.ema_period
else:
self.ema += (close - self.ema) * 2.0 / (p.ema_period + 1)
# The raw stochastic: of the RSI (standard), or of the price (price_stoch).
raw = None
if p.price_stoch == 1:
self.highs.append(high)
self.lows.append(low)
del self.highs[:-p.stoch_period]
del self.lows[:-p.stoch_period]
if len(self.highs) == p.stoch_period:
hh, ll = max(self.highs), min(self.lows)
raw = 100.0 * (close - ll) / (hh - ll) if hh > ll else 50.0
elif self.moves >= p.rsi_period:
rsi = 100.0 if self.avg_loss == 0 else 100.0 - 100.0 / (1.0 + self.avg_gain / self.avg_loss)
self.rsis.append(rsi)
del self.rsis[:-p.stoch_period]
if len(self.rsis) == p.stoch_period:
top, bottom = max(self.rsis), min(self.rsis)
raw = 100.0 * (rsi - bottom) / (top - bottom) if top > bottom else 0.0
# %K and %D.
k1, d1 = self.prev_k, self.prev_d
k0 = d0 = None
if raw is not None:
self.raw.append(raw)
del self.raw[:-p.k_smooth]
if len(self.raw) == p.k_smooth:
self.slow_k.append(sum(self.raw) / p.k_smooth)
del self.slow_k[:-p.d_period]
k0 = self.slow_k[-1]
if len(self.slow_k) == p.d_period:
d0 = sum(self.slow_k) / p.d_period
self.prev_k, self.prev_d = k0, d0
if (k0 is None or d0 is None or k1 is None or d1 is None
or self.atr_count < p.atr_period or self.ema is None):
return
low_level, high_level = p.oversold, p.overbought
cross_up = k1 <= d1 and k0 > d0 # %K crosses above %D
cross_down = k1 >= d1 and k0 < d0 # %K crosses below %D
if p.leave_zone == 1:
buy_signal = k1 <= low_level < k0 and k0 > d0
sell_signal = k1 >= high_level > k0 and k0 < d0
else:
buy_signal = cross_up and k0 < low_level and d0 < low_level
sell_signal = cross_down and k0 > high_level and d0 > high_level
pos = ctx.position
if pos is not None:
if pos.is_long and cross_down:
ctx.close_position()
self.reverse_to = "short" if sell_signal else None
elif pos.is_short and cross_up:
ctx.close_position()
self.reverse_to = "long" if buy_signal else None
return
# A reversal waits one candle for the old trade to close. Drop it if %K crossed back.
pending, self.reverse_to = self.reverse_to, None
if pending == "long" and k0 > d0:
buy_signal = True
if pending == "short" and k0 < d0:
sell_signal = True
trend = p.trend_filter == 1
entry = close
dist = p.atr_mult * self.atr
if ctx.gate("buy_signal", buy_signal):
if not ctx.gate("above_200_ema", not trend or entry > self.ema):
return
stop = entry - dist
size = ctx.size_by_risk_pct(0.01, stop=stop, entry=entry)
if ctx.gate("trade_size_allowed", size > 0):
ctx.buy(size=size, sl=stop, tag="stoch_rsi_long")
elif ctx.gate("sell_signal", sell_signal):
if not ctx.gate("below_200_ema", not trend or entry < self.ema):
return
stop = entry + dist
size = ctx.size_by_risk_pct(0.01, stop=stop, entry=entry)
if ctx.gate("trade_size_allowed", size > 0):
ctx.sell(size=size, sl=stop, tag="stoch_rsi_short")
Your turn
Test the Stochastic RSI crossover yourself
Change the settings, the market or the stop-loss and see the result in seconds. Ask the BacktestingMax AI: Backtest the Stochastic RSI crossover on EUR/USD, 4-hour chart, and compare it with the same rules on the regular stochastic (14, 3, 3)
.
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 2 November 2026.