Strategies we backtested stochastic crossover (14, 3, 3)

Tested by BacktestingMax

Stochastic oscillator crossover (14, 3, 3) backtest

Does the stochastic oscillator crossover strategy work?

No. In our backtest, the stochastic crossover (14, 3, 3) lost money in 33 of 36 tests with the standard rules, after trading costs. We tested 9 markets from 2019 to 2025 (4 currency pairs, gold, silver and 3 stock indices), each on 15-minute, 1-hour, 4-hour and daily charts. The stochastic oscillator is an indicator that shows where price closed within the range of the last 14 candles, from 0 (the lowest price) to 100 (the highest). %K is this reading averaged over 3 candles, and %D is a slower average of %K. The standard rules buy when %K crosses above %D with both lines below 20 (oversold). They sell short (sell first, to make money if price falls) when %K crosses below %D with both lines above 80 (overbought). A trade closes when %K crosses back over %D or reaches the other zone (80 for a buy, 20 for a sell), or at the stop-loss. All 27 tests on 15-minute, 1-hour and 4-hour charts lost money. On daily charts, 3 of 9 made money, and the best, AUD/USD, grew the account by only 6.2% in 7 years. Why: only about 1 trade in 7 reached the other zone. In 2 trades out of 3, %K crossed back first, and those trades lost money on average. The few big wins did not cover these losses and the stop-losses.

36 backtests 2019–2025 Trading costs included Tested 26 October 2026

Where it worked 36 backtests
Made money
3
of 36 tests, using the standard rules
Made money in both periods
1
2019–2022 and again 2023–2025
Best backtest
+6%
AUD/USD, daily chart: account growth 2019–2025
With a 200 EMA trend filter
1
tests made money in both periods, compared with 1 using the standard rules

Made money in both periods

  • AUD/USD, daily

Lost money on every market

  • 15-minute charts
  • 1-hour charts
  • 4-hour charts

The results

Results on every market

