Dual Trend Lines Intelligent Tracking BTC Investment Strategy

Author: ChaoZhang, Date: 2023-11-22 15:18:53



This strategy is mainly used for the automated long-term investment in BTC. It uses the crossover of dual EMA and LSMA to determine the trend direction and uses the ATR indicator to calculate a dynamic stop loss to effectively track the BTC bullish trend.

Strategy Logic

  1. Use 25-period EMA and 100-period LSMA to form a dual moving average. Their crossover is used to determine the market trend. The EMA responds quickly to price changes while the LSMA filters out false breakouts.

  2. When the fast EMA crosses above the slow LSMA, it is determined that the uptrend is still intact and long positions are taken. On the contrary, when the fast EMA crosses below the slow LSMA, it is determined that a downtrend has begun and existing positions are closed.

  3. After taking long positions, the dynamic stop loss calculated using the ATR indicator keeps adjusting to effectively track the uptrend of BTC. Specifically, the initial point of the stop loss line is the entry price. After that, each adjustment will slide up by a fixed percentage of the ATR amplitude.

  4. The stop loss line can effectively lock in the floating profit brought by the BTC uptrend, while preventing the stop loss point from getting too close to the latest price to avoid frequent stop loss. In addition, the strategy also sets two moving stop profits of different proportions to lock in more profits.

Advantage Analysis

  1. Using dual moving averages to determine the trend is more reliable and can effectively prevent false signals.

  2. The ATR dynamic trailing stop loss can lock in most profits while avoiding frequent small stop losses.

  3. No matter whether the bullish trend ends or not, as long as the moving average issues an exit signal, the position will be stopped out to control risks.

  4. The strategy has a high degree of automation without manual intervention, making it suitable for long-term live trading.

Risk Analysis

  1. Still need to pay attention to sudden major news to avoid huge slippage losses.

  2. Although the combination of dual moving averages can reduce false signals, it is still difficult to completely avoid them in range-bound markets.

  3. Improper parameter settings of ATR can also affect the stop loss effect. Adjustments are needed based on different products.

  4. Unreasonable moving average periods or failure to update them in time can lead to signal lag.

  5. Ensure server stability to avoid abnormal crashes that interrupt automated trading.

Optimization Directions

  1. More indicators such as Bollinger Bands can be added to determine the trend. Machine learning models can also be used to predict prices.

  2. The calculation method of the ATR dynamic stop loss can also be adjusted and optimized to make the stop loss smoother.

  3. Trading volume based alert mechanisms and intraday rotation features can be added to guard against impacts from major news.

  4. Parameters vary for different coins. More historical data can be used to train personalized parameters.


Overall, this is a very practical automated BTC investment program. Using dual EMAs to determine the major trend is very reliable. With ATR trailing stop loss, it can achieve decent profits and the validity period can be very long. As parameters continue to be optimized, there is still much room for improvement in the performance of this strategy. It is well worth live trading verification.

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

strategy("Automated Bitcoin (BTC) Investment Strategy", overlay=true, initial_capital=5000,pyramiding = 0, currency="USD", default_qty_type=strategy.percent_of_equity, default_qty_value=100,  commission_type=strategy.commission.percent,commission_value=0.1)

////////////  Functions

Atr(p) =>
    atr = 0.
    Tr = max(high - low, max(abs(high - close[1]), abs(low - close[1])))
    atr := nz(atr[1] + (Tr - atr[1])/p,Tr)

TEMA(series, length) =>
    if (length > 0)
        ema1 = ema(series, length)
        ema2 = ema(ema1, length)
        ema3 = ema(ema2, length)
        (3 * ema1) - (3 * ema2) + ema3
tradeType = input("LONG", title="What trades should be taken : ", options=["LONG", "SHORT", "BOTH", "NONE"])


trend_type1 = input("TEMA", title ="First Trend Line : ", options=["LSMA", "TEMA","EMA","SMA"])
trend_type2 = input("LSMA", title ="First Trend Line : ", options=["LSMA", "TEMA","EMA","SMA"])

trend_type1_length=input(25, "Length of the First Trend Line")
trend_type2_length=input(100, "Length of the Second Trend Line")

