Double Inside Bar & Trend Strategy

Author: ChaoZhang, Date: 2024-01-30 15:11:48
Tags:

img

Double Inside Bar & Trend Strategy

Overview

The Double Inside Bar & Trend strategy is a quantitative trading strategy that utilizes double inside bar patterns combined with moving average to determine the trend. It provides high probability trading signals with double inside bars, and goes long or short according to the trend judged by the moving average line.

Strategy Logic

  1. Use Hull Moving Average (HMA) as an indicator for trend judgement.
  2. When a double inside bar pattern occurs, it is considered a high probability trading signal. An inside bar is a pattern where the high and low of the last bar is encompassed by the prior bar.
  3. If close price is above MA and a bullish inside bar forms, place a buy stop order around the high of the inside bar. If close is below MA and a bearish inside bar forms, place a sell stop order around the low of the inside bar.
  4. Once the stop order is triggered, set stop loss and take profit based on predefined stop loss percentage and take profit ratio.

Advantage Analysis

  1. Inside bars provide high probability reversal signals. The occurrence of double inside bars may indicate a short-term price reversal.
  2. Used with moving averages to follow the major trend direction, it improves the probability of profit.
  3. Using stop orders around breakthrough points in the trend enjoys good entry opportunities.

Risk Analysis

  1. In ranging markets, trading signals from inside bars may frequently lead to losses.
  2. The moving average as a trend indicator may also give false signals, resulting in losses from countertrend trading.
  3. If the stop loss is set too tight, it may be triggered by small price slips.

Optimization Directions

  1. Test different parameters of moving averages as the trend judging indicator.
  2. Combine other indicators to filter ranging markets, avoiding blind trading without a clear trend.
  3. Obtain more optimal parameter combinations through big data analysis, such as moving average period, stop loss multiplier, take profit ratio etc.
  4. Add filters on trading sessions and products to adapt to different timeframes and product characteristics.

Summary

The Double Inside Bar & Trend strategy utilizes the high probability trading signals from double inside bars, aided by moving averages to determine the major trend direction to go long or short, making it a relatively stable breakout strategy. Through parameter optimization and logic optimization, the adaptability and profitability of this strategy can be improved.