Each box shows one backtest of the stochastic crossover (14, 3, 3) 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 Feb 2020 −53% Lost money −42% Lost money −0.8% Lost money
GBP/USD −100% Lost money. Account down 90% by Dec 2019 −81% Lost money −13% Lost money +3% Made money overall, lost in one period
USD/JPY −100% Lost money. Account down 90% by Feb 2020 −93% Lost money. Account down 90% by Jun 2025 −22% Lost money −12% Lost money
AUD/USD −100% Lost money. Account down 90% by Nov 2019 −93% Lost money. Account down 90% by Jun 2025 −17% Lost money +6% Passed all four checks
Gold −99% Lost money. Account down 90% by Oct 2019 −81% Lost money −34% Lost money −6% Lost money
Silver −99% Lost money. Account down 90% by Mar 2019 −93% Lost money. Account down 90% by Jun 2022 −38% Lost money −2% Lost money
Nasdaq 100 −99% Lost money. Account down 90% by Jan 2020 −77% Lost money −2% Lost money −13% Lost money
S&P 500 −100% Lost money. Account down 90% by May 2021 −58% Lost money −14% Lost money −17% Lost money
DAX −98% Lost money. Account down 90% by May 2022 −79% Lost money −10% Lost money +0.1% Made money overall, lost in one period
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 4,851 30.5% 0.73 −99.6% −99.7% −99.4% −34.4% −99.7% $10,328
EUR/USD 1-hour 2,717 35.1% 0.92 −53.1% −59.1% −35.2% −27.5% −72.0% $7,432
EUR/USD 4-hour 755 32.5% 0.79 −42.3% −44.6% −44.6% +4.3% −53.2% $1,026
EUR/USD daily 132 34.1% 0.98 −0.8% −12.6% +9.1% −9.0% −14.9% $100
GBP/USD 15-minute 4,371 30.5% 0.64 −99.5% −99.6% −99.2% −35.9% −99.6% $6,431
GBP/USD 1-hour 2,880 33.3% 0.86 −81.1% −84.2% −51.1% −61.4% −85.9% $7,027
GBP/USD 4-hour 766 33.6% 0.95 −12.7% −24.3% −4.4% −8.8% −39.4% $1,567
GBP/USD daily 140 35.7% 1.05 +2.6% −10.7% +9.4% −6.3% −13.3% $111
USD/JPY 15-minute 4,596 32.3% 0.71 −99.5% −99.6% −99.4% −13.7% −99.6% $9,818
USD/JPY 1-hour 2,880 32.1% 0.74 −92.7% −92.8% −79.8% −64.0% −94.1% $4,310
USD/JPY 4-hour 794 33.5% 0.90 −22.3% −36.8% −26.5% +5.8% −44.0% $1,165
USD/JPY daily 127 28.3% 0.71 −11.9% −13.2% −4.5% −7.7% −19.3% $75
AUD/USD 15-minute 3,929 29.8% 0.67 −99.6% −99.6% −99.5% −21.1% −99.6% $10,665
AUD/USD 1-hour 3,127 33.1% 0.75 −92.6% −92.7% −80.4% −62.4% −94.0% $5,870
AUD/USD 4-hour 822 34.4% 0.93 −16.5% −33.3% −28.0% +16.0% −38.9% $1,959
AUD/USD daily 136 36% 1.13 +6.2% −7.0% +1.5% +4.6% −12.7% $143
Gold 15-minute 2,664 28.9% 0.58 −98.6% −98.6% −98.4% −12.3% −98.7% $10,098
Gold 1-hour 2,484 34.6% 0.81 −80.6% −82.2% −61.1% −50.0% −84.6% $5,946
Gold 4-hour 748 32.8% 0.83 −34.4% −35.5% −18.0% −19.9% −45.6% $1,258
Gold daily 118 35.6% 0.83 −6.0% −9.2% −1.1% −4.9% −14.5% $75
Silver 15-minute 724 19.1% 0.18 −98.8% −98.8% −98.8% 0.0% −98.8% $9,361
Silver 1-hour 1,259 26.8% 0.43 −93.2% −93.8% −92.2% −12.6% −93.6% $7,060
Silver 4-hour 679 32.5% 0.80 −37.5% −37.8% −19.1% −22.7% −46.2% $3,362
Silver daily 123 30.9% 0.94 −2.2% −7.2% −3.7% +1.6% −13.2% $232
Nasdaq 100 15-minute 4,126 30.5% 0.71 −98.6% −98.6% −98.1% −26.3% −98.8% $8,615
Nasdaq 100 1-hour 2,857 31.8% 0.81 −77.3% −80.7% −71.2% −21.3% −83.5% $3,460
Nasdaq 100 4-hour 850 34.6% 1.00 −1.9% −32.9% +25.4% −21.8% −38.2% $1,252
Nasdaq 100 daily 170 28.2% 0.75 −13.0% −14.6% −8.3% −5.1% −21.0% $66
S&P 500 15-minute 6,814 31.5% 0.83 −99.7% −99.7% −98.9% −71.9% −99.8% $13,547
S&P 500 1-hour 2,865 32.6% 0.89 −58.4% −70.5% −64.1% +15.8% −75.8% $4,325
S&P 500 4-hour 828 32.5% 0.95 −13.9% −26.8% −17.2% +4.0% −41.4% $1,061
S&P 500 daily 169 26.6% 0.71 −16.8% −21.9% −6.5% −11.0% −25.0% $81
DAX 15-minute 8,260 32.8% 0.86 −97.6% −97.8% −91.3% −72.1% −98.4% $8,044
DAX 1-hour 2,806 32.6% 0.87 −78.6% −79.3% −40.7% −64.0% −84.3% $2,764
DAX 4-hour 751 35.4% 0.96 −9.7% −24.8% −5.6% −4.4% −36.6% $554
DAX daily 125 29.6% 1.00 +0.1% −8.0% +5.1% −4.8% −12.9% $33

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

Best test AUD/USD, daily chart +6.2% from 2019 to 2025
Middle test (median): half of the 36 did better, half did worse EUR/USD, 4-hour chart −42.3% from 2019 to 2025

What we found

