This strategy is based on G channel indicator.
The trades are entered on a combination of a long and short periods(100 and 300) of the G channel.
The SL and TP based on a multiple of ATR period.
Alternatively a trade can be closed after X no of bars in market.
This is tested on 1 hour chart of MES futures contract.
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © QuantG
//@version=5
strategy("QG-Dynamic Channel Breakout Strategy", overlay=true,default_qty_type=strategy.percent_of_equity , default_qty_value=50, margin_long=100, margin_short=100)
//Input
lengthLong = input(300)
lengthShort = input(100)
src = input.source(close)
CloseTradeAfterXBars = input.int(defval=20, title='Close Trades after X no of bars')
//----------------------------------------------------------------------|
// channel calculation |
//----------------------------------------------------------------------|
a = 0.,b = 0.
a := math.max(src,nz(a[1])) - nz(a[1] - b[1])/lengthLong
b := math.min(src,nz(b[1])) + nz(a[1] - b[1])/lengthLong
avg = math.avg(a,b)
//----
crossup = b[1] < src[1] and b > src
crossdn = a[1] < src[1] and a > src
bullish = ta.barssince(crossdn) <= ta.barssince(crossup)
c = bullish ? color.new(color.lime,50) : color.new(color.red,50)
p1=plot(avg,"Average",color=c,linewidth=2)
p2=plot(close,"Close price",color=c,linewidth=1)
//fill(p1,p2,color=c)
showcross = input(true)
plotshape(showcross and not bullish and bullish[1] ? avg : na, location=location.absolute, style=shape.labeldown, color=color.red, size=size.tiny, text="Sell", textcolor=#ffffff, offset=-1)
plotshape(showcross and bullish and not bullish[1] ? avg : na, location=location.absolute, style=shape.labelup, color=color.lime, size=size.tiny, text="Buy", textcolor=#ffffff, offset=-1)
// short length channel
x = 0.,y = 0.
x := math.max(src,nz(x[1])) - nz(x[1] - y[1])/lengthShort
y := math.min(src,nz(y[1])) + nz(x[1] - y[1])/lengthShort
avgS = math.avg(x,y)
p3=plot(avgS,"Average1",color=color.new(color.blue, 50),linewidth=2)
crossUP = y[1] < close[1] and y > close
crossDN = x[1] < close[1] and x > close
bullishS = ta.barssince(crossDN) <= ta.barssince(crossUP)
//Custom functions
//Exit after X no of bars
BarsSinceFirstEntry() =>
bar_index - strategy.opentrades.entry_bar_index(0)
//Time delay between trades
i_qtyTimeUnits = input.int(defval=1, title="Delay between orders:", inline = "1", minval = 0, tooltip = "Use 0 for no delay")
i_timeUnits = input.string(defval="days", title="Enter time units", inline = "1", options = ["seconds", "minutes", "hours", "days", "months", "years"])
// ————— Converts current chart timeframe into a float minutes value.
f_tfInMinutes() =>
_tfInMinutes = timeframe.multiplier * (
timeframe.isseconds ? 1. / 60 :
timeframe.isminutes ? 1. :
timeframe.isdaily ? 60. * 24 :
timeframe.isweekly ? 60. * 24 * 7 :
timeframe.ismonthly ? 60. * 24 * 30.4375 : na)
f_timeFrom(_from, _qty, _units) =>
int _timeFrom = na
_unit = str.replace_all(_units, "s", "")
_t = _from == "bar" ? time : _from == "close" ? time_close : timenow
if _units == "chart"
_timeFrom := int(_t + (f_tfInMinutes() * 60 * 1000 * _qty))
else
_year = year(_t) + (_unit == "year" ? int(_qty) : 0)
_month = month(_t) + (_unit == "month" ? int(_qty) : 0)
_day = dayofmonth(_t) + (_unit == "day" ? int(_qty) : 0)
_hour = hour(_t) + (_unit == "hour" ? int(_qty) : 0)
_minute = minute(_t) + (_unit == "minute" ? int(_qty) : 0)
_second = second(_t) + (_unit == "econd" ? int(_qty) : 0)
_timeFrom := timestamp(_year, _month, _day, _hour, _minute, _second)
var float lastTradeTime = na
if nz(ta.change(strategy.position_size), time) != 0
lastTradeTime := time
delayElapsed = f_timeFrom("bar", i_qtyTimeUnits, i_timeUnits) >= lastTradeTime
//Calculate ATR based SL and TP
ATRlength = input.int(title="ATR Length", defval=14, minval=1)
smoothing = input.string(title="ATR Smoothing", defval="EMA", options=["SMA", "EMA", "WMA"])
m = input.float(2, "ATR Multiplier")
rrr = input.float(defval= 1.5,title='Risk Reward Ratio',minval=1)
src1 = input.source(high)
src2 = input.source(low)
ma_function(source, length) =>
if smoothing == "EMA"
ta.ema(source, length)
else
if smoothing == "SMA"
ta.sma(source, length)
else
if smoothing == "WMA"
ta.wma(source, length)
//a = ma_function(ta.atr(true), length) * m
x1 = ma_function(ta.tr(true), ATRlength) * m + src1
x2 = src2 - ma_function(ta.tr(true), ATRlength) * m
//Buy and Sell algos
BuySignal = barstate.isconfirmed and bullish and avgS>avgS[1] and strategy.position_size==0
SellSignal = barstate.isconfirmed and not bullish and avgS<avgS[1] and strategy.position_size==0
//Exit signals
ExL = not bullishS and bullishS[1]
ExS = bullishS and not bullishS[1]
// Enable Long Strategy
enable_long_strategy = input.bool(true, title='Enable Long Strategy', group='SL/TP For Long Strategy', inline='1')
long_stoploss_value = ta.valuewhen(BuySignal, x2, 0)
long_takeprofit_value = ta.valuewhen(BuySignal,src1,0) + (rrr*(ta.valuewhen(BuySignal, close, 0)-long_stoploss_value))
// Enable Short Strategy
enable_short_strategy = input.bool(true, title='Enable Short Strategy', group='SL/TP For Short Strategy', inline='3')
short_stoploss_value = ta.valuewhen(SellSignal, x1, 0)
short_takeprofit_value = ta.valuewhen(SellSignal,src2,0) -(rrr*(short_stoploss_value-ta.valuewhen(SellSignal, close, 0)))
// Plot Stoploss & Take Profit Levels
LSL=plot(strategy.position_size >0?long_stoploss_value:na, color=color.new(#ff0000, 0), style=plot.style_linebr, linewidth=2, title='Long SL Level')
LTP=plot(strategy.position_size >0?long_takeprofit_value:na, color=color.new(#008000, 0), style=plot.style_linebr, linewidth=2, title='Long TP Level')
SSL=plot(strategy.position_size <0?short_stoploss_value:na, color=color.new(#ff0000, 0), style=plot.style_linebr, linewidth=2, title='Short SL Level')
STP=plot(strategy.position_size <0?short_takeprofit_value:na, color=color.new(#008000, 0), style=plot.style_linebr, linewidth=2, title='Short TP Level')
EP = plot(strategy.opentrades>0 ?strategy.position_avg_price:na,color=color.new(color.white, 50), style=plot.style_linebr, linewidth=2, title='Entry Price level')
fill(EP,LSL,color=color.new(color.red,80), title='loss area')
fill(EP,LTP,color=color.new(color.green,80), title='profit area')
fill(EP,SSL,color=color.new(color.red,80), title='loss area')
fill(EP,STP,color=color.new(color.green,80), title='profit area')
// Date Range
start_date = input.int(title='Start Date', defval=1, minval=1, maxval=31, group='Date Range')
start_month = input.int(title='Start Month', defval=1, minval=1, maxval=12, group='Date Range')
start_year = input.int(title='Start Year', defval=2020, minval=1800, maxval=3000, group='Date Range')
end_date = input.int(title='End Date', defval=1, minval=1, maxval=3, group='Date Range')
end_month = input.int(title='End Month', defval=1, minval=1, maxval=12, group='Date Range')
end_year = input.int(title='End Year', defval=2077, minval=2022, maxval=3000, group='Date Range')
in_date_range = time >= timestamp(syminfo.timezone, start_year, start_month, start_date, 0, 0) and time < timestamp(syminfo.timezone, end_year, end_month, end_date, 0, 0)
// Long Strategy
if BuySignal and in_date_range and enable_long_strategy == true and strategy.position_size==0
strategy.entry('Long', strategy.long, alert_message='Open Long Position')
strategy.exit('Long SL/TP', from_entry='Long',qty_percent=100,stop=long_stoploss_value, limit=long_takeprofit_value,alert_message='Your Long SL/TP Limit As Been Triggered.')
// Short Strategy
if SellSignal and in_date_range and enable_short_strategy == true and strategy.position_size==0
strategy.entry('Short', strategy.short, alert_message='Open Short Position')
strategy.exit('Short SL/TP', from_entry='Short',qty_percent=100, stop=short_stoploss_value, limit=short_takeprofit_value,alert_message='Your Short SL/TP Limit As Been Triggered.')
strategy.close('Long', when=ExL, alert_message='Close Long Position')
strategy.close('Short', when=ExS, alert_message='Close Short Position')
if(BarsSinceFirstEntry()>CloseTradeAfterXBars and strategy.position_size!=0 )
strategy.close_all(comment = "close Max Bars")
///////////////////////////// --- BEGIN TESTER CODE --- ////////////////////////
// COPY below into your strategy to enable display
////////////////////////////////////////////////////////////////////////////////
// Declare performance tracking variables
drawTester = input.bool(true, "Draw Tester")
var balance = strategy.initial_capital
var drawdown = 0.0
var maxDrawdown = 0.0
var maxBalance = 0.0
var totalWins = 0
var totalLoss = 0
// Prepare stats table
var table testTable = table.new(position.top_right, 5, 2, border_width=1)
f_fillCell(_table, _column, _row, _title, _value, _bgcolor, _txtcolor) =>
_cellText = _title + "\n" + _value
table.cell(_table, _column, _row, _cellText, bgcolor=_bgcolor, text_color=_txtcolor)
// Custom function to truncate (cut) excess decimal places
truncate(_number, _decimalPlaces) =>
_factor = math.pow(10, _decimalPlaces)
int(_number * _factor) / _factor
// Draw stats table
var bgcolor = color.new(color.black,0)
if drawTester
if barstate.islastconfirmedhistory
// Update table
dollarReturn = strategy.netprofit
f_fillCell(testTable, 0, 0, "Total Trades:", str.tostring(strategy.closedtrades), bgcolor, color.white)
f_fillCell(testTable, 0, 1, "Win Rate:", str.tostring(truncate((strategy.wintrades/strategy.closedtrades)*100,2)) + "%", bgcolor, color.white)
f_fillCell(testTable, 1, 0, "Starting:", "$" + str.tostring(strategy.initial_capital), bgcolor, color.white)
f_fillCell(testTable, 1, 1, "Ending:", "$" + str.tostring(truncate(strategy.initial_capital + strategy.netprofit,2)), bgcolor, color.white)
f_fillCell(testTable, 2, 0, "Avg Win:", "$"+ str.tostring(truncate(strategy.grossprofit / strategy.wintrades, 2)), bgcolor, color.white)
f_fillCell(testTable, 2, 1, "Avg Loss:", "$"+ str.tostring(truncate(strategy.grossloss / strategy.losstrades, 2)), bgcolor, color.white)
f_fillCell(testTable, 3, 0, "Profit Factor:", str.tostring(truncate(strategy.grossprofit / strategy.grossloss,2)), strategy.grossprofit > strategy.grossloss ? color.green : color.red, color.white)
f_fillCell(testTable, 3, 1, "Max Runup:", str.tostring(truncate(strategy.max_runup, 2 )), bgcolor, color.white)
f_fillCell(testTable, 4, 0, "Return:", (dollarReturn > 0 ? "+" : "") + str.tostring(truncate((dollarReturn / strategy.initial_capital)*100,2)) + "%", dollarReturn > 0 ? color.green : color.red, color.white)
f_fillCell(testTable, 4, 1, "Max DD:", str.tostring(truncate((strategy.max_drawdown / strategy.equity) * 100 ,2)) + "%", color.red, color.white)
// --- END TESTER CODE --- ///////////////
// Monthly Table Performance Dashboard By @QuantNomad
//
// Dashboard Table Text Size
i_tableTextSize = input.string(title="Dashboard Size", defval="Normal", options=["Auto", "Huge", "Large", "Normal", "Small", "Tiny"], group="Dashboards")
table_text_size(s) =>
switch s
"Auto" => size.auto
"Huge" => size.huge
"Large" => size.large
"Normal" => size.normal
"Small" => size.small
=> size.tiny
tableTextSize = table_text_size(i_tableTextSize)
i_showMonthlyPerformance = input.bool(true, 'Monthly Performance', group='Dashboards', inline="Show Dashboards")
i_monthlyReturnPercision = 2
if i_showMonthlyPerformance
new_month = month(time) != month(time[1])
new_year = year(time) != year(time[1])
eq = strategy.equity
bar_pnl = eq / eq[1] - 1
cur_month_pnl = 0.0
cur_year_pnl = 0.0
// Current Monthly P&L
cur_month_pnl := new_month ? 0.0 :
(1 + cur_month_pnl[1]) * (1 + bar_pnl) - 1
// Current Yearly P&L
cur_year_pnl := new_year ? 0.0 :
(1 + cur_year_pnl[1]) * (1 + bar_pnl) - 1
// Arrays to store Yearly and Monthly P&Ls
var month_pnl = array.new_float(0)
var month_time = array.new_int(0)
var year_pnl = array.new_float(0)
var year_time = array.new_int(0)
last_computed = false
if (not na(cur_month_pnl[1]) and (new_month or barstate.islastconfirmedhistory))
if (last_computed[1])
array.pop(month_pnl)
array.pop(month_time)
array.push(month_pnl , cur_month_pnl[1])
array.push(month_time, time[1])
if (not na(cur_year_pnl[1]) and (new_year or barstate.islastconfirmedhistory))
if (last_computed[1])
array.pop(year_pnl)
array.pop(year_time)
array.push(year_pnl , cur_year_pnl[1])
array.push(year_time, time[1])
last_computed := barstate.islastconfirmedhistory ? true : nz(last_computed[1])
// Monthly P&L Table
var monthly_table = table(na)
if (barstate.islastconfirmedhistory)
monthly_table := table.new(position.bottom_right, columns = 14, rows = array.size(year_pnl) + 1, border_width = 1)
table.cell(monthly_table, 0, 0, "", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 1, 0, "Jan", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 2, 0, "Feb", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 3, 0, "Mar", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 4, 0, "Apr", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 5, 0, "May", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 6, 0, "Jun", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 7, 0, "Jul", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 8, 0, "Aug", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 9, 0, "Sep", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 10, 0, "Oct", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 11, 0, "Nov", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 12, 0, "Dec", bgcolor = #cccccc, text_size=tableTextSize)
table.cell(monthly_table, 13, 0, "Year", bgcolor = #999999, text_size=tableTextSize)
for yi = 0 to array.size(year_pnl) - 1
table.cell(monthly_table, 0, yi + 1, str.tostring(year(array.get(year_time, yi))), bgcolor = #cccccc, text_size=tableTextSize)
y_color = array.get(year_pnl, yi) > 0 ? color.new(color.teal, transp = 40) : color.new(color.gray, transp = 40)
table.cell(monthly_table, 13, yi + 1, str.tostring(math.round(array.get(year_pnl, yi) * 100, i_monthlyReturnPercision)), bgcolor = y_color, text_color=color.new(color.white, 0),text_size=tableTextSize)
for mi = 0 to array.size(month_time) - 1
m_row = year(array.get(month_time, mi)) - year(array.get(year_time, 0)) + 1
m_col = month(array.get(month_time, mi))
m_color = array.get(month_pnl, mi) > 0 ? color.new(color.teal, transp = 40) : color.new(color.maroon, transp = 40)
table.cell(monthly_table, m_col, m_row, str.tostring(math.round(array.get(month_pnl, mi) * 100, i_monthlyReturnPercision)), bgcolor = m_color, text_color=color.new(color.white, 0), text_size=tableTextSize)
Comentários