0bps

Strategy vault / Momentum

STEM and MATCS Combined Momentum Trading Strategy

This strategy is called the STEM and MATCS Combined Momentum Trading Strategy. It combines the Supertrend indicator with the MACD indicator to generate trading signals. How the strategy works: 1. Calculate the…

Author
ChaoZhang
Complexity
Intermediate · 103 lines
Parameters
26
Backtest bar
1h · intraday
Tested on
BTC/USDT · futures

This strategy is called the STEM and MATCS Combined Momentum Trading Strategy. It combines the Supertrend indicator with the MACD indicator to generate trading signals.

How the strategy works:

  1. Calculate the Supertrend indicator to generate buy and sell signals when price reverses.
  2. Calculate the fast, medium and slow MAs of the MACD indicator. Buy signals are generated when the fast MA crosses above the medium MA. Sell signals are generated when the fast MA crosses below the medium MA.
  3. Combine the signals from Supertrend and MACD, only taking trades when both indicators agree.
  4. Use the ATR indicator to calculate dynamic stop loss levels.

Specific trading rules:

  1. When Supertrend flips from down to up, and MACD fast MA crosses above medium MA, go long.
  2. When Supertrend flips from up to down, and MACD fast MA crosses below medium MA, go short.
  3. Exit rules: stop loss or take profit (optional).

Advantages of this strategy:

  1. Combining multiple indicators improves signal accuracy.
  2. Dynamic stop loss can limit individual big losses.
  3. Has both trend following and mean reversion capabilities.

Risks of this strategy:

  1. Incorrect Supertrend and MACD parameters may generate bad signals.
  2. Stop loss too close may result in frequent stop outs.
  3. Fees and slippage impact profits.

In summary, the STEM and MATCS Combined Momentum Trading Strategy enhances effects through indicator integration, suitable for short-term and medium-term trading. Stop loss application is critical for risk control. Traders need to reduce risks in live trading through parameter optimization and strict money management.

Parameters

NameDefaultWhat it controls
v_input_1trueST_EMA_PERIOD
v_input_295ATR_PERIOD
v_input_32.1ATR_TUNE
v_input_4trueShow_Buy/Sell_Labels ?
v_input_5trueHighlight_State ?
v_input_63fastLength
v_input_79medLength
v_input_812slowLength
v_input_916signalLength
v_input_105ATR_CrossOver_Period
v_input_110.962ATR_SIGNAL_FINE_TUNE
v_input_12falseStopLoss_Initial_Short
v_input_13falseStopLoss_Initial_Long
v_input_14falseStopLoss_Long_Adjust
v_input_15falseStopLoss_Short_Adjust
v_input_16200VOLUME_CHECK
v_input_17falseFrom Minute
v_input_18falseFrom Hour
v_input_19trueFrom Day
v_input_20trueFrom Month
v_input_212019From Year
v_input_22falseTill Minute
v_input_23falseTill Hour
v_input_24trueTill Day
v_input_25trueTill Month
v_input_262020Till Year

Source Pine Script

