0bps

Strategy vault / Trend following

Trend Following Strategy Based on Distance with Trailing Stop Loss

This strategy utilizes the Distance Close Bars (DCB) indicator to determine price trend and fast RSI indicator as a filter, implements trailing stop loss for trend following trading. It also uses martingale principle…

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

IMG

Overview

This strategy utilizes the Distance Close Bars (DCB) indicator to determine price trend and fast RSI indicator as a filter, implements trailing stop loss for trend following trading. It also uses martingale principle for position sizing. Suitable for medium-long term trend trading.

Principles

  1. Calculate lastg and lastr representing last green bar's close and last red bar's close.

  2. Calculate dist as the difference between lastg and lastr.

  3. Calculate adist as 30-period SMA of dist.

  4. Generate trading signal when dist is greater than 2 times of adist.

  5. Use fast RSI indicator to filter signal, avoiding false breakout.

  6. Enter trade at fixed percentage of equity if signal presents with no position.

  7. Martingale to scale in after loss.

  8. Close position when stop loss or take profit is triggered.

Advantages

  1. DCB indicator effectively captures mid-long term trends.

  2. Fast RSI filter avoids losses from false breakouts.

  3. Trailing stop locks in profits and controls risks.

  4. Martingale increases position after loss for higher profit.

  5. Reasonable parameter settings suit different market environments.

Risks

  1. DCB may generate wrong signals, needs other filters.

  2. Martingale can amplify losses, requires strict risk management.

  3. Improper stop loss setting may lead to excessive loss.

  4. Position sizing should be limited to prevent over-leverage.

  5. Improper contract settings may lead to huge loss in extreme market.

Optimization

  1. Optimize DCB parameters for best combination.

  2. Try other indicators to replace fast RSI filter.

  3. Optimize stop loss and take profit for higher win rate.

  4. Optimize martingale parameters to reduce risk.

  5. Test on different products for best asset allocation.

  6. Use machine learning to dynamically optimize parameters.

Summary

This is an overall mature trend following strategy. DCB determines trend direction and fast RSI filters signals to avoid wrong entries. Stop loss and take profit effectively controls single trade loss. But there are still risks, parameters need further optimization to reduce risk and improve stability. The logic is clear and easy to understand, suitable for mid-long term trend traders.

Parameters

NameDefaultWhat it controls
v_input_1trueLong
v_input_2trueShort
v_input_3trueUse Martingale
v_input_4100Capital, %
v_input_5trueUse RSI-Filter
v_input_67RSI Period
v_input_730RSI Limit
v_input_82018From Year
v_input_92100To Year
v_input_10trueFrom Month
v_input_1112To Month
v_input_12trueFrom day
v_input_1331To day

Source Pine Script

/*backtest
start: 2023-11-07 00:00:00
end: 2023-11-14 00:00:00
period: 3m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//Noro
//2018

//@version=2
strategy(title = "Noro's Distance Strategy v1.0", shorttitle = "Distance str 1.0", overlay = true, default_qty_type = strategy.percent_of_equity, default_qty_value = 100, pyramiding = 10)

//Settings 
needlong = input(true, defval = true, title = "Long")
needshort = input(true, defval = true, title = "Short")
usemar = input(true, defval = true, title = "Use Martingale")
capital = input(100, defval = 100, minval = 1, maxval = 10000, title = "Capital, %")
usersi = input(true, defval = true, title = "Use RSI-Filter")
periodrsi = input(7, defval = 7, minval = 2, maxval = 50, title = "RSI Period")
limitrsi = input(30, defval = 30, minval = 1, maxval = 50, title = "RSI Limit")
fromyear = input(2018, 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(01, defval = 01, minval = 01, maxval = 31, title = "From day")
today = input(31, defval = 31, minval = 01, maxval = 31, title = "To day")

//Fast RSI
fastup = rma(max(change(close), 0), periodrsi)
fastdown = rma(-min(change(close), 0), periodrsi)
fastrsi = fastdown == 0 ? 100 : fastup == 0 ? 0 : 100 - (100 / (1 + fastup / fastdown))

//Distance
bar = close > open ? 1 : close < open ? -1 : 0
lastg = bar == 1 ? close : lastg[1]
lastr = bar == -1 ? close : lastr[1]
dist = lastg - lastr
adist = sma(dist, 30)
plot(lastg, linewidth = 3, color = lime)
plot(lastr, linewidth = 3, color = red)
up = bar == -1 and dist > adist * 2
dn = bar == 1 and dist > adist * 2

//RSI Filter
rsidn = fastrsi < limitrsi or usersi == false
rsiup = fastrsi > 100 - limitrsi or usersi == false

//Signals
up1 = up and rsidn
dn1 = dn and rsiup
exit = ((strategy.position_size > 0 and close > open) or (strategy.position_size < 0 and close < open))

//Arrows
plotarrow(up1 ? 1 : na, colorup = blue, colordown = blue)
plotarrow(dn1 ? -1 : na, colorup = blue, colordown = blue)

//Trading
profit = exit ? ((strategy.position_size > 0 and close > strategy.position_avg_price) or (strategy.position_size < 0 and close < strategy.position_avg_price)) ? 1 : -1 : profit[1]
mult = usemar ? exit ? profit == -1 ? mult[1] * 2 : 1 : mult[1] : 1
lot = strategy.position_size == 0 ? strategy.equity / close * capital / 100 * mult : lot[1]

signalup = up1
if signalup
    if strategy.position_size < 0
        strategy.close_all()
        
    strategy.entry("long", strategy.long, needlong == false ? 0 : lot, when=(time > timestamp(fromyear, frommonth, fromday, 00, 00) and time < timestamp(toyear, tomonth, today, 23, 59)))

signaldn = dn1
if signaldn
    if strategy.position_size > 0
        strategy.close_all()
        
    strategy.entry("Short", strategy.short, needshort == false ? 0 : lot, when=(time > timestamp(fromyear, frommonth, fromday, 00, 00) and time < timestamp(toyear, tomonth, today, 23, 59)))
    
if time > timestamp(toyear, tomonth, today, 23, 59) or exit
    strategy.close_all()

Published by ChaoZhang on the FMZ strategy square · last modified 2023-11-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/Trend-Following-Strategy-Based-on-Distance-with-Trailing-Stop-Loss.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