本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Uncle_the_shooter
//@version=6
indicator('Breakout Lines + TP/SL', overlay = true, max_lines_count = 500, max_labels_count = 500, max_boxes_count = 500)
// INPUTS
left = input.int(20, 'Pivot Left')
right = input.int(20, 'Pivot Right')
maxBars = input.int(500, 'Max extend bars from detection (from the moment the pivot is detected)', minval = 10, maxval = 500)
maxHigh = input.int(5, 'Show maximum last N HIGH lines (0 = all)', minval = 0, group = 'Line Limits')
maxLow = input.int(5, 'Show maximum last N LOW lines (0 = all)', minval = 0, group = 'Line Limits')
transp = input.int(50, 'Transparency (0-100)', minval = 0, maxval = 100, group = 'Colors')
// TREND LINE COLORS (these inputs also control signals, TP/SL levels, and fills)
highTrendColor = input.color(#ef5350, 'High Trendline Color (Resistance)', group = 'Colors')
lowTrendColor = input.color(#26a69a, 'Low Trendline Color (Support)', group = 'Colors')
// Signal and TP/SL colors are automatically linked to trendline colors
buyLabelColor = lowTrendColor
sellLabelColor = highTrendColor
buyColorLight = color.new(buyLabelColor, 40)
sellColorLight = color.new(sellLabelColor, 40)
buyFill = color.new(buyLabelColor, 70)
sellFill = color.new(sellLabelColor, 70)
// TP/SL SETTINGS
show_buy_sell_labels = input.bool(false, "Show BUY/SELL Labels", group = "Signals")
show_triangles = input.bool(true, "Show Triangle Signals", group = "Signals")
show_targets = input.bool(true, "Show TP/SL Targets", group = "Targets")
use_atr_sl = input.bool(true, "SL = ATR × instead of %", group = "Targets")
atr_period = input.int(14, "ATR Period", minval=1, group = "Targets")
sl_atr_mult = input.float(1.5, "SL ATR Multiplier", step=0.1, group = "Targets")
sl_percent = input.float(1.0, "SL % from Entry", step=0.1, group = "Targets")
rr_tp1 = input.float(1.0, "TP1 Risk-Reward Ratio", step=0.1, group = "Targets")
rr_tp2 = input.float(2.0, "TP2 Risk-Reward Ratio", step=0.1, group = "Targets")
rr_tp3 = input.float(3.0, "TP3 Risk-Reward Ratio", step=0.1, group = "Targets")
// DISPLAY
show_sl_level = input.bool(true, "Show SL Level", group = "Display")
show_tp1_level = input.bool(true, "Show TP1 Level", group = "Display")
show_tp2_level = input.bool(true, "Show TP2 Level", group = "Display")
show_tp3_level = input.bool(true, "Show TP3 Level", group = "Display")
// CLEANUP FUNCTION
cleanupLines(array<line> linesArr, array<int> detArr, array<bool> activeArr, int maxShow) =>
if maxShow > 0 and array.size(linesArr) > maxShow
while array.size(linesArr) > maxShow
oldLine = array.shift(linesArr)
line.delete(oldLine)
array.shift(detArr)
array.shift(activeArr)
// PIVOTS
ph = ta.pivothigh(high, left, right)
pl = ta.pivotlow(low, left, right)
// PIVOT MEMORY
var float prevHighPrice = na
var int prevHighBar = na
var float prevLowPrice = na
var int prevLowBar = na
// LINE ARRAYS
var array<line> highLines = array.new_line()
var array<int> highDetection = array.new_int()
var array<bool> highActive = array.new_bool()
var array<line> lowLines = array.new_line()
var array<int> lowDetection = array.new_int()
var array<bool> lowActive = array.new_bool()
// NEW HIGH PIVOT
if not na(ph)
pivotBar = bar_index - right
pivotPrice = ph
detectionBar = bar_index
if not na(prevHighPrice)
dx = pivotBar - prevHighBar
slope = dx != 0 ? (pivotPrice - prevHighPrice) / float(dx) : 0.0
x2_ext = math.min(detectionBar + maxBars, bar_index + 500)
y2_ext = prevHighPrice + slope * float(x2_ext - prevHighBar)
newLine = line.new(prevHighBar, prevHighPrice, x2_ext, y2_ext, width = 2, color = color.new(highTrendColor, transp))
array.push(highLines, newLine)
array.push(highDetection, detectionBar)
array.push(highActive, true)
prevHighPrice := pivotPrice
prevHighBar := pivotBar
// NEW LOW PIVOT
if not na(pl)
pivotBar = bar_index - right
pivotPrice = pl
detectionBar = bar_index
if not na(prevLowPrice)
dx = pivotBar - prevLowBar
slope = dx != 0 ? (pivotPrice - prevLowPrice) / float(dx) : 0.0
x2_ext = math.min(detectionBar + maxBars, bar_index + 500)
y2_ext = prevLowPrice + slope * float(x2_ext - prevLowBar)
newLine = line.new(prevLowBar, prevLowPrice, x2_ext, y2_ext, width = 2, color = color.new(lowTrendColor, transp))
array.push(lowLines, newLine)
array.push(lowDetection, detectionBar)
array.push(lowActive, true)
prevLowPrice := pivotPrice
prevLowBar := pivotBar
// HIGH LINE CONTROL
breakUp = false
if array.size(highLines) > 0
for i = 0 to array.size(highLines) - 1
if array.get(highActive, i)
l = array.get(highLines, i)
detectionBar = array.get(highDetection, i)
linePrice = line.get_price(l, bar_index)
if close > linePrice or bar_index - detectionBar >= maxBars
line.set_extend(l, extend.none)
line.set_x2(l, bar_index)
line.set_y2(l, linePrice)
array.set(highActive, i, false)
if close > linePrice
breakUp := true
// LOW LINE CONTROL
breakDown = false
if array.size(lowLines) > 0
for i = 0 to array.size(lowLines) - 1
if array.get(lowActive, i)
l = array.get(lowLines, i)
detectionBar = array.get(lowDetection, i)
linePrice = line.get_price(l, bar_index)
if close < linePrice or bar_index - detectionBar >= maxBars
line.set_extend(l, extend.none)
line.set_x2(l, bar_index)
line.set_y2(l, linePrice)
array.set(lowActive, i, false)
if close < linePrice
breakDown := true
// CLEANUP ON EVERY BAR
if maxHigh > 0
cleanupLines(highLines, highDetection, highActive, maxHigh)
if maxLow > 0
cleanupLines(lowLines, lowDetection, lowActive, maxLow)
// ATR AND TP/SL VARIABLES
atr_val = ta.atr(atr_period)
var int trade_dir = 0
var float sl_level = na
var float extreme_level = na
var line entry_line = na
var label entry_label = na
var line sl_line = na
var label sl_label = na
var line tp1_line = na
var label tp1_label = na
var line tp2_line = na
var label tp2_label = na
var line tp3_line = na
var label tp3_label = na
var line extreme_line = na
var linefill risk_fill = na
var linefill reward_fill = na
var int entry_bar = na
// TP/SL ON BREAKUP (BUY)
if breakUp
if show_buy_sell_labels
label.new(bar_index, low, 'BUY', style = label.style_label_up, color = color.new(buyLabelColor, 40), textcolor = color.white, size = size.small)
if show_targets
// Delete previous objects
line.delete(entry_line)
label.delete(entry_label)
line.delete(sl_line)
label.delete(sl_label)
line.delete(tp1_line)
label.delete(tp1_label)
line.delete(tp2_line)
label.delete(tp2_label)
line.delete(tp3_line)
label.delete(tp3_label)
line.delete(extreme_line)
linefill.delete(risk_fill)
linefill.delete(reward_fill)
trade_dir := 1
entry_bar := bar_index
float entry_price = close
float risk_dist = use_atr_sl ? atr_val * sl_atr_mult : entry_price * (sl_percent / 100)
sl_level := entry_price - risk_dist
float tp1_p = entry_price + risk_dist * rr_tp1
float tp2_p = entry_price + risk_dist * rr_tp2
float tp3_p = entry_price + risk_dist * rr_tp3
float max_tp = na
if show_tp3_level
max_tp := tp3_p
if show_tp2_level
max_tp := na(max_tp) ? tp2_p : math.max(max_tp, tp2_p)
if show_tp1_level
max_tp := na(max_tp) ? tp1_p : math.max(max_tp, tp1_p)
extreme_level := max_tp
entry_line := line.new(bar_index, entry_price, bar_index + 1, entry_price, color = buyLabelColor, width = 1, extend = extend.right)
entry_label := label.new(bar_index, entry_price, "BUY " + str.tostring(entry_price, format.mintick), style = label.style_label_left, color = buyLabelColor, textcolor = color.white, size = size.small)
if show_sl_level
sl_line := line.new(bar_index, sl_level, bar_index + 1, sl_level, color = sellColorLight, width = 1, style = line.style_dashed, extend = extend.right)
sl_label := label.new(bar_index, sl_level, "SL " + str.tostring(sl_level, format.mintick), style = label.style_label_left, color = sellColorLight, textcolor = color.white, size = size.small)
if show_tp1_level
tp1_line := line.new(bar_index, tp1_p, bar_index + 1, tp1_p, color = buyColorLight, width = 1, extend = extend.right)
tp1_label := label.new(bar_index, tp1_p, "TP1 " + str.tostring(tp1_p, format.mintick), style = label.style_label_left, color = buyColorLight, textcolor = color.white, size = size.small)
if show_tp2_level
tp2_line := line.new(bar_index, tp2_p, bar_index + 1, tp2_p, color = buyColorLight, width = 1, extend = extend.right)
tp2_label := label.new(bar_index, tp2_p, "TP2 " + str.tostring(tp2_p, format.mintick), style = label.style_label_left, color = buyColorLight, textcolor = color.white, size = size.small)
if show_tp3_level
tp3_line := line.new(bar_index, tp3_p, bar_index + 1, tp3_p, color = buyColorLight, width = 1, style = line.style_dotted, extend = extend.right)
tp3_label := label.new(bar_index, tp3_p, "TP3 " + str.tostring(tp3_p, format.mintick), style = label.style_label_left, color = buyColorLight, textcolor = color.white, size = size.small)
if show_sl_level
risk_fill := linefill.new(entry_line, sl_line, sellFill)
float max_tp_for_fill = entry_price
if show_tp1_level
max_tp_for_fill := math.max(max_tp_for_fill, tp1_p)
if show_tp2_level
max_tp_for_fill := math.max(max_tp_for_fill, tp2_p)
if show_tp3_level
max_tp_for_fill := math.max(max_tp_for_fill, tp3_p)
if max_tp_for_fill > entry_price
extreme_line := line.new(bar_index, max_tp_for_fill, bar_index + 1, max_tp_for_fill, color = na, extend = extend.right)
reward_fill := linefill.new(entry_line, extreme_line, buyFill)
// TP/SL ON BREAKDOWN (SELL)
if breakDown
if show_buy_sell_labels
label.new(bar_index, high, 'SELL', style = label.style_label_down, color = color.new(sellLabelColor, 40), textcolor = color.white, size = size.small)
if show_targets
// Delete previous objects
line.delete(entry_line)
label.delete(entry_label)
line.delete(sl_line)
label.delete(sl_label)
line.delete(tp1_line)
label.delete(tp1_label)
line.delete(tp2_line)
label.delete(tp2_label)
line.delete(tp3_line)
label.delete(tp3_label)
line.delete(extreme_line)
linefill.delete(risk_fill)
linefill.delete(reward_fill)
trade_dir := -1
entry_bar := bar_index
float entry_price = close
float risk_dist = use_atr_sl ? atr_val * sl_atr_mult : entry_price * (sl_percent / 100)
sl_level := entry_price + risk_dist
float tp1_p = entry_price - risk_dist * rr_tp1
float tp2_p = entry_price - risk_dist * rr_tp2
float tp3_p = entry_price - risk_dist * rr_tp3
float min_tp = na
if show_tp3_level
min_tp := tp3_p
if show_tp2_level
min_tp := na(min_tp) ? tp2_p : math.min(min_tp, tp2_p)
if show_tp1_level
min_tp := na(min_tp) ? tp1_p : math.min(min_tp, tp1_p)
extreme_level := min_tp
entry_line := line.new(bar_index, entry_price, bar_index + 1, entry_price, color = sellLabelColor, width = 1, extend = extend.right)
entry_label := label.new(bar_index, entry_price, "SELL " + str.tostring(entry_price, format.mintick), style = label.style_label_left, color = sellLabelColor, textcolor = color.white, size = size.small)
if show_sl_level
sl_line := line.new(bar_index, sl_level, bar_index + 1, sl_level, color = sellColorLight, width = 1, style = line.style_dashed, extend = extend.right)
sl_label := label.new(bar_index, sl_level, "SL " + str.tostring(sl_level, format.mintick), style = label.style_label_left, color = sellColorLight, textcolor = color.white, size = size.small)
if show_tp1_level
tp1_line := line.new(bar_index, tp1_p, bar_index + 1, tp1_p, color = buyColorLight, width = 1, extend = extend.right)
tp1_label := label.new(bar_index, tp1_p, "TP1 " + str.tostring(tp1_p, format.mintick), style = label.style_label_left, color = buyColorLight, textcolor = color.white, size = size.small)
if show_tp2_level
tp2_line := line.new(bar_index, tp2_p, bar_index + 1, tp2_p, color = buyColorLight, width = 1, extend = extend.right)
tp2_label := label.new(bar_index, tp2_p, "TP2 " + str.tostring(tp2_p, format.mintick), style = label.style_label_left, color = buyColorLight, textcolor = color.white, size = size.small)
if show_tp3_level
tp3_line := line.new(bar_index, tp3_p, bar_index + 1, tp3_p, color = buyColorLight, width = 1, style = line.style_dotted, extend = extend.right)
tp3_label := label.new(bar_index, tp3_p, "TP3 " + str.tostring(tp3_p, format.mintick), style = label.style_label_left, color = buyColorLight, textcolor = color.white, size = size.small)
if show_sl_level
risk_fill := linefill.new(entry_line, sl_line, sellFill)
float min_tp_for_fill = entry_price
if show_tp1_level
min_tp_for_fill := math.min(min_tp_for_fill, tp1_p)
if show_tp2_level
min_tp_for_fill := math.min(min_tp_for_fill, tp2_p)
if show_tp3_level
min_tp_for_fill := math.min(min_tp_for_fill, tp3_p)
if min_tp_for_fill < entry_price
extreme_line := line.new(bar_index, min_tp_for_fill, bar_index + 1, min_tp_for_fill, color = na, extend = extend.right)
reward_fill := linefill.new(entry_line, extreme_line, buyFill)
// POSITION UPDATE + CLOSING ON SL/TP
if trade_dir != 0
label.set_x(entry_label, bar_index)
if not na(sl_label)
label.set_x(sl_label, bar_index)
if not na(tp1_label)
label.set_x(tp1_label, bar_index)
if not na(tp2_label)
label.set_x(tp2_label, bar_index)
if not na(tp3_label)
label.set_x(tp3_label, bar_index)
bool sl_hit = false
bool tp_hit = false
if trade_dir == 1
sl_hit := low <= sl_level
tp_hit := not na(extreme_level) and high >= extreme_level
else if trade_dir == -1
sl_hit := high >= sl_level
tp_hit := not na(extreme_level) and low <= extreme_level
if bar_index > entry_bar and (sl_hit or tp_hit)
line.set_extend(entry_line, extend.none)
line.set_x2(entry_line, bar_index)
if not na(sl_line)
line.set_extend(sl_line, extend.none)
line.set_x2(sl_line, bar_index)
if not na(tp1_line)
line.set_extend(tp1_line, extend.none)
line.set_x2(tp1_line, bar_index)
if not na(tp2_line)
line.set_extend(tp2_line, extend.none)
line.set_x2(tp2_line, bar_index)
if not na(tp3_line)
line.set_extend(tp3_line, extend.none)
line.set_x2(tp3_line, bar_index)
if not na(extreme_line)
line.set_extend(extreme_line, extend.none)
line.set_x2(extreme_line, bar_index)
trade_dir := 0
// VISUAL SIGNALS
plotshape(breakUp and show_triangles, style = shape.triangleup, location = location.belowbar, color = buyLabelColor, size = size.tiny, textcolor = color.white)
plotshape(breakDown and show_triangles, style = shape.triangledown, location = location.abovebar, color = sellLabelColor, size = size.tiny, textcolor = color.white)
// ALERTS
alertcondition(breakUp, title = "Buy Breakout Signal", message = "Pivot Trendlines BUY Breakout")
alertcondition(breakDown, title = "Sell Breakout Signal", message = "Pivot Trendlines SELL Breakout")