/*backtest
start: 2023-09-07 00:00:00
end: 2023-09-14 00:00:00
period: 1h
basePeriod: 15m
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/
// © IncomePipelineGenerator
//@version=4
// strategy("STRAT_STEM_MATCS_BTC", overlay=true, pyramiding = 0, default_qty_value = 20, slippage = 5)


ST_EMA_PERIOD = input(1, minval=1)
ST_EMA = ema(close, ST_EMA_PERIOD)

LENGTH = input(title="ATR_PERIOD", type=input.integer, defval=95)
ATR_TUNE = input(title="ATR_TUNE", type=input.float, step=0.1, defval=2.1)
showLabels = input(title="Show_Buy/Sell_Labels ?", type=input.bool, defval=true)
highlightState = input(title="Highlight_State ?", type=input.bool, defval=true)

ATR = ATR_TUNE * atr(LENGTH)

longStop = ST_EMA - ATR
longStopPrev = nz(longStop[1], longStop)
longStop := (close[1]) > longStopPrev ? max(longStop, longStopPrev) : longStop

shortStop = ST_EMA + ATR
shortStopPrev = nz(shortStop[1], shortStop)
shortStop := (close[1]) < shortStopPrev ? min(shortStop, shortStopPrev) : shortStop

dir = 1
dir := nz(dir[1], dir)
dir := dir == -1 and (close) > shortStopPrev ? 1 : dir == 1 and (close) < longStopPrev ? -1 : dir


fastLength = input(3, minval=1), medLength=input(9, minval=1), slowLength=input(12, minval=1), signalLength=input(16,minval=1)
fastMA = ema(close, fastLength), medMA = ema(close, medLength), slowMA = ema(close, slowLength)

macd = fastMA - slowMA
fmacd = fastMA - medMA
smacd = slowMA - medMA

signal = ema(macd, signalLength)
fsignal = ema(fmacd, signalLength)
ssignal = ema(smacd, signalLength)


SetStopLossShort = 0.0
SetStopLossShort := if(strategy.position_size < 0)
    StopLossShort = shortStop
    min(StopLossShort,SetStopLossShort[1])

SetStopLossLong = 0.0
SetStopLossLong := if(strategy.position_size > 0)
    StopLossLong = longStop
    max(StopLossLong,SetStopLossLong[1])


ATR_CrossOver_Period = input(5, type=input.integer, minval=1, maxval=2000)
ATR_SIGNAL_FINE_TUNE = input(0.962, type=input.float)  
ATR_CS = atr(ATR_CrossOver_Period)*ATR_SIGNAL_FINE_TUNE

StopLoss_Initial_Short = input(0.0, type=input.float) 
StopLoss_Initial_Long = input(0.0, type=input.float) 

StopLoss_Long_Adjust = input(0.0, type=input.float) 
StopLoss_Short_Adjust = input(0.0, type=input.float) 

VOLUME_CHECK = input(200)

//Custom Time Interval
fromMinute = input(defval = 0, title = "From Minute", minval = 0, maxval = 60)
fromHour = input(defval = 0, title = "From Hour", minval = 0, maxval = 24)
fromDay = input(defval = 1, title = "From Day", minval = 1)
fromMonth = input(defval = 1, title = "From Month", minval = 1)
fromYear = input(defval = 2019, title = "From Year", minval = 1900)
tillMinute = input(defval = 0, title = "Till Minute", minval = 0, maxval = 60)
tillHour = input(defval = 0, title = "Till Hour", minval = 0, maxval = 24)
tillDay = input(defval = 1, title = "Till Day", minval = 1)
tillMonth = input(defval = 1, title = "Till Month", minval = 1)
tillYear = input(defval = 2020, title = "Till Year", minval = 1900)
timestampStart = timestamp(fromYear,fromMonth,fromDay,fromHour,fromMinute)
timestampEnd = timestamp(tillYear,tillMonth,tillDay,tillHour,tillMinute)


//Custom Buy Signal Code --  This is where you design your own buy and sell signals. You now have millions of possibilites with the use of simple if/and/or statements.
if (  dir==1 and dir[1]==-1  and volume > VOLUME_CHECK and ((fsignal[1] -fsignal) <= 0) and  cross(fmacd, smacd) )
    strategy.exit("SELL")
    strategy.entry("BUY", strategy.long)
    strategy.exit("BUY_STOP","BUY", stop = close - StopLoss_Initial_Long)

//Custom Sell Signal Code
if  ( dir == -1 and dir[1] == 1 and dir[2] == 1 and dir[3] == 1 and dir[4] == 1 and  cross(fmacd, smacd) )
    strategy.exit( "BUY")
    strategy.entry("SELL", strategy.short)
    strategy.exit("SELL_STOP","SELL", stop = close + StopLoss_Initial_Short)

//Slight adjustments to ST for fine tuning
if (strategy.opentrades > 0 )
    strategy.exit("BUY_TRAIL_STOP","BUY", stop = longStop - StopLoss_Long_Adjust)
    strategy.exit("SELL_TRAIL_STOP","SELL", stop = shortStop + StopLoss_Short_Adjust)

Published by ChaoZhang on the FMZ strategy square · last modified 2023-09-15. 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/STEM-and-MATCS-Combined-Momentum-Trading-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