Schaff Trend Cycle (STC): The MACD-Stochastic Hybrid That Cuts Lag by 30-40% for Futures Traders
Overview #
The Schaff Trend Cycle (STC) is a momentum oscillator created by Doug Schaff in 1999 that solves a problem most traders encounter the hard way: the MACD is slow and unbounded, the stochastic is fast but noisy, and neither by itself gives you a clean, actionable trend signal.
Schaff's insight was to run a MACD line through a double stochastic algorithm — applying two successive stochastic normalizations to the MACD output and smoothing the result. What comes out is a bounded oscillator from 0 to 100 that identifies trend direction 30--40% faster than the raw MACD, with less noise than a standalone stochastic.
The default parameters — 23-period fast EMA, 50-period slow EMA, 10-period cycle length — were designed for the forex and futures markets and have held up well on 5-minute charts across ES, NQ, CL, and GC. The signal rules are simple: the STC crossing above 25 signals a bullish trend turn, crossing below 75 signals a bearish turn. But like any single indicator, the STC earns its keep only when combined with a trend filter and placed within a disciplined risk management framework.
@kiasom on NexusFi was among the first to share the original EasyLanguage STC code:
@"The STC has several benefits compared to its component indicators. It produces less whipsaw and fewer false signals than the MACD or Price Cycle oscillators. By combining the two, Schaff created an indicator that is more accurate and more adaptive than either original indicator is by itself."
How STC Is Calculated #
The STC computation follows six steps. Understanding them is worth the five minutes — it tells you exactly why the indicator behaves the way it does, and why it can pin at 0 or 100 in strong trends.
Start with two exponential moving averages of the close: a fast EMA (default 23 periods) and a slow EMA (default 50 periods). The MACD line is simply the difference:
MACD = EMA(close, 23) − EMA(close, 50)
This is identical to the first step in any MACD calculation. The difference from the standard MACD is everything that comes next.
Take the MACD line and apply a stochastic normalization over a lookback window (default 10 bars). This positions the current MACD reading within its recent range:
%K₁ = 100 × (MACD − Lowest(MACD, 10)) / (Highest(MACD, 10) − Lowest(MACD, 10))
This is the key step that makes the STC cycle-aware. The stochastic transforms an unbounded MACD value into a 0--100 reading relative to the most recent 10 bars of MACD activity. When the MACD is at a 10-bar high, %K₁ hits 100. At a 10-bar low, it hits 0.
Apply an EMA to %K₁ to reduce noise:
%D₁ = EMA(%K₁, 3)
Apply the same stochastic normalization to the smoothed %D₁ over the same 10-bar window:
%K₂ = 100 × (%D₁ − Lowest(%D₁, 10)) / (Highest(%D₁, 10) − Lowest(%D₁, 10))
This second pass removes more oscillation noise and creates the characteristic "flat-top, flat-bottom" behavior that distinguishes the STC from raw MACD. In strong trends, %D₁ itself reaches its own local extremes, and the second stochastic pins the output at 0 or 100.
Steps 5--6: Final smoothing
Apply a final EMA smoothing to produce the STC line:
STC = EMA(%K₂, 3)
Output range: 0 to 100. The double stochastic transformation is what keeps the STC bounded regardless of instrument volatility. A crude oil chart with $3 daily ranges produces the same 0--100 oscillator output as a Treasury bond chart with a few ticks of daily range. This makes STC more easily compared across contracts than raw MACD.
A note on platform implementations: the smoothing factor (typically 3, applied as an EMA) is sometimes implemented differently across platforms. Before relying on 25/75 crossovers in live trading, verify your platform's STC output against a known reference on historical data. @Tiberius documented exactly this kind of implementation investigation in the NexusFi thread "Getting the Schaff... Trading Methods" (2012, 22 thanks), which became one of the community's go-to references for understanding STC in practice.
Signal Interpretation #
The STC oscillates between 0 and 100. Reading it correctly means understanding both the threshold signals and the zone dynamics.
The four zones
Overbought zone (75--100): The bullish cycle phase is extended. Don't initiate new longs; instead, tighten stops on existing positions and prepare for the potential reversal. When the STC crosses back below 75, that's the sell signal. Critically: in strong uptrends, the STC can stay pinned at 100 for 10--20+ bars. Don't short it just because it looks "high."
Bullish momentum (50--75): The trend is confirmed up. Hold longs, trail stops below swing lows. The crossing of 50 from below confirms the trend regime shift from bearish to bullish.
Bearish momentum (25--50): The trend is confirmed down. Hold shorts, trail stops above swing highs. Watch for divergence here — if price is making new lows but STC is rising within this zone, momentum is thinning and a reversal may follow.
Oversold zone (0--25): The bearish cycle is extended. Don't initiate new shorts; tighten stops on existing short positions. STC crossing back above 25 is the buy signal. Same pin-at-0 warning applies in strong downtrends.
Buy and sell signals
The standard entry triggers are:
Buy signal: STC crosses from below 25 to above 25. This marks the moment the MACD's double-stochastic reading escapes the oversold zone — the cycle is turning from bearish to bullish. Enter long on the close of the crossover bar or the next bar's open, with a stop below the recent swing low.
Sell signal: STC crosses from above 75 to below 75. The overbought cycle is losing momentum. Enter short on close or next open, stop above recent swing high.
Some traders also use the 50-level as a confirmation filter: only take buy signals when STC is above 50 (trend confirmed), only take sell signals when below 50. This reduces total signal count but increases the quality of what remains.
STC vs MACD #
Comparing the STC to the standard MACD on the same chart tells the story quickly. The MACD is useful, but it has three structural problems for futures day trading:
Unbounded output: The MACD value on an ES chart might be +8 on a strong day and +2 on a quiet day. There's no "this is overbought" level you can point to. You're comparing the current reading to the recent average, which requires constant recalibration.
Lag: Because MACD is built from two EMAs and the signal line is an EMA of the MACD, you're looking at three layers of exponential smoothing. A trend change on the 5-minute chart often doesn't produce a MACD crossover for another 4--8 bars.
Range-market drift: In sideways sessions, the MACD oscillates near zero without clear direction. The STC's stochastic transform forces a full 0--100 range even within narrow price bands, which makes the oscillator more readable when the market is ranging.
The STC addresses all three: the double stochastic creates a consistent 0--100 range, the cycle normalization speeds up the response relative to a standard MACD, and the bounded output makes threshold-based trading rules simple to define and test.
The tradeoff is that the same double smoothing that reduces noise can also create slight artificiality — the flat tops and bottoms at 0 and 100 are mathematical constraints, not direct reflections of price action. Experienced NexusFi members like @Fat Tails have noted this in discussions of market internals and oscillator construction: bounded oscillators that compress signal at extremes need to be paired with price structure, not used in isolation.
Trading Strategies #
The STC works as a timing tool within a structured plan. Used alone, it's just another oscillator. Paired with a trend filter, it becomes genuinely useful.
Strategy 1: Trend-filtered cycle turn (primary)
This is the bread-and-butter application for ES and NQ day traders.
Setup: 5-minute chart, STC (23/50/10), VWAP or 20-period EMA as trend filter, ADX optional (≥25 adds filtering power).
Long entry: Price above VWAP AND STC crosses above 25 from below. Stop below the most recent swing low. Target: 1.5× ATR(14) or STC reaching 75, whichever comes first. Exit if STC crosses back below 50.
Short entry: Price below VWAP AND STC crosses below 75 from above. Stop above recent swing high. Mirror target and exit rules.
The VWAP filter is the most important element. Without it, you're taking STC signals in both directions regardless of whether the session is trending or choppy — and that's where accounts bleed.
Strategy 2: Multi-timeframe alignment
This approach uses two STC periods: the 30-minute chart defines the trade direction, the 5-minute chart times the entry.
Filter (30-min): If the 30-minute STC is above 50, you're in bullish territory for the session — take only long signals on the 5-minute. If below 50, take only shorts. When the 30-minute STC is between 45--55, consider standing aside — the trend is ambiguous.
Entry (5-min): Apply the standard 25/75 crossover rules, but only in the direction allowed by the 30-minute filter. This two-layer approach cuts false signals by roughly 40--50% in backtests versus using the 5-minute STC alone.
Exit: Trail stop with 1.5× ATR, close the position when the higher-timeframe STC crosses back through 50. This keeps you in the trade while the 30-minute trend persists.
Structural logic: Every 5-minute signal exists within a 30-minute context. When the 30-minute STC is below 50, taking a 5-minute long means fighting a confirmed larger-frame downtrend — signal quality drops much. Keep two chart windows open, or use a multi-timeframe indicator that plots the 30-minute STC on your 5-minute chart. Check the state before each entry. For CL and GC swing traders, a three-timeframe approach (daily for multi-day bias, 30-minute for session, 5-minute for entry) suits holds of hours rather than intraday scalps.
Strategy 3: Divergence setup
Divergence is one of the STC's most powerful setups — especially for recognizing when a trend is losing its momentum before price confirms it.
Bearish divergence: Price makes a higher high, but STC makes a lower high. This means the MACD's underlying momentum has weakened even as price pushed higher. The trigger is when STC subsequently crosses below 75. Enter short with stop above the price high that formed the divergence.
Bullish divergence: Price makes a lower low, STC makes a higher low. Momentum is building. Trigger: STC crosses above 25. Stop below the price low.
Divergence setups work best in the context of structure — look for them at known resistance (for bearish) or support (for bullish) levels, not in the middle of a range. @Tiberius's trading setup in the Schaff thread used exactly this combination: STC state with price action context, watching for the moment "as the RMI breaks above 70 when above 70, a green triangle is just below the price bar" — structure confirmation before acting on the signal.
Quality filters: Best setups occur at structural levels (prior support/resistance, VWAP, prior day high/low). Require STC peaks separated by 5+ points; divergence spanning at least 5 bars; ADX or volume confirming. The STC's double stochastic normalization makes divergence more visible than on raw MACD — the bounded 0-100 output forces peak comparison into a consistent range. Weak divergences — barely separated peaks, mid-range price location — consistently underperform and should be filtered out.
Strategy 4: Range mean-reversion (confirmed range only)
In genuine range-bound sessions (ADX < 20, or price oscillating between two known levels), you can fade the STC extremes directly:
Long: Near support when STC crosses up through 25. Target: midrange or VWAP. Stop: below support.
Short: Near resistance when STC crosses down through 75. Target: midrange. Stop: above resistance.
The critical discipline: if ADX rises above 25 while you're in this trade, the range is breaking and the mean-reversion is invalidated. Exit immediately.
Parameter Selection #
The 23/50/10 defaults were not chosen arbitrarily. The 50-period slow EMA provides the base trend reference, the 23-period fast EMA captures short-term price movement, and the 10-period cycle window normalizes the MACD across its recent range. The ratio of approximately 1:2 between fast and slow EMAs creates the right balance of sensitivity to noise.
Timeframe scaling rules
1-minute charts: Reduce to 12/26/5-7. The higher bar frequency means the default 50-period EMA spans too many hours; you need a shorter cycle to respond within the session. Expect more false signals — use tighter VWAP confirmation and reduce position size.
5-minute charts: The 23/50/10 default is the starting point for most ES and NQ traders. Verify on at least 60 days of out-of-sample data before modifying.
15-minute charts: 23-26/50-52/12-14 works well. The slightly longer cycle smooths out the session's natural mid-morning lull that can produce false crossovers on the 5-minute.
30-minute to 1-hour: Use 34/55/14-20. The longer EMAs track multi-session trends rather than intraday cycles. This is appropriate for CL and GC traders who are holding positions for hours rather than minutes.
Contract-specific considerations
ES (E-Mini S&P 500): The most liquid futures market; 5-minute 23/50/10 works well. Opening range (first 30 minutes) is noisier — consider standing aside or requiring additional confirmation until 10am Central.
NQ (E-Mini Nasdaq 100): Higher intraday volatility than ES. Consider tightening stops to 0.5× ATR rather than the standard 1.5× for the target. The STC default parameters work but expect more intrabar STC volatility — require bar-close confirmation before entering.
CL (Crude Oil): News-driven market with frequent gap moves. Pair STC with OBV or volume SMA for confirmation. The 15-minute STC (23/50/12) is often more reliable than 5-minute for CL. ATR-based stops are essential.
GC (Gold): Cyclical intraday behavior that suits the STC well. Use 30-minute STC for swing entries. High-impact news (CPI, NFP, Fed) can override any indicator signal — stand aside or widen stops much in the 30 minutes around these releases.
STC in Choppy Markets #
The STC's biggest failure mode is a choppy, range-bound session. When price is oscillating without direction, the STC generates crossovers through 25 and 75 repeatedly. These look like valid signals but have no follow-through. Each one costs a few ticks and some slippage.
The solution isn't to abandon the STC in ranging conditions — it's to add a regime filter that tells you which mode the market is in before you look at the STC signal.
ADX filter: ADX below 20--25 signals a non-trending market. When ADX is low, either skip STC signals entirely or switch to the mean-reversion range strategy described earlier. ADX above 25 with rising slope: proceed with trend-following STC signals.
Bollinger Band width: Narrow band width (price compressing) followed by band expansion often signals the beginning of a trend move. STC signals taken when Bollinger Bands are expanding from a squeeze have higher follow-through than signals taken in wide, volatile bands.
Higher-timeframe confirmation: If the 30-minute STC is flat near 50 (the ambiguous zone), the session may not have established a clear bias. Standing aside or waiting for the 30-minute to commit in one direction before taking 5-minute signals filters out a large percentage of choppy-session noise.
@Inletcap's observations in the Scalper's Journal thread on NexusFi — about using dynamic threshold oscillators "for context" rather than as standalone signals — capture this principle well: context is everything. The oscillator's state matters less than the market environment in which that state is occurring.
Platform Implementation #
TradingView (Pine Script v5)
TradingView includes a built-in STC in its standard library — search "Schaff Trend Cycle" in the indicators panel. For Pine Script v5 custom implementation: MACD = ta.ema(close,23) - ta.ema(close,50), two successive stochastic normalizations over 10 bars, each followed by a 3-period EMA smooth. Output: bounded 0-100. Verify against TradingView's native STC before trusting any custom version.
NinjaTrader 8
NinjaTrader has community-contributed STC indicators available on the NinjaTrader ecosystem forums. In the NexusFi thread started by @Tiberius, members specifically referenced the ZiSchaffTrendCycle indicator: "I discovered this indicator here in a nexusfi.com (formerly BMT) thread and found the Schaff on the NinjaTrader support forum for download."
For custom NinjaScript implementation, the core logic follows the same steps as above. Key implementation checks:
Use the EMA() function for all smoothing. Apply MAX(series, cycleLen) and MIN(series, cycleLen) for the stochastic high/low lookbacks. The output should be a double value in the range 0--100.
After coding, run the indicator on a test chart and compare it against the TradingView version on the same data. Small implementation differences in smoothing can shift the 25/75 crossover timing by 1--2 bars — not catastrophic, but worth checking before live deployment.
Session-aware implementation
For futures markets with defined trading sessions (ES, NQ, CL), consider resetting the STC calculation at the start of each session. This prevents carry-over of the previous session's momentum state from distorting early-session readings. Most modern indicator implementations in NinjaTrader and TradingView support session-based resets through the IsFirstTickOfBar logic or equivalent.
Risk Management #
The STC is a timing tool. Risk management is the framework that determines whether that timing generates a positive expectancy over hundreds of trades.
Stop placement
Never place stops at STC levels. The oscillator can whipsaw across 25 or 50 multiple times on the same bar sequence without any meaningful price movement. Price structure — swing lows for longs, swing highs for shorts — is the only reliable stop reference.
For a long entered on an STC 25 crossover: identify the most recent swing low that formed before the entry signal. Place the stop 1--2 ticks below it. This is your risk. If the risk is too large for your position size, skip the trade.
Position sizing
Risk 0.5--1% of account equity per trade. For a $50,000 account, that's $250--$500 per trade. ES has a tick value of $12.50. A 4-tick ($50) stop means you can trade 5--10 contracts at 1% risk. A wider 12-tick ($150) stop means 1--3 contracts at the same risk percentage.
Most ES day traders find that keeping stops to 4--8 ticks is practical for STC-based entries, which typically enter near swing lows/highs where price structure is compressed.
Target selection
Two common approaches:
ATR-based: Target = entry price + 1.5× ATR(14). This adapts automatically to changing volatility conditions — narrow sessions produce smaller targets, wide sessions produce larger ones. Take 50% off at the ATR target, trail the rest.
STC-based: Take 50% off when STC reaches 60--70 (for a long from 25), trail the rest until STC crosses back through 50. This keeps you in the trade while momentum persists but exits when it starts to fade.
Either approach produces acceptable results. The ATR approach is simpler and less chart-dependent. The STC approach maximizes runners in trending sessions but exits faster in choppy ones.
Correlation management
ES, NQ, and ZN are correlated instruments. Running STC signals simultaneously on all three doesn't multiply your edge — it concentrates your risk. If all three give bullish STC crossovers at the same time, that's one macro trade expressed three ways, not three independent trades. Cap total exposure to 2--3 contracts across correlated instruments.
Common Mistakes #
Most STC failures come from one of five predictable mistakes:
Using STC without a trend filter: The oscillator generates 6--12 crossovers per session on a 5-minute chart. Without a VWAP or higher-timeframe filter, you're taking all of them. Trending sessions produce 2--3 clean signals; choppy sessions produce 8--10 losing ones. The filter separates the two.
Over-optimizing parameters: Back-testing 2,000 parameter combinations on 6 months of ES data until you find the one that produces a Sharpe of 2.4 is not research — it's data mining. The 23/50/10 defaults exist for a reason: they've survived across instruments and market regimes without being specifically optimized for any of them. Start there. Modify only if you have a structural reason (very short or very long timeframe) and validate out-of-sample.
Placing stops at STC levels: "Exit if STC crosses back through 50" sounds clean but creates a stop placement with no relationship to actual price structure. The STC can cross 50 due to a single volatile bar followed immediately by a reversal. Stops at swing lows/highs keep you in the trade through normal oscillation.
Shorting pinned extremes in trending markets: When STC is at 95 in a strong uptrend, the instinct is "it has to come down soon." It doesn't. The double stochastic pins the output at 100 specifically when the underlying MACD is at a 10-bar extreme — which is exactly when the trend is strongest. Trading against a pinned STC is one of the fastest ways to lose in a trending session.
Platform discrepancies: Two "STC 23/50/10" implementations can produce different outputs. Verify against a reference source before live trading.
Summary #
The Schaff Trend Cycle solves a real problem in futures trading: the MACD is useful but slow and unbounded; the stochastic is fast but noisy. By running the MACD through a double stochastic algorithm and smoothing the result, Schaff created an indicator that gives actionable, bounded trend signals roughly 30--40% faster than the raw MACD — without the noise that makes standalone stochastics difficult to trade.
The default parameters (23/50/10) work well on 5-minute futures charts across ES, NQ, CL, and GC. The core signals are straightforward: cross above 25 is bullish, cross below 75 is bearish. The four zones — overbought, bullish momentum, bearish momentum, oversold — provide a continuous regime reading, not just binary entry/exit signals.
But the STC's value comes from how you use it, not from the indicator itself. As a standalone oscillator, it will generate losses in choppy sessions. Paired with a VWAP trend filter and a higher-timeframe confirmation, it becomes a precision timing tool. Risk management — stops at price structure, fixed-percentage position sizing, minimum 1.5:1 R:R before entry — converts that timing into positive expectancy over time.
The NexusFi community's experience with the STC spans nearly 15 years, from @kiasom's early EasyLanguage code in 2010 to @Tiberius's detailed trading methodology threads. That history provides exactly the kind of practitioner perspective that transforms academic indicator descriptions into working trading tools: what parameters actually hold up in different market conditions, where the indicator fails, how to combine it with price action. Use those threads as a supplement to the structural understanding here.
Knowledge Map
Prerequisites
Understand these firstGo Deeper
Build on this knowledgeReferences This Article
Articles that build on this topicCitations
- — Schaff (2010) 👍 6
- — Getting the Schaff .... Trading Methods (2012) 👍 22
- — Getting the Schaff .... Trading Methods (2012) 👍 7
- — The Scalper's Journey (2016) 👍 11
- — Market Internals (2010) 👍 8
- — Schaff (2011) 👍 3
- — Lean, Mean Trading Machine (2012) 👍 4
- — Gold, Silver and Dow-Important Levels Reached (2013) 👍 4
- — Schaff Trend Cycle STC Settings and Rules (2024)
- — SchaffTrendCycle -- thinkorswim Reference (2024)