What the 36 backtests show

  1. All 27 tests on 15-minute, 1-hour and 4-hour charts lost money. Each test started with its own $10,000 account. On 15-minute charts, every account lost more than 97%, and 7 of the 9 were already down 90% by February 2020. On those charts, the spread (the gap between the buy and the sell price) was on average 10.7% of the distance to the stop-loss, and 71% on silver's 15-minute chart. So each trade paid about a tenth of what it risked, just in trading costs. On daily charts, the spread was only 0.8% of that distance. AUD/USD daily was the only test that made money in both 2019–2022 and 2023–2025. It passed all four of our checks (see 'How a test passes' below), with 136 trades, but it grew the account by only 6.2% in 7 years. Our results do not include overnight (swap) fees, which matter most on daily charts.

  2. Most trades closed within a few candles, when %K crossed back over %D. R is 1% of the account when the trade opens: the amount each trade is sized to lose at its stop-loss. Results in R are after trading costs, so −0.16R is a loss of 0.16% of the account. On 1-hour, 4-hour and daily charts, the standard rules made 32,108 trades, and half of them lasted 4 candles or less. 66.0% of them closed at the cross back, and they lost 0.16R on average. Only 15.1% reached the other zone, where they made 1.55R on average. These wins did not cover the cross-back losses and the 18.9% of trades that hit the stop-loss. The same was true in all 36 tests, including the 15-minute charts (see the table below).

  3. Crosses below 20 or above 80 did no better than crosses anywhere else. To check this, we tested a version that takes every cross of %K and %D, with the same exits as the standard rules. In that version, on 1-hour, 4-hour and daily charts, the crosses in the zones lost 0.047R per trade, and the other crosses lost 0.033R per trade. On each of the three charts on its own, the crosses in the zones also lost more (see the comparison below). Taking every cross also meant almost 3 times as many trades as the standard rules. Since the average trade lost money, more trades meant bigger losses.

  4. Holding each trade until %K reached the other zone did not make the average trade better. With this change, a cross back no longer closed the trade. On 1-hour, 4-hour and daily charts, more trades won: 37.3%, compared with 32.9% with the standard rules. But 62.6% of the trades hit the stop-loss, and the average trade was about the same: −0.055R, compared with −0.054R. From 2019 to 2025, 5 of the 36 tests made money with this change, compared with 3 with the standard rules. The best were GBP/USD daily (+14.7%) and AUD/USD daily (+10.4%).

  5. On the 3 stock indices, which rose 132% to 298% from 2019 to 2025, %K was above 80 far more often than below 20, so the rules sold short twice as often as they bought: 7,617 sells and 3,804 buys on 1-hour, 4-hour and daily charts. The sells lost 0.043R per trade, and the buys 0.019R.

How the trades ended

2 trades in 3 closed at the cross back, and on average they lost money

Each row puts together all the trades of the standard rules on one chart, across the 9 markets, from 2019 to 2025. A cross back is when %K crosses below %D during a buy, or above %D during a sell, before %K reaches the other zone. Each cell shows the share of the trades that ended that way, and what they made on average. Results are in R (1% of the account when the trade opened), after trading costs.

Chart Closed at the cross back Reached the other zone (80 or 20) Hit the stop-loss Average trade
15-minute (40,335 trades) 66.5% of trades, −0.21R on average 15.5%, +1.36R 18.0%, −0.98R −0.105R
1-hour (23,875 trades) 65.7%, −0.16R 15.1%, +1.52R 19.1%, −0.98R −0.062R
4-hour (6,993 trades) 66.3%, −0.15R 15.1%, +1.66R 18.6%, −0.97R −0.028R
Daily (1,240 trades) 69.8%, −0.19R 14.8%, +1.52R 15.0%, −0.87R −0.033R

On 15-minute charts, 60% of the trades are from 2019 and 2020, because after that the accounts were too small to take most signals. On daily charts, 4 trades (0.3%) were still open at the end of 2025, and the test closed them then. On daily charts, the trades that hit the stop-loss lost 0.87R on average, less than 1R. This is because on gold, silver, the Nasdaq 100 and the DAX, the trade size was rounded down to a size the market allows.

