本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo
//@version=5
indicator("Breakout Detector (Previous MTF High Low Levels) [LuxAlgo]", 'LuxAlgo - Breakout Detector (Previous MTF High Low Levels)', max_lines_count=500, max_boxes_count=500, max_labels_count=500, max_bars_back=2000, overlay=true)
//------------------------------------------------------------------------------
//Settings
//-----------------------------------------------------------------------------{
s5 = ' '
s7 = ' '
s10 = ' '
opt = input.string ( 'HTF' ,'Option: '+s10 , options= [ 'HTF' , 'Mult' ] , inline='a', group='Set Higher TimeFrame')
res = input.timeframe( 'D' , '• HTF' +s10+s5 , inline='b', group='Set Higher TimeFrame')
mlt = input.int ( 3 , '• Mult'+s10+s5, minval =1, maxval =20, tooltip='Multiple of Current TF', inline='c', group='Set Higher TimeFrame')
iTP = input.string ( 'W : L' , 'SL / TP ' , options= [ 'W : L' , 'W% : L%' ] , inline='1', group='Set Win / Loss Level')
w = input.int ( 2 , 'W : L'+s7 , minval = 0 , inline='3', group='Set Win / Loss Level')
l = input.int ( 1 , ':' , minval = 0 , tooltip='-> Loss Settings (L)' , inline='3', group='Set Win / Loss Level')
percW = input.float ( 5 , 'W% : L%' , minval = 0.01 , inline='2', group='Set Win / Loss Level') / 100
percL = input.float ( 2 , ':' , minval = 0.01 , inline='2', group='Set Win / Loss Level') / 100
loss = input.string ( 'RCM' , 'Base:'+s7+s10, options= ['RCM', 'ATR', 'Last Swing'] , inline='4', group= 'Loss Settings (L)' )
RcmAtrM = input.int ( 3 ,'• Multiple'+s10, minval =1, maxval =20 , tooltip= 'Multiple Of:\n• Average True Range\n• Range Cumulative Mean'
, inline='5', group= 'Loss Settings (L)' )
len = input.int ( 10 ,'• Swing Length', minval =1, maxval =20 , tooltip='Swing (Length Left)' , inline='6', group= 'Loss Settings (L)' )
INV = color.new (color.blue , 100)
cTP = input.color (#2157f3 ,'TP')
cSL = input.color (#ff5d00 ,'SL')
border = input.string (line.style_dotted, 'Borders', options=[line.style_solid, line.style_dashed, line.style_dotted], tooltip= "When TP/SL not reached")
bcol = input.bool ( true , 'Show Timeframe Change' , group= "Extra" )
falseOutBreak = input.bool ( true , 'Detect False Breakout' , inline = 'cFail', group= "Extra" ), x = falseOutBreak ? 2 : 0
cFail = input.color ( color.new(color.fuchsia, 80), '' , inline = 'cFail', group= "Extra" )
stopAtEndHTF = input.bool ( false , 'Cancel TP/SL at end of HTF' , group= "Extra" )
//Dashboard
showDash = input.bool ( true , 'Show Dashboard' , group= 'Dashboard' )
dashLoc = input.string ( 'Top Right' , 'Location' , options = ['Top Right', 'Bottom Right', 'Bottom Left'] , group= 'Dashboard' )
textSize = input.string ( 'Small' , 'Size' , options = ['Tiny', 'Small', 'Normal'] , group= 'Dashboard' )
//-----------------------------------------------------------------------------}
//Calculations
//-----------------------------------------------------------------------------{
n = bar_index
ph = fixnan(ta.pivothigh(len, 1))
pl = fixnan(ta.pivotlow (len, 1))
atr= ta.atr(200)
rcm= ta.cum(high - low) / (n+1) // RCM (range cumulative mean)
//-----------------------------------------------------------------------------}
//UDT
//-----------------------------------------------------------------------------{
type Tbreak
bool act
int idx
float prc
float stp
bool fail
float tp
bool prof
//-----------------------------------------------------------------------------}
//Methods/Functions
//-----------------------------------------------------------------------------{
p(int x, float y) => chart.point.from_index(x, y)
method box(string s, Tbreak obj) =>
// TP box
box.new(obj.idx, obj.prc, n, obj.tp , bgcolor= color.new(cTP, 85), border_color=
s == 'fail' ? INV : s == 'prof' or (obj.prc > obj.stp and close > obj.prc)
or (obj.prc < obj.stp and close < obj.prc) ? cTP : INV ,
border_style = s == 'none' and ((obj.prc > obj.stp and close > obj.prc and close < obj.tp and close > obj.stp)
or (obj.prc < obj.stp and close < obj.prc and close > obj.tp and close < obj.stp)) ? border : line.style_solid)
// SL box
box.new(obj.idx, obj.prc, n, obj.stp, bgcolor= color.new(cSL, 85), border_color=
s == 'prof' ? INV : s == 'fail' or (obj.prc > obj.stp and close < obj.prc)
or (obj.prc < obj.stp and close > obj.prc) ? cSL : INV ,
border_style = s == 'none' and ((obj.prc > obj.stp and close < obj.prc and close < obj.tp and close > obj.stp)
or (obj.prc < obj.stp and close > obj.prc and close > obj.tp and close < obj.stp)) ? border : line.style_solid)
method update(Tbreak br, bool a, int i, float p, float s, bool f, float t, bool w) => br.act := a, br.idx := i, br.prc := p, br.stp := s, br.fail := f, br.tp := t, br.prof := w
method lab(string s, string pos, color col, color txtcol) => label.new(
n , close
, yloc = pos == 'top' ? yloc.abovebar : yloc.belowbar
, style = pos == 'top' ? label.style_label_down : label.style_label_up
, color = col
, textcolor = txtcol
, size = size.small
, text = s
)
res() =>
M = timeframe.multiplier * mlt, strM = str.tostring(M)
opt == 'HTF' ? timeframe.in_seconds(timeframe.period)
>= timeframe.in_seconds(res)
? ''
: res
: timeframe.isdaily ? strM + 'D'
: timeframe.isweekly ? strM + 'W'
: timeframe.ismonthly ? strM + 'M'
: M >= 1440
? str.tostring(math.round(M / 1440)) + 'D'
: strM
formatRes(res) =>
out = res
if not str.contains(res, 'D') and not str.contains(res, 'W') and not str.contains(res, 'M')
nRes = str.tonumber(res)
if nRes % 60 == 0
out := str.format('{0}{1}', nRes / 60, 'h' )
else
out := str.format('{0}{1}', nRes , 'min')
out
//-----------------------------------------------------------------------------}
//Execution
//-----------------------------------------------------------------------------{
fres = res(), tfCh = timeframe.change(fres)
var line prevh = na, var crossph = false, var max = high, var max_x1 = 0
var line prevl = na, var crosspl = false, var min = low , var min_x1 = 0
var countBrOut_TT = 0, var count_F_BrOut_TT = 0, var countTP_TT = 0, var countSL_TT = 0, var countWn_TT = 0, var countLs_TT = 0
var countBrOut_Bl = 0, var count_F_BrOut_Bl = 0, var countTP_Bl = 0, var countSL_Bl = 0, var countWn_Bl = 0, var countLs_Bl = 0
var countBrOut_Br = 0, var count_F_BrOut_Br = 0, var countTP_Br = 0, var countSL_Br = 0, var countWn_Br = 0, var countLs_Br = 0
brOutBl = false, falseBl = false, prof_Bl = false, fail_Bl = false, brOutBr = false, falseBr = false, prof_Br = false, fail_Br = false
if tfCh
if not crossph
prevh.set_x2(max_x1)
if not crosspl
prevl.set_x2(min_x1)
prevh := line.new(max_x1, max, n, max, color = #f23645)
prevl := line.new(min_x1, min, n, min, color = #089981)
max := high, max_x1 := n, crossph := false
min := low , min_x1 := n, crosspl := false
else //Update max/min and anchoring points
max := math.max(high , max )
max_x1 := max == high ? n : max_x1
min := math.min(low , min )
min_x1 := min == low ? n : min_x1
if not crossph
prevh.set_x2(n)
if close > prevh.get_y2()
crossph := true
if not crosspl
prevl.set_x2(n)
if close < prevl.get_y2()
crosspl := true
var bxTopBreak = Tbreak.new(false, na, na, na, na, na, na)
var bxBtmBreak = Tbreak.new(false, na, na, na, na, na, na)
//Break-out
ATRok = iTP == 'W : L' and loss == 'ATR' ? n > 200 : true
top = prevh.get_y2(), breakTop = crossph and not crossph[1] and ATRok and not bxTopBreak.act
btm = prevl.get_y2(), breakBtm = crosspl and not crosspl[1] and ATRok and not bxBtmBreak.act
method poly(Tbreak T) =>
p = array.new<chart.point>()
p.unshift(chart.point.from_index( n , T.prc))
p.unshift(chart.point.from_index( n , T.tp ))
p.unshift(chart.point.from_index(T.idx, T.tp ))
p.unshift(chart.point.from_index(T.idx, T.prc))
polyline.new(p, line_color=INV
, fill_color=color.new(color.green, 75))
p := array.new<chart.point>()
p.unshift(chart.point.from_index( n , T.stp))
p.unshift(chart.point.from_index(T.idx, T.stp))
p.unshift(chart.point.from_index(T.idx, T.prc))
p.unshift(chart.point.from_index( n , T.prc))
polyline.new(p, line_color=INV
, fill_color=color.new(color.red , 75))
for poly in polyline.all
poly.delete()
// While already in position, there is a break in the same direction, this will be ignored
// example -> bullish position, bullish break -> ignored
switch
breakTop =>
brOutBl := true, countBrOut_TT += 1, countBrOut_Bl += 1, '▲'.lab('btm', color(na), #089981)
ls = iTP == 'W% : L%'
? close * (1 - percL)
: loss == 'ATR'
? close - (atr * RcmAtrM)
: loss == 'RCM'
? close - (rcm * RcmAtrM)
: pl
pf = iTP == 'W% : L%'
? close * (1 + percW)
: loss == 'ATR'
? close + ((atr * RcmAtrM) * (w/l))
: loss == 'RCM'
? close + ((rcm * RcmAtrM) * (w/l))
: close + (close - pl) * (w/l)
bxTopBreak.update(true , n , close, ls, false, pf, false)
bxTopBreak.poly()
bxTopBreak.act =>
switch
breakBtm or (stopAtEndHTF and tfCh) =>
switch
close >= bxTopBreak.prc =>
switch
close < bxTopBreak.tp => countWn_TT += 1, countWn_Bl += 1
=> countWn_TT += 1, countWn_Bl += 1
, countTP_TT += 1, countTP_Bl += 1
=>
switch
close > bxTopBreak.stp => countLs_TT += 1, countLs_Bl += 1
=> countLs_TT += 1, countLs_Bl += 1
, countSL_TT += 1, countSL_Bl += 1
bxTopBreak.act := false
'none'.box(bxTopBreak)
(n - bxTopBreak.idx < x and close < top) =>
falseBl := true
, 'F'.lab('top', cFail, color.white)
, count_F_BrOut_TT += 1
, count_F_BrOut_Bl += 1
, bxTopBreak.update(false, na, na, na, na, na, na)
high > bxTopBreak.tp and not bxTopBreak.prof =>
bxTopBreak.prof := true
, prof_Bl := true
, 'prof'.box(bxTopBreak)
, countWn_TT += 1, countWn_Bl += 1
, countTP_TT += 1, countTP_Bl += 1
, bxTopBreak.update(false, na, na, na, na, na, na)
close < bxTopBreak.stp and not bxTopBreak.fail =>
bxTopBreak.fail := true
, fail_Bl := true
, 'fail'.box(bxTopBreak)
, countLs_TT += 1, countLs_Bl += 1
, countSL_TT += 1, countSL_Bl += 1
, bxTopBreak.update(false, na, na, na, na, na, na)
bxTopBreak.poly()
(bxTopBreak.fail[1] or
bxTopBreak.prof[1]) => bxTopBreak.update(false, na, na, na, na, na, na)
switch
breakBtm =>
brOutBr := true, countBrOut_TT += 1, countBrOut_Br += 1, '▼'.lab('top', color(na), #f23645)
ls = iTP == 'W% : L%'
? close * (1 + percL)
: loss == 'ATR'
? close + (atr * RcmAtrM)
: loss == 'RCM'
? close + (rcm * RcmAtrM)
: ph
pf = iTP == 'W% : L%'
? close * (1 - percW)
: loss == 'ATR'
? close - ((atr * RcmAtrM) * (w/l))
: loss == 'RCM'
? close - ((rcm * RcmAtrM) * (w/l))
: close - (ph - close) * (w/l)
bxBtmBreak.update(true , n , close, ls, false, pf, false)
bxBtmBreak.poly()
bxBtmBreak.act =>
switch
breakTop or (stopAtEndHTF and tfCh) =>
switch
close <= bxBtmBreak.prc =>
switch
close > bxBtmBreak.tp => countWn_TT += 1, countWn_Br += 1
=> countWn_TT += 1, countWn_Br += 1
, countTP_TT += 1, countTP_Br += 1
=>
switch
close < bxBtmBreak.stp => countLs_TT += 1, countLs_Br += 1
=> countLs_TT += 1, countLs_Br += 1
, countSL_TT += 1, countSL_Br += 1
bxBtmBreak.act := false
'none'.box(bxBtmBreak)
(n - bxBtmBreak.idx < x and close > btm) =>
falseBr := true
, 'F'.lab('btm', cFail, color.white)
, count_F_BrOut_TT += 1, count_F_BrOut_Br += 1
, bxBtmBreak.update(false, na, na, na, na, na, na)
low < bxBtmBreak.tp and not bxBtmBreak.prof =>
bxBtmBreak.prof := true
, prof_Br := true
, 'prof'.box(bxBtmBreak)
, countWn_TT += 1, countWn_Br += 1
, countTP_TT += 1, countTP_Br += 1
, bxBtmBreak.update(false, na, na, na, na, na, na)
close > bxBtmBreak.stp and not bxBtmBreak.fail =>
bxBtmBreak.fail := true
, fail_Br := true
, 'fail'.box(bxBtmBreak)
, countLs_TT += 1, countLs_Br += 1
, countSL_TT += 1, countSL_Br += 1
, bxBtmBreak.update(false, na, na, na, na, na, na)
bxBtmBreak.poly()
(bxBtmBreak.fail[1] or
bxBtmBreak.prof[1]) => bxBtmBreak.update(false, na, na, na, na, na, na)
if breakTop[1]
bxBtmBreak.update(false, na, na, na, false, na, na)
if breakBtm[1]
bxTopBreak.update(false, na, na, na, false, na, na)
//-----------------------------------------------------------------------------}
//Plot
//-----------------------------------------------------------------------------{
t1 = plot(bxTopBreak.prc, style=plot.style_linebr, color=color.new(cTP, 50), display=display.none)
t2 = plot(bxTopBreak.stp, style=plot.style_linebr, color=color.new(cTP, 50), display=display.none)
b1 = plot(bxBtmBreak.prc, style=plot.style_linebr, color=color.new(cSL, 50), display=display.none)
b2 = plot(bxBtmBreak.stp, style=plot.style_linebr, color=color.new(cSL, 50), display=display.none)
//-----------------------------------------------------------------------------}
//Timeframe Change
//-----------------------------------------------------------------------------{
bgcolor(bcol and tfCh ? color.new(color.silver, 93) : na)
//-----------------------------------------------------------------------------}
//Dashboard
//-----------------------------------------------------------------------------{
var table_position = dashLoc == 'Bottom Left' ? position.bottom_left
: dashLoc == 'Top Right' ? position.top_right
: position.bottom_right
var table_size = textSize == 'Tiny' ? size.tiny
: textSize == 'Small' ? size.small
: size.normal
var tb = table.new(table_position, falseOutBreak ? 7 : 6, 5
, bgcolor = #1e222d
, border_color = #373a46
, border_width = 1
, frame_color = #373a46
, frame_width = 1)
if showDash
if barstate.isfirst
tb .cell(0, 0, '' , text_color = color.white, text_size = table_size)
tb .cell(0, 1, '' , text_color = color.white, text_size = table_size)
tb .cell(1, 1, 'Breakouts' , text_color = color.white, text_size = table_size)
tb .cell(2, 1, 'Wins' , text_color = color.white, text_size = table_size)
tb .cell(3, 1, '-> TP hit' , text_color = color.white, text_size = table_size)
tb .cell(4, 1, 'Losses' , text_color = color.white, text_size = table_size)
tb .cell(5, 1, '-> SL hit' , text_color = color.white, text_size = table_size)
if falseOutBreak
tb.cell(6, 1, 'False\nBreakouts' , text_color = color.white, text_size = table_size)
tb .cell(0, 2, 'Bullish' , text_color = color.white, text_size = table_size)
tb .cell(0, 3, 'Bearish' , text_color = color.white, text_size = table_size)
tb .cell(0, 4, 'Total' , text_color = color.white, text_size = table_size)
if barstate.islast
tb .merge_cells
(0, 0, falseOutBreak ? 6 : 5, 0 )
tb .cell(0, 0, str.format('HTF = {0}'
, formatRes (fres) ), text_color = color.white, text_size = table_size)
tb .cell(1, 2, str.tostring(countBrOut_Bl ), text_color = color.white, text_size = table_size)
tb .cell(1, 3, str.tostring(countBrOut_Br ), text_color = color.white, text_size = table_size)
tb .cell(1, 4, str.tostring(countBrOut_TT ), text_color = color.white, text_size = table_size)
tb .cell(2, 2, str.tostring(countWn_Bl ), text_color = color.white, text_size = table_size)
tb .cell(2, 3, str.tostring(countWn_Br ), text_color = color.white, text_size = table_size)
tb .cell(2, 4, str.tostring(countWn_TT ), text_color = color.white, text_size = table_size)
tb .cell(3, 2, str.tostring(countTP_Bl ), text_color = color.white, text_size = table_size)
tb .cell(3, 3, str.tostring(countTP_Br ), text_color = color.white, text_size = table_size)
tb .cell(3, 4, str.tostring(countTP_TT ), text_color = color.white, text_size = table_size)
tb .cell(4, 2, str.tostring(countLs_Bl ), text_color = color.white, text_size = table_size)
tb .cell(4, 3, str.tostring(countLs_Br ), text_color = color.white, text_size = table_size)
tb .cell(4, 4, str.tostring(countLs_TT ), text_color = color.white, text_size = table_size)
tb .cell(5, 2, str.tostring(countSL_Bl ), text_color = color.white, text_size = table_size)
tb .cell(5, 3, str.tostring(countSL_Br ), text_color = color.white, text_size = table_size)
tb .cell(5, 4, str.tostring(countSL_TT ), text_color = color.white, text_size = table_size)
if falseOutBreak
tb.cell(6, 2, str.tostring(count_F_BrOut_Bl), text_color = color.white, text_size = table_size)
tb.cell(6, 3, str.tostring(count_F_BrOut_Br), text_color = color.white, text_size = table_size)
tb.cell(6, 4, str.tostring(count_F_BrOut_TT), text_color = color.white, text_size = table_size)
//-----------------------------------------------------------------------------}
//Alerts
//-----------------------------------------------------------------------------{
alertcondition(brOutBl,' Bullish Breakout' , 'Bullish Breakout' )
alertcondition(falseBl,' Bullish False Breakout', 'Bullish False Breakout')
alertcondition(prof_Bl,' Bullish TP' , 'Bullish TP' )
alertcondition(fail_Bl,' Bullish Fail' , 'Bullish Fail' )
alertcondition(brOutBr,' Bearish Breakout' , 'Bearish Breakout' )
alertcondition(falseBr,' Bearish False Breakout', 'Bearish False Breakout')
alertcondition(prof_Br,' Bearish TP' , 'Bearish TP' )
alertcondition(fail_Br,'Bearish Fail' , 'Bearish Fail' )
//-----------------------------------------------------------------------------}