leadLine1 = if trend_type1=="LSMA"
    linreg(close, trend_type1_length, 0)
else if trend_type1=="TEMA"
else if trend_type1 =="EMA"

leadLine2 = if trend_type2=="LSMA"
    linreg(close, trend_type2_length, 0)
else if trend_type2=="TEMA"
else if trend_type2 =="EMA"

p3 = plot(leadLine1, color= #53b987, title="EMA", transp = 50, linewidth = 1)
p4 = plot(leadLine2, color= #eb4d5c, title="SMA", transp = 50, linewidth = 1)
fill(p3, p4, transp = 60, color = leadLine1 > leadLine2 ? #53b987 : #eb4d5c)

//Upward Trend

long_tp1_inp = input(15, title='Long Take Profit 1 %', step=0.1)/100
long_tp1_qty = input(20, title="Long Take Profit 1 Qty", step=1)

long_tp2_inp = input(30, title='Long Take Profit 2%', step=0.1)/100
long_tp2_qty = input(20, title="Long Take Profit 2 Qty", step=1)

long_take_level_1 = strategy.position_avg_price * (1 + long_tp1_inp)
long_take_level_2 = strategy.position_avg_price * (1 + long_tp2_inp)

long_sl_input = input(5, title='stop loss in %', step=0.1)/100
long_sl_input_level = strategy.position_avg_price * (1 - long_sl_input)

// Stop Loss
multiplier = input(3.5, "SL Mutiplier", minval=1, step=0.1)
ATR_period=input(8,"ATR period", minval=1, step=1)

// Strategy

SC = input(close, "Source", input.source)
SL1 = multiplier * Atr(ATR_period)  // Stop Loss
Trail1 = 0.0
Trail1 :=  iff(SC < nz(Trail1[1], 0) and SC[1] < nz(Trail1[1], 0), min(nz(Trail1[1], 0), SC + SL1), iff(SC > nz(Trail1[1], 0), SC - SL1, SC + SL1))

// iff(SC > nz(Trail1[1], 0) and SC[1] > nz(Trail1[1], 0), max(nz(Trail1[1], 0), SC - SL1),

entry_long=crossover(leadLine1,leadLine2) and Trail1_high < close
exit_long = close < Trail1_high or crossover(leadLine2,leadLine1) or close < long_sl_input_level

///// BACKTEST PERIOD ///////
testStartYear = input(2016, "Backtest Start Year")
testStartMonth = input(1, "Backtest Start Month")
testStartDay = input(1, "Backtest Start Day")
testPeriodStart = timestamp(testStartYear, testStartMonth, testStartDay, 0, 0)

testStopYear = input(9999, "Backtest Stop Year")
testStopMonth = input(12, "Backtest Stop Month")
testStopDay = input(31, "Backtest Stop Day")
testPeriodStop = timestamp(testStopYear, testStopMonth, testStopDay, 0, 0)

testPeriod() =>
    time >= testPeriodStart and time <= testPeriodStop ? true : false

if testPeriod()
    if tradeType=="LONG" or tradeType=="BOTH"
        if strategy.position_size == 0 or strategy.position_size > 0
            strategy.entry("long", strategy.long, comment="b8f60da7_ENTER-LONG_BINANCE_BTC/USDT_b8f60da7-BTC-Investment_4H", when=entry_long)
            strategy.exit("TP1", "long", qty_percent=long_tp1_qty, limit=long_take_level_1)
            strategy.exit("TP2", "long", qty_percent=long_tp2_qty, limit=long_take_level_2)
            strategy.close("long", when=exit_long, comment="b8f60da7_EXIT-LONG_BINANCE_BTC/USDT_b8f60da7-BTC-Investment_4H" )


plot(strategy.position_size > 0 ? long_take_level_1 : na, style=plot.style_linebr, color=color.green, linewidth=1, title="1st Long Take Profit")
plot(strategy.position_size > 0 ? long_take_level_2 : na, style=plot.style_linebr, color=color.green, linewidth=1, title="2nd Long Take Profit")
plot(strategy.position_size > 0 ? Trail1_high : na, style=plot.style_linebr, color=color.red, linewidth=1, title="Long Stop Loss")