The 20 and 80 zones

Crosses in the zones did no better than other crosses

This comparison comes from the version that takes every cross of %K and %D, with the same exits as the standard rules. It puts together that version's trades on 1-hour, 4-hour and daily charts, from 2019 to 2025, split by where the two lines were when they crossed. Results are in R (1% of the account when the trade opened), after trading costs.

Crosses with both lines below 20 (buys) or above 80 (sells)
−0.047R
per trade, over 27,391 trades. 33.0% of them made money.
All other crosses
−0.033R
per trade, over 61,285 trades. 41.0% of them made money.

On each chart on its own, the crosses in the zones also did worse. On 1-hour charts, they lost 0.055R per trade, and the other crosses lost 0.042R. On 4-hour charts, they lost 0.028R, and the other crosses 0.010R. On daily charts, they lost 0.026R, and the other crosses made +0.004R. In 2019–2022, the crosses in the zones lost 0.055R per trade and the other crosses lost 0.035R. In 2023–2025, they lost 0.032R and 0.029R. This version took fewer zone crosses than the standard rules (27,391, compared with 32,108 trades), almost all of the difference on 1-hour charts. There, its accounts lost so much that 21,738 signals were too small to trade.

Trade by trade

With every version, the average trade lost money

Each row is one version: the standard rules, or one of the three changes under 'Can the stochastic crossover (14, 3, 3) be improved?' below. Each row puts together all the trades of that version on 1-hour, 4-hour and daily charts: 27 tests 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.

Version Trades Win rate Average winning trade Average losing trade Average trade
Standard rules 32,108 32.9% +0.94R −0.54R −0.054R
Every cross, wherever the lines are 88,676 38.5% +0.62R −0.45R −0.037R
With a 200 EMA trend filter 7,842 33.0% +0.96R −0.57R −0.064R
Hold until the other zone 24,650 37.3% +1.49R −0.98R −0.055R

We leave out the 15-minute charts here, because those accounts lost 90% early and then skipped most signals, a different number in each version (see 'Smallest trade size' further down). 1-hour charts give most of the trades: 23,875 out of 32,108 with the standard rules. With the 200 EMA filter, the average trade was a little worse than with the standard rules on 1-hour charts: −0.075R, compared with −0.062R. On 4-hour charts, it was −0.031R, compared with −0.028R. It was better on daily charts (+0.021R, compared with −0.033R), but on only 248 trades.

The strategy

What the stochastic crossover (14, 3, 3) is

George Lane, an American trader, made the stochastic oscillator popular in the 1950s. It compares each close with the price range of the last 14 candles, on a scale from 0 to 100. A reading of 100 means the candle closed at the highest price of those 14 candles, and 0 means it closed at the lowest. The 14, 3, 3 settings draw two lines. %K is that 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. This version is often called the slow stochastic. 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 waits for the two lines to cross in these zones. It buys when %K crosses above %D with both lines below 20, as a sign that price may stop falling and start to rise. It sells short when %K crosses below %D with both lines above 80.

