Quantitative Trading Strategy Based on Multiple Indicators

Author: ChaoZhang, Date: 2023-10-25 18:06:44



This strategy combines multiple technical indicators to make long and short trading decisions. It mainly uses Bollinger Bands, RSI, ADX and other indicators, together with moving averages to determine trend direction.

Strategy Logic

The strategy mainly uses Bollinger Bands to judge price volatility. Narrowing bands represents decreasing volatility which may lead to a breakout. RSI is used to identify overbought and oversold conditions. RSI above 70 is overbought while below 30 is oversold. When bands narrow and RSI approaches its limits, reverse trading is considered.

In addition, ADX is used to assess trend strength. High ADX represents a strong trend, favoring trend trading. Low ADX represents no clear trend, considering mean reversion. Finally, moving averages define long-term trend direction. Uptrend favors long while downtrend favors short.

Specifically, when bands squeeze, RSI nears its limits, and price breaks below lower band, a bounce is expected, go long. When bands squeeze, RSI nears its limits, and price breaks above upper band, a decline is expected, go short. Also, with high ADX, add longs in uptrend. With low ADX, add shorts in downtrend. Combining indicators improves system robustness.

Advantage Analysis

The multi-indicator strategy has these advantages:

  1. Combining indicators improves accuracy and robustness. Single indicator is prone to false signals while multiple indicators verify signals and avoid bad trades.

  2. Considers both trend and range trading, adaptable to different market conditions. Trend trading targets big moves. Range trading aims for small profits.

  3. Longs and shorts lower directional risks and avoid extreme moves.

  4. Stop loss and take profit lock in profits and limit losses when trades go wrong.

  5. Parameter optimization continuously improves strategy by adapting to changing markets.

Risk Analysis

The strategy also has some risks:

  1. More indicators increase complexity. Improper settings may degrade performance. Extensive testing and optimization are needed.

  2. Overreliance on technicals while ignoring fundamentals may cause inaccurate signals. Indicator false signals should be treated with caution.

  3. Markets may have already moved when signals emerge, posing chasing risk. Allowing pullbacks is prudent.

  4. Dual direction trading increases frequency, raising costs and pressure. Position sizing needs control.

  5. Curve fitting risks exist. Robustness should be tested across diverse markets.

Risks can be managed through strict stop loss, prudent position sizing, reasonable leverage etc. Overall, the strategy has strong practical value.

Enhancement Opportunities

Some ways to optimize the strategy:

  1. Test different parameter sets to find optimum values using stepwise, random or genetic algorithms.

  2. Add more indicators like KDJ, Williams to build a robust indicator ensemble.

  3. Optimize position sizing models to dynamically manage risk.

  4. Incorporate machine learning models to predict price trends and movements.

  5. Test across different products, timeframes and markets to improve adaptiveness.

  6. Refine entry and exit timing to capture trends early and exit before reversals.

  7. Employ profit taking, trailing stops to lock in profits and limit losses.

  8. Add fundamental factors and market structure analysis to filter technical signals.


This strategy automates trading by interpreting multiple indicators. It benefits from indicator cross-validation, dual direction trading, stop loss/take profit etc. Overfitting and false signals require caution. Continuous optimization and testing can transform it into a robust, practical system, representing the future of quant trading strategies.

start: 2023-09-24 00:00:00
end: 2023-10-24 00:00:00
period: 2h
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/
// © The_Bigger_Bull
strategy("Best TradingView Strategy", overlay=true, margin_long=0, margin_short=0)
//Bollinger Bands
source1 = close
length1 = input.int(15, minval=1)
mult1 = input.float(2.0, minval=0.001, maxval=50)
basis1 = ta.sma(source1, length1)
dev1 = mult1 * ta.stdev(source1, length1)
upper1 = basis1 + dev1
lower1 = basis1 - dev1
//buyEntry = ta.crossover(source1, lower1)
//sellEntry = ta.crossunder(source1, upper1)

ma(source, length, type) =>
    switch type
        "SMA" => ta.sma(source, length)
        "Bollinger Bands" => ta.sma(source, length)
        "EMA" => ta.ema(source, length)
        "SMMA (RMA)" => ta.rma(source, length)
        "WMA" => ta.wma(source, length)
        "VWMA" => ta.vwma(source, length)

rsiLengthInput = input.int(14, minval=1, title="RSI Length", group="RSI Settings")
rsiSourceInput = input.source(close, "Source", group="RSI Settings")
maTypeInput = input.string("SMA", title="MA Type", options=["SMA", "Bollinger Bands", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group="MA Settings")
maLengthInput = input.int(14, title="MA Length", group="MA Settings")
bbMultInput = input.float(2.0, minval=0.001, maxval=50, title="BB StdDev", group="MA Settings")

up = ta.rma(math.max(ta.change(rsiSourceInput), 0), rsiLengthInput)
down = ta.rma(-math.min(ta.change(rsiSourceInput), 0), rsiLengthInput)
rsi = down == 0 ? 100 : up == 0 ? 0 : 100 - (100 / (1 + up / down))
rsiMA = ma(rsi, maLengthInput, maTypeInput)
isBB = maTypeInput == "Bollinger Bands"

//plot(rsi, "RSI", color=#7E57C2)
//plot(rsiMA, "RSI-based MA", color=color.yellow)
rsiUpperBand = hline(70, "RSI Upper Band", color=#787B86)
hline(50, "RSI Middle Band", color=color.new(#787B86, 50))
rsiLowerBand = hline(30, "RSI Lower Band", color=#787B86)
fill(rsiUpperBand, rsiLowerBand, color=color.rgb(126, 87, 194, 90), title="RSI Background Fill")
bbUpperBand = plot(isBB ? rsiMA + ta.stdev(rsi, maLengthInput) * bbMultInput : na, title = "Upper Bollinger Band", color=color.green)
bbLowerBand = plot(isBB ? rsiMA - ta.stdev(rsi, maLengthInput) * bbMultInput : na, title = "Lower Bollinger Band", color=color.green)
fill(bbUpperBand, bbLowerBand, color= isBB ? color.new(color.green, 90) : na, title="Bollinger Bands Background Fill")


adxlen = input(14, title="ADX Smoothing")
dilen = input(14, title="DI Length")
dirmov(len) =>
	up1 = ta.change(high)
	down1 = -ta.change(low)
	plusDM = na(up1) ? na : (up1 > down1 and up1 > 0 ? up1 : 0)
	minusDM = na(down1) ? na : (down1 > up1 and down1 > 0 ? down1 : 0)
	truerange = ta.rma(ta.tr, len)
	plus = fixnan(100 * ta.rma(plusDM, len) / truerange)
	minus = fixnan(100 * ta.rma(minusDM, len) / truerange)
	[plus, minus]
adx(dilen, adxlen) =>
	[plus, minus] = dirmov(dilen)
	sum = plus + minus
	adx = 100 * ta.rma(math.abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen)
sig = adx(dilen, adxlen)

out = ta.sma(close, 14)



longCondition = (out>sma1) and ta.crossover(source1, lower1)

if (longCondition )
    strategy.entry("long", strategy.long)
shortCondition = (out<sma1) and ta.crossunder(source1, lower1)

if (shortCondition )
    strategy.entry("short", strategy.short)


//if strategy.position_avg_price<0
plot(sma1 , color=color.blue)
plot(out, color=color.green)