0bps

Strategy vault / Trend following

HMA and CCI Combo Trend Following Strategy

This strategy combines HMA and CCI to identify and trade trends. Specifically, it goes long when HMA breaks upwards and CCI crosses above lower band, and goes short when HMA breaks downwards and CCI crosses below…

Author
ChaoZhang
Complexity
Intermediate · 79 lines
Parameters
16
Backtest bar
3h · intraday
Tested on
BTC/USDT · futures

This strategy combines HMA and CCI to identify and trade trends. Specifically, it goes long when HMA breaks upwards and CCI crosses above lower band, and goes short when HMA breaks downwards and CCI crosses below upper band. Exits occur when HMA breaks back in opposite direction, or CCI re-enters threshold range.

The advantage of this strategy is using HMA to determine trend direction, and CCI to confirm trend start, effectively reducing whipsaws and pullback errors. However, both HMA and CCI have lagging issues, potentially missing optimal entry points. Also, CCI has limited capabilities in complex market situations.

In summary, the HMA and CCI combo trend following strategy can produce decent results during strong trending phases. But in live trading, attention is still needed on stop loss to cut losses from LIQR events. Only with proper parameter optimization can this strategy be applied successfully in the long run.

Parameters

NameDefaultWhat it controls
v_input_1_close0src: close | high | low | open | hl2 | hlc3 | hlcc4 | ohlc4
v_input_221hmaLen
v_input_310cciLen
v_input_4-50cciLower
v_input_550cciUpper
v_input_6-100cciLowerExit
v_input_7100cciUpperExit
v_input_8falsehmaExit
v_input_9truecciExit
v_input_102017From Year
v_input_112100To Year
v_input_12trueFrom Month
v_input_1312To Month
v_input_1421From day
v_input_1531To day
v_input_16100leverage

Source Pine Script

/*backtest
start: 2023-08-11 00:00:00
end: 2023-09-10 00:00:00
period: 3h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=3
strategy("HMA+CCI strategy", overlay=true)

src = input(close)
hmaLen = input(21)
cciLen = input(10)
cciLower = input(-50)
cciUpper = input(50)
cciLowerExit = input(-100)
cciUpperExit = input(100)
hmaExit = input(false)
cciExit = input(true)
//rciLower = input(-60)
//rciUpper = input(60)

// Backtest
fromyear = input(2017, defval = 2018, minval = 1900, maxval = 2100, title = "From Year")
toyear = input(2100, defval = 2100, minval = 1900, maxval = 2100, title = "To Year")
frommonth = input(01, defval = 01, minval = 01, maxval = 12, title = "From Month")
tomonth = input(12, defval = 12, minval = 01, maxval = 12, title = "To Month")
fromday = input(21, defval = 01, minval = 01, maxval = 31, title = "From day")
today = input(31, defval = 31, minval = 01, maxval = 31, title = "To day")

leverage = input(100)

term = (time > timestamp(fromyear, frommonth, fromday, 00, 00) and time < timestamp(toyear, tomonth, today, 23, 59))

//itvs = input(9, "short interval")
//itvm = input(36, "middle interval")
//itvl = input(52, "long interval")
//src = input(close, "source")
//upperband=input(title="High line[%]",defval=80,type=integer)
//lowerband=input(title="Low line[%]",defval=-80,type=integer)

ord(seq, idx, itv) =>
    p = seq[idx]
    o = 1
    for i = 0 to itv - 1
        if p < seq[i]
            o := o + 1
    o

d(itv) =>
    sum = 0.0
    for i = 0 to itv - 1
        sum := sum + pow((i + 1) - ord(src, i, itv), 2)
    sum

rci(itv) => (1.0 - 6.0 * d(itv) / (itv * (itv * itv - 1.0))) * 100.0

hullma = wma(2*wma(src, hmaLen/2)-wma(src, hmaLen), round(sqrt(hmaLen)))
cci = cci(close, cciLen)
plot(hullma, color=hullma[1]>hullma?red:green, linewidth=4)
longCondition = hullma[1] < hullma and crossover(cci, cciLower) //rci < -60 // crossover(cci, cciLower)
shortCondition = hullma[1] > hullma and crossunder(cci, cciUpper) //rci > 60
exitLong1 = hmaExit ? hullma[1] > hullma : false
exitLong2 = cciExit ? cci > cciUpperExit : false
exitShort1 = hmaExit ? hullma[1] < hullma : false
exitShort2 = cciExit ? cci < cciLowerExit : false

if (longCondition and term)
    strategy.entry("Long",  strategy.long )
if (shortCondition and term)
    strategy.entry("Short",  strategy.short)
        
if strategy.position_size > 0 and term
    if (exitLong1 or exitLong2)
        strategy.close_all()
if strategy.position_size < 0 and term
    if (exitShort1 or exitShort2)
        strategy.close_all()

Published by ChaoZhang on the FMZ strategy square · last modified 2023-09-11. 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/HMA-and-CCI-Combo-Trend-Following-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