Stochastic
14, 3, 3, often called the slow stochastic. 14: the range of the last 14 candles. 3: %K is averaged over 3 candles. 3: %D is the average of the last 3 %K values. Levels 20 and 80.
Entry
%K crosses above %D with both lines below 20 (buy), or below %D with both lines above 80 (sell short). The candle where the lines cross is the signal candle. The trade opens at the next candle's open.
Exit
Whichever comes first: %K crosses back over %D, %K reaches the other zone (80 for a buy, 20 for a sell), or the stop-loss
Stop-loss
1.5 × ATR(14) from the signal candle's close. ATR is how far price moves in 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 cross back or the other zone 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: EUR/USD 0.8 pips, GBP/USD 1.2 pips, USD/JPY 0.9 pips, AUD/USD 1.0 pip, gold $0.30 an ounce, silver $0.020 an ounce, the Nasdaq 100 1.5 points, the S&P 500 0.4 points and the DAX 1.0 point. For silver, the Nasdaq 100 and the DAX, we used wider spreads than our backtest engine's own, 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, measured from the signal candle's close to the stop-loss. Two things change the real risk a little. The trade opens at the next candle's open, not at the signal candle's 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 of a dollar or euro 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 1-hour, 4-hour and daily charts, it skipped 1,370 out of the 33,478 signals that came while no trade was open. 1,186 of them were on silver's 1-hour chart, where the account had lost 90% by June 2022. On 15-minute charts, 7 of the 9 accounts had lost 90% by February 2020. After that, most signals were too small to trade, and the test skipped 58,570 out of 98,905.
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 4 hours or less on 1-hour charts. On 4-hour charts, half stayed open 16 hours or less, and on daily charts 6 days or less. On 4-hour and daily charts, a trade was open 29% to 37% of the time. So these fees matter most for the 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. 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

  1. The stochastic (14, 3, 3) is worked out in three steps. First, it measures where the candle closed within the range of the last 14 candles, from 0 (at the lowest price) to 100 (at the highest price). Then %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.
  2. 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. We call this candle the signal candle. The trade opens at the next candle's open.
  3. Sell short when %K crosses below %D and both lines are above 80. The trade opens at the next candle's open.
  4. Close a buy when %K crosses back below %D, or when %K reaches 80 or higher, whichever comes first. Close a sell when %K crosses back above %D, or when %K reaches 20 or lower. The trade closes at the next candle's open.
  5. ATR 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 signal candle's close: below it for a buy, above it for a sell. The stop-loss does not move. If price reaches it, the trade closes at the stop price, or at a worse price if price gaps past it (opens beyond it).
  6. Only one trade is open at a time: a signal that comes while a trade is open is ignored.
  7. 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.
  8. 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 stochastic or the ATR, and they give no signal.

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 crossover (14, 3, 3) be improved?

Not on most tests. We tested three changes, one at a time, on the same 36 tests. Each one changes a different part of the standard rules. The first takes every cross of %K and %D, wherever the two lines are, instead of only crosses below 20 or above 80. The second trades only in the direction of the trend. It buys only when the signal candle closes above the 200 EMA, and sells short only when it closes below it. The third holds each trade until %K reaches the other zone. If you pick the best change on some years and judge it on the same years, it will almost always look good. You picked it because it did well in those years. 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: only crosses with both lines below 20 (buys) or above 80 (sells). 5 of 36middle test −38.0% 7 of 36middle test −12.4% 1 1
Every cross, wherever the lines are Buy every time %K crosses above %D, and sell short every time it crosses below, wherever the two lines are. The exits stay the same. So a cross back closes the trade and also opens a trade the other way, one candle later, once the old trade has closed. 5 of 36middle test −58.3% 4 of 36middle test −10.1% 1 0
With a 200 EMA trend filterBest on 2019–2022 The 200 EMA is a moving average of the last 200 closing prices that gives more weight to recent candles. Only buy when the signal candle closes above the 200 EMA, and only sell short when it closes below it. The 200 EMA needs 200 candles, so on daily charts this version could not trade before about October 2019. 11 of 36middle test −8.8% 9 of 36middle test −7.5% 1 1
Hold until the other zone Ignore the cross back. Close a buy only when %K reaches 80, and a sell only when %K reaches 20, or at the stop-loss. The entries and the stop-loss stay the same. 4 of 36middle test −30.6% 8 of 36middle test −17.6% 2 0

