0bps

Strategy vault / Trend following

EMA Tracking Trend Suppressing Oscillation Strategy

This strategy combines the advantages of three indicators: EMA, Trend Tracking Strategy (TTS) and Schaff Trend Cycle (STC) to form a strong short-term trend tracking strategy. Specifically, the strategy will judge…

Author
ChaoZhang
Complexity
Intermediate · 118 lines
Parameters
7
Backtest bar
1d · swing
Tested on
BTC/USDT · futures

IMG

Overview

This strategy combines the advantages of three indicators: EMA, Trend Tracking Strategy (TTS) and Schaff Trend Cycle (STC) to form a strong short-term trend tracking strategy. Specifically, the strategy will judge whether the buy and sell signals of the three indicators are consistent. If they are consistent, trading signals will be generated; otherwise no trades will be made. This filters out some false signals and makes the strategy more reliable.

Strategy Principle

The strategy consists of three main parts: EMA indicator, TTS trend tracking strategy and STC indicator.

Firstly, the 200-period EMA exponential moving average line is calculated. If the price is below this EMA line, the EMA indicator gives a sell signal: -1; if the price is above the line, the EMA indicator gives a buy signal: 1.

Secondly, the relevant parameters of the TTS trend tracking strategy are calculated. According to the price breakouts of the upper and lower rails, the market trend direction is determined. If the price breaks through the upper rail, a buy signal 1 is generated; if the price breaks through the lower rail, a sell signal -1 is generated.

Finally, the Schaff Trend Cycle (STC) indicator is calculated, which reflects the change trend of the price consolidation. If the STC indicator rises, it generates a buy signal 1; if the STC indicator falls, it generates a sell signal -1.

After obtaining the judgment signals from the three indicators, the strategy will determine whether they are consistent. Only when all three indicator judgment signals are consistent will actual trading signals be generated. This can effectively filter out some false signals and make the strategy more reliable.

Once determining to generate trading signals, long or short positions will be opened and stop-profit/stop-loss points will be set.

Advantages

  1. The strategy combines three different types of indicators to effectively determine market trend direction.

  2. Using the consistency of judgment signals from three indicators to filter out false signals can reduce unnecessary trades and make the strategy more reliable.

  3. Setting reasonable stop-profit/stop-loss points can lock in profits and prevent losses from expanding.

  4. The optimized parameters are suitable for most stocks and forex products.

  5. Simple and easy-to-understand trading logic.

Risks

  1. Inconsistency between indicator judgments may cause loss of trading opportunities. Judgment rules can be further optimized.

  2. STC indicator is sensitive to parameters. Different products need parameter tuning.

  3. In downtrends, stop loss may be penetrated, causing huge losses. Adaptive stop loss can be considered.

  4. Sideway consolidations cannot be effectively identified, leading to trap positions.

Enhancements

  1. Test more indicator combinations to find stronger judgment rules, e.g. adding RSI indicator.

  2. Optimize STC parameters for better adaptation across different products. Add adaptive parameter optimization module.

  3. Increase adaptive stop loss module to optimize stop loss points dynamically.

  4. Enhance position closing module to identify sideway ranges and avoid traps.

  5. Optimize algorithms for high frequency trading, reducing latency and improving order fulfillment rates.

Conclusion

The strategy combines EMA, TTS and STC indicators to determine market direction, with consistent judgments from all three triggering trades, effectively filtering out false signals. There is still large room for optimizations, e.g. testing more indicator combinations, adding adaptive algorithms, optimizing high frequency trading modules, etc, to further strengthen trend tracking capability. Compared to traditional strategies simply following moving averages, this strategy can judge markets more intelligently, capture trends while avoiding traps.

Parameters

NameDefaultWhat it controls
v_input_float_10.1(?Strategy)Profit %
v_input_int_121(?Trend Trader Strategy)Length
v_input_float_23Multiplier
v_input_int_212(?Schaff Trend Cycle)Length
v_input_int_326FastLength
v_input_int_450SlowLength
v_input_float_30.5AAA

Source Pine Script