/*backtest
start: 2023-12-01 00:00:00
end: 2023-12-31 23:59:59
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/
// © Kaspricci

//@version=5
strategy(
     title = "Double Inside Bar & Trend Strategy - Kaspricci", 
     shorttitle = "Double Inside Bar & Trend", 
     overlay=true, 
     initial_capital = 100000, 
     currency = currency.USD, 
     default_qty_type = strategy.percent_of_equity, 
     default_qty_value = 100, 
     calc_on_every_tick = true, 
     close_entries_rule = "ANY")

// ================================================ Entry Inputs ======================================================================
headlineEntry   = "Entry Seettings"

maSource        = input.source(defval = close,             group = headlineEntry, title = "MA Source")
maType          = input.string(defval = "HMA",             group = headlineEntry, title = "MA Type", options = ["EMA", "HMA", "SMA", "SWMA", "VWMA", "WMA"])
maLength        = input.int(   defval = 45,    minval = 1, group = headlineEntry, title = "HMA Length")

float ma = switch maType 
    "EMA"  => ta.ema(maSource,  maLength)
    "HMA"  => ta.hma(maSource,  maLength)
    "SMA"  => ta.sma(maSource,  maLength)
    "SWMA" => ta.swma(maSource)
    "VWMA" => ta.vwma(maSource, maLength)
    "WMA"  => ta.wma(maSource,  maLength)

plot(ma, "Trend MA", color.purple)

// ================================================ Trade Inputs ======================================================================
headlineTrade   = "Trade Seettings"

stopLossType    = input.string(defval = "ATR",                         group = headlineTrade,                 title = "Stop Loss Type",            options = ["ATR", "FIX"])
atrLength       = input.int(   defval = 50,   minval = 1,              group = headlineTrade, inline = "ATR", title = "   ATR: Length                 ")
atrFactor       = input.float( defval =  2.5, minval = 0, step = 0.05, group = headlineTrade, inline = "ATR", title = "Factor       ",             tooltip = "multiplier for ATR value")
takeProfitRatio = input.float( defval =  2.0, minval = 0, step = 0.05, group = headlineTrade,                 title = "            TP Ration",     tooltip = "Multiplier for Take Profit calculation")
fixStopLoss     = input.float( defval = 10.0, minval = 0, step = 0.5,  group = headlineTrade, inline = "FIX", title = "   FIX: Stop Loss             ") * 10 // need this in ticks
fixTakeProfit   = input.float( defval = 20.0, minval = 0, step = 0.5,  group = headlineTrade, inline = "FIX", title = "Take Profit",               tooltip = "in pips") * 10 // need this in ticks
useRiskMagmt    = input.bool(  defval = true,                          group = headlineTrade, inline = "RM",  title = "")
riskPercent     = input.float( defval = 1.0,  minval = 0., step = 0.5, group = headlineTrade, inline = "RM",  title = "Risk in %                ", tooltip = "This will overwrite quantity from startegy settings and calculate the trade size based on stop loss and risk percent") / 100

// ================================================ Filter Inputs =====================================================================
headlineFilter  = "Filter Setings"

// date filter
filterDates     = input.bool(defval = false,                                 group = headlineFilter, title = "Filter trades by dates")
startDateTime   = input(defval = timestamp("2022-01-01T00:00:00+0000"), group = headlineFilter, title = "       Start Date & Time")
endDateTime     = input(defval = timestamp("2099-12-31T23:59:00+0000"), group = headlineFilter, title = "       End Date & Time  ")

dateFilter      = not filterDates or (time >= startDateTime and time <= endDateTime)

// session filter
filterSession   = input.bool(title = "Filter trades by session", defval = false, group = headlineFilter)
session         = input(title = "       Session", defval = "0045-2245", group = headlineFilter)

sessionFilter   = not filterSession or time(timeframe.period, session, timezone = "CET")

// ================================================ Trade Entries and Exits =====================================================================

// calculate stop loss
stopLoss        = switch stopLossType
    "ATR" => nz(math.round(ta.atr(atrLength) * atrFactor / syminfo.mintick, 0), 0)
    "FIX" => fixStopLoss

// calculate take profit
takeProfit      = switch stopLossType
    "ATR" => math.round(stopLoss * takeProfitRatio, 0)
    "FIX" => fixTakeProfit


doubleInsideBar = high[2] > high[1] and high[2] > high[0] and low[2] < low[1] and low[2] < low[0]

// highlight mother candel and inside bar candles
bgcolor(doubleInsideBar ? color.rgb(33, 149, 243, 80) : na)
bgcolor(doubleInsideBar ? color.rgb(33, 149, 243, 80) : na, offset = -1)
bgcolor(doubleInsideBar ? color.rgb(33, 149, 243, 80) : na, offset = -2)

var float buyStopPrice  = na
var float sellStopPrice = na

if (strategy.opentrades == 0 and doubleInsideBar and barstate.isconfirmed)
    buyStopPrice  := high[0] // high of recent candle (second inside bar)
    sellStopPrice := low[0] // low of recent candle (second inside bar)

    tradeID = str.tostring(strategy.closedtrades + strategy.opentrades + 1)

    quantity = useRiskMagmt ? math.round(strategy.equity * riskPercent / stopLoss, 2) / syminfo.mintick : na

    commentTemplate = "{0} QTY: {1,number,#.##} SL: {2} TP: {3}"

    if (close > ma)
        longComment = str.format(commentTemplate, tradeID + "L", quantity, stopLoss / 10, takeProfit / 10)
        strategy.entry(tradeID + "L", strategy.long, qty = quantity, stop = buyStopPrice, comment = longComment)
        strategy.exit(tradeID + "SL", tradeID + "L", profit = takeProfit, loss = stopLoss, comment_loss = "SL", comment_profit = "TP")

    if (close < ma)
        shortComment = str.format(commentTemplate, tradeID + "S", quantity, stopLoss / 10, takeProfit / 10)
        strategy.entry(tradeID + "S", strategy.short, qty = quantity, stop = sellStopPrice, comment = shortComment)
        strategy.exit(tradeID + "SL", tradeID + "S", profit = takeProfit, loss = stopLoss, comment_loss = "SL", comment_profit = "TP")

// as soon as the first pending order has been entered the remaing pending order shall be cancelled 
if strategy.opentrades > 0
    currentTradeID = str.tostring(strategy.closedtrades + strategy.opentrades)
    strategy.cancel(currentTradeID + "S")
    strategy.cancel(currentTradeID + "L")


More