The 200 EMA trend filter did best in 2019–2022: 11 of 36 tests made money with it, compared with 5 with the standard rules. But 8 of those 11 were daily tests with only 16 to 38 trades from 2019 to 2025, fewer than the 100 we need to judge a test. In 2019–2022, those 8 daily tests made only +0.2% to +3.4%. In 2023–2025, 9 of 36 tests made money with the filter, compared with 7 with the standard rules. With the filter, only one test with at least 100 trades made money in both periods: the Nasdaq 100 on the 4-hour chart. It made +33.0% from 2019 to 2025, compared with a loss of 1.9% with the standard rules, and it passed all four of our checks. That is 1 test out of 36, so it could be chance. For comparison, the Nasdaq 100 itself rose 298% in these years. With the filter, each trade lost a little more on average: −0.064R, compared with −0.054R, on 1-hour, 4-hour and daily charts. But the filter made 75% fewer trades, so in 32 of 36 tests the result from 2019 to 2025 was better than with the standard rules. Holding until the other zone made money in both periods on 2 tests (GBP/USD and AUD/USD, daily). Taking every cross made money in both periods on 1 test (gold, daily). So none of the three changes made the stochastic crossover make money on most tests.

Passed all four checks with a 200 EMA trend filter

  • Nasdaq 100, 4-hour

Questions

Questions traders ask

Does the stochastic crossover strategy work?

No, not in our backtest. From 2019 to 2025, after trading costs, the 14, 3, 3 crossover lost money in 33 of 36 tests: 9 markets, each on 15-minute, 1-hour, 4-hour and daily charts. The stochastic draws two lines, %K and its slower average %D, on a scale from 0 to 100. The standard rules buy when %K crosses above %D with both lines below 20, and sell short when %K crosses below %D with both lines above 80. Only 3 tests made money, all on daily charts. The best, AUD/USD, grew the account by 6.2% in 7 years, and it was the only test that made money in both 2019–2022 and 2023–2025.

What is the best timeframe for the stochastic crossover?

No timeframe made money on most markets in our test. All 27 tests on 15-minute, 1-hour and 4-hour charts lost money. Daily charts had the best results: 3 of 9 tests made money, and the middle daily test (half did better, half did worse) lost 2.2% in 7 years. The middle 4-hour test lost 16.5%. Daily charts made the fewest trades, 118 to 170 per market. Their trading cost (the spread) was on average 0.8% of the distance to the stop-loss, compared with 10.7% on 15-minute charts. Per trade, 4-hour charts lost slightly less than daily charts: 0.028R, compared with 0.033R (R is 1% of the account when the trade opens).

Should you only trade stochastic crosses below 20 and above 80?

No. In our test, waiting for crosses below 20 or above 80 did not help. R is 1% of the account when the trade opens: the amount each trade is sized to lose at its stop-loss. We tested a version that takes every cross of %K and %D, with the same exits as the standard rules. On 1-hour, 4-hour and daily charts, its crosses in the zones lost 0.047R per trade, and its other crosses lost 0.033R. But it made almost 3 times as many trades as the standard rules, so its total losses were bigger. On 1-hour charts, all 9 of its accounts lost between 89.5% and 98.9%.

Should you close a stochastic trade when the lines cross back?