/*backtest
start: 2022-12-05 00:00:00
end: 2023-04-14 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ajahanbin1374

//@version=5
strategy(title = "EMA + TTS + STC", shorttitle = "EMA + TTS + STC", overlay = true, calc_on_order_fills=false, calc_on_every_tick = false, initial_capital = 100, default_qty_type = strategy.percent_of_equity, default_qty_value = 100, commission_type = strategy.commission.percent, commission_value = 0.01)

////////////////////////////////////////////////////////////
// Strategy entry
////////////////////////////////////////////////////////////
profit = input.float(defval = 0.1, minval = 0.0, title="Profit %", step=0.01, group = "Strategy") * 0.01

////////////////////////////////////////////////////////////
// Emponential Moving Average
////////////////////////////////////////////////////////////
ema = ta.ema(close, 200)
posEma = close < ema ? -1 : 1

////////////////////////////////////////////////////////////
// Trend Trader Strategy
////////////////////////////////////////////////////////////
Length = input.int(21, minval=1, group="Trend Trader Strategy")
Multiplier = input.float(3, minval=0.000001, group="Trend Trader Strategy")
avgTR = ta.wma(ta.atr(1), Length)
highestC = ta.highest(Length)
lowestC = ta.lowest(Length)
hiLimit = highestC[1] - avgTR[1] * Multiplier
loLimit = lowestC[1] + avgTR[1] * Multiplier
ret = 0.0
posTts = 0.0
ret:= close > hiLimit and close > loLimit ? hiLimit :
         close < loLimit and close < hiLimit ? loLimit : nz(ret[1], close)
posTts:=  close > ret ? 1 :close < ret ? -1 : nz(posTts[1], 0)


////////////////////////////////////////////////////////////
// Schaff Trend Cycle (STC)
////////////////////////////////////////////////////////////
EEEEEE = input.int(12, 'Length', group ="Schaff Trend Cycle")
BBBB = input.int(26, 'FastLength', group ="Schaff Trend Cycle")
BBBBB = input.int(50, 'SlowLength', group ="Schaff Trend Cycle")

AAAA(BBB, BBBB, BBBBB) =>
    fastMA = ta.ema(BBB, BBBB)
    slowMA = ta.ema(BBB, BBBBB)
    AAAA = fastMA - slowMA
    AAAA

AAAAA(EEEEEE, BBBB, BBBBB) =>
    AAA = input.float(0.5, group ="Schaff Trend Cycle")
    var CCCCC = 0.0
    var DDD = 0.0
    var DDDDDD = 0.0
    var EEEEE = 0.0
    BBBBBB = AAAA(close, BBBB, BBBBB)
    CCC = ta.lowest(BBBBBB, EEEEEE)
    CCCC = ta.highest(BBBBBB, EEEEEE) - CCC
    CCCCC := CCCC > 0 ? (BBBBBB - CCC) / CCCC * 100 : nz(CCCCC[1])
    DDD := na(DDD[1]) ? CCCCC : DDD[1] + AAA * (CCCCC - DDD[1])
    DDDD = ta.lowest(DDD, EEEEEE)
    DDDDD = ta.highest(DDD, EEEEEE) - DDDD
    DDDDDD := DDDDD > 0 ? (DDD - DDDD) / DDDDD * 100 : nz(DDDDDD[1])
    EEEEE := na(EEEEE[1]) ? DDDDDD : EEEEE[1] + AAA * (DDDDDD - EEEEE[1])
    EEEEE

mAAAAA = AAAAA(EEEEEE, BBBB, BBBBB)
mColor = mAAAAA > mAAAAA[1] ? color.new(color.green, 20) : color.new(color.red, 20)
posStc = mAAAAA > mAAAAA[1] ? 1 : -1

////////////////////////////////////////////////////////////
// Strategy entry
////////////////////////////////////////////////////////////
pos = posEma == 1 and posTts == 1 and posStc == 1 ? 1 : posEma == -1 and posTts == -1 and posStc == -1 ? -1 : 0

currentPostition = strategy.position_size > 0 ? 1 : strategy.position_size < 0 ? -1 : 0
noOpenPosition = strategy.position_size == 0

signal = pos != pos[1] and pos == 1 and noOpenPosition ? 1 : pos != pos[1] and pos == -1 and noOpenPosition ? -1 : 0

stopPriceForLong = math.min(close * (1 - profit), low[1] * 0.9998, low[2] * 0.9998)
limitPriceForLong = close + (close - stopPriceForLong)
stopPriceForShort = math.max(close * (1 + profit), high[1] * 1.0002, high[2] * 1.0002)
limitPriceForShort = close - (stopPriceForShort - close)

if signal == 1
    strategy.entry(id="L", direction=strategy.long)
    strategy.exit(id='EL', from_entry='L', limit=limitPriceForLong, stop=stopPriceForLong)
if signal == -1
    strategy.entry(id="S", direction=strategy.short)
    strategy.exit(id='ES', from_entry='S', limit=limitPriceForShort, stop=stopPriceForShort)

////////////////////////////////////////////////////////////
// Plots - Debuger
////////////////////////////////////////////////////////////
plotchar(signal, title='singal', char = '')
plotchar(posEma, title='posEma', char = '')
plotchar(posTts, title='posTts', char = '')
plotchar(pos, title='pos', char = '')
plotchar(currentPostition, title = 'currentPostition', char='')
plotchar(stopPriceForLong, title = "stopPriceForLong", char ='')
plotchar(limitPriceForLong, title = 'limitPriceForLong', char='')
plotchar(stopPriceForShort, title = "stopPriceForShort", char ='')
plotchar(limitPriceForShort, title = 'limitPriceForShort', char='')

////////////////////////////////////////////////////////////
// Plots
////////////////////////////////////////////////////////////
plot(ret, color=color.new(color.black, 0), title='Trend Trader Strategy')
plotchar(mAAAAA, color=mColor, title='STC', location = location.bottom, char='-', size=size.normal)
plot(series = ema, title = "ema")

Published by ChaoZhang on the FMZ strategy square · last modified 2023-12-12. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.

Build this with AgenKit

A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.

in Claude Code, Cursor, Codex & 4 more
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/EMA-Tracking-Trend-Suppressing-Oscillation-Strategy.md
  1. npx agenkit install engineering-kit in your project
  2. Paste the command into your agent and approve each phase
  3. Get tests, backtest, risk controls and a paper-trading switch

Understand it first

Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.

Related specs

esc

Try , , or .

↑↓ move↵ open