Closing at the cross back made little difference in our test. It kept each loss small, but the strategy still lost money. R is 1% of the account when the trade opens: the amount each trade is sized to lose at its stop-loss. With the standard rules, 66.0% of the trades on 1-hour, 4-hour and daily charts closed at the cross back, and they lost 0.16R on average. When we held each trade until %K reached the other zone (80 for a buy, 20 for a sell), 62.6% of the trades hit the stop-loss instead. The average trade was about the same either way: −0.054R when closing at the cross back, and −0.055R when holding.

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 StochasticCrossover1433(Strategy):
    """The stochastic oscillator crossover (14/3/3, levels 20 and 80), as most traders learn
    it, plus three changes traders often make.
    The stochastic is worked out here, on the candles the strategy uses (see "Skipped candles"):
      raw %K = 100 x (close - lowest low of the last 14 candles)
                   / (highest high of the last 14 candles - lowest low of the last 14 candles)
      %K     = the average of the last 3 raw %K values (the "slow" %K)
      %D     = the average of the last 3 %K values (the signal line)
    This is the slow stochastic that charting platforms show as 14, 3, 3.
    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, or when %K closes at 80 or higher, whichever
      comes first. Close a sell when %K crosses above %D, or when %K closes at 20 or lower.
      Entries and these exits fill at the next candle's open.
      Stop-loss 1.5 x ATR(14) from the signal candle's close. It does not move.
      Size: 1% of the account lost at the stop. One trade at a time; a signal that comes
      while a trade is open is ignored.
    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
    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:
      any_cross    = 1  take every cross of %K and %D, wherever the two lines are. The exits
                        stay the same, so a cross the other way closes the trade and opens the
                        opposite one, one candle later, once the old trade has closed
      trend_filter = 1  only buy when the signal candle closes above the 200 EMA, only sell
                        short when it closes below it
      zone_exit    = 1  hold until the other zone: close a buy only when %K reaches 80, and a
                        sell only when %K reaches 20 (or at the stop-loss). A cross the other
                        way no longer closes the trade
    """
    params = {"k_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),
              "any_cross": Param(type=int, default=0, min=0, max=1),
              "trend_filter": Param(type=int, default=0, min=0, max=1),
              "zone_exit": Param(type=int, default=0, min=0, max=1)}
    lookback = 2
    def init(self, ctx):
        self.ny = ctx.clock("America/New_York")
        self.highs = []          # highs and lows of the last k_period candles used
        self.lows = []
        self.raw_k = []          # the last k_smooth raw %K values
        self.slow_k = []         # the last d_period %K values
        self.prev_k = None       # %K and %D on the previous candle used
        self.prev_d = None
        self.prev_close = None
        self.atr = None          # Wilder's average of the true range, as the built-in ATR
        self.atr_count = 0
        self.ema = None          # the 200 EMA, started from the average of the first 200 closes
        self.ema_seed = []
        self.reverse_to = None   # any_cross: "long" / "short", 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 (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))
        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 stochastic 14, 3, 3.
        self.highs.append(high)
        self.lows.append(low)
        del self.highs[:-p.k_period]
        del self.lows[:-p.k_period]
        k1, d1 = self.prev_k, self.prev_d
        k0 = d0 = None
        if len(self.highs) == p.k_period:
            hh, ll = max(self.highs), min(self.lows)
            self.raw_k.append(100.0 * (close - ll) / (hh - ll))
            del self.raw_k[:-p.k_smooth]
            if len(self.raw_k) == p.k_smooth:
                self.slow_k.append(sum(self.raw_k) / 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:
            return
        cross_up = k1 <= d1 and k0 > d0      # %K crosses above %D
        cross_down = k1 >= d1 and k0 < d0    # %K crosses below %D
        pos = ctx.position
        if pos is not None:
            if pos.is_long:
                if k0 >= p.overbought or (p.zone_exit == 0 and cross_down):
                    ctx.close_position()
                    if p.any_cross == 1 and cross_down:
                        self.reverse_to = "short"
            else:
                if k0 <= p.oversold or (p.zone_exit == 0 and cross_up):
                    ctx.close_position()
                    if p.any_cross == 1 and cross_up:
                        self.reverse_to = "long"
            return
        # any_cross: a reversal waits one candle for the old trade to close. Drop it if the
        # lines crossed back.
        pending, self.reverse_to = self.reverse_to, None
        if pending == "long" and k0 > d0:
            cross_up = True
        if pending == "short" and k0 < d0:
            cross_down = True
        if p.any_cross == 1:
            long_zone, short_zone = True, True
        else:
            long_zone = k0 < p.oversold and d0 < p.oversold
            short_zone = k0 > p.overbought and d0 > p.overbought
        trend = p.trend_filter == 1
        if trend and self.ema is None:
            return
        entry = close
        dist = p.atr_mult * self.atr
        if ctx.gate("k_crosses_above_d", cross_up) and ctx.gate("both_lines_oversold", long_zone):
            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_long")
        elif ctx.gate("k_crosses_below_d", cross_down) and ctx.gate("both_lines_overbought", short_zone):
            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_short")

Your turn

Test the stochastic crossover (14, 3, 3) yourself

Change the settings, the market or the stop-loss and see the result in seconds. Ask the BacktestingMax AI: Backtest the stochastic crossover (14, 3, 3) on GBP/USD, daily chart, and compare closing at the cross back with holding until %K reaches the other zone.

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 26 October 2026.