Skip to content

Instantly share code, notes, and snippets.

@yaakov123
Last active April 7, 2025 18:16
Show Gist options
  • Save yaakov123/846215f2072eafa78dd9d9c1f9d7e5fb to your computer and use it in GitHub Desktop.
Save yaakov123/846215f2072eafa78dd9d9c1f9d7e5fb to your computer and use it in GitHub Desktop.
Dynamic TP/SL Levels
//@version=5
indicator(title="Dynamic TP/SL Lines with Risk and ATR", shorttitle="Dyn TP/SL Risk ATR", overlay=true, precision=2, max_lines_count = 52, max_labels_count = 50) // Increased max_lines_count
// === INPUTS ===
group_levels = "Level Configuration"
numLevels = input.int(3, title="Number of Levels (Each Side)", minval=1, maxval=25, group=group_levels, tooltip="How many TP/SL levels to draw above and below the price.") // Max 25 to stay within limits
pointIncrement = input.float(5.0, title="Point Increment Per Level", minval=0.25, step=0.25, group=group_levels, tooltip="The distance in points between consecutive TP/SL levels.")
startingNumber = input.int(0, title = "Starting number", minval=0, group=group_levels, tooltip="What distance should the increments start from")
atrLength = input.int(14, title="ATR Length (1min Chart)", minval=1, group=group_levels, tooltip="Length of the ATR calculation on the 1-minute chart.")
atrMultiplier = input.int(2, title="ATR Multiple", minval=1, group=group_levels, tooltip="What multiple of the ATR value to draw the lines at")
group_risk = "Risk Management"
riskAmount = input.float(300.0, title="Risk Amount ($)", minval=0.0, group=group_risk, tooltip="The total amount you are willing to risk.")
positionType = "Long"
group_style = "Line & Label Style"
tpColor = input.color(color.new(color.green, 0), title="TP Line Color", group=group_style)
slColor = input.color(color.new(color.red, 0), title="SL Line Color", group=group_style)
atrColor = input.color(color.new(color.blue, 50), title="ATR Line Color", group=group_style)
// --- Line Style Input for line.new ---
STYLE_SOLID = "Solid"
STYLE_DASHED = "Dashed"
STYLE_DOTTED = "Dotted"
lineStyleInput = input.string(STYLE_SOLID, title="Line Style", options=[STYLE_SOLID, STYLE_DASHED, STYLE_DOTTED], group=group_style)
// --- End Style Input ---
lineWidth = input.int(1, title="Line Width", minval=1, group=group_style)
lineExtendBars = input.int(25, title="Line Extension (Bars)", minval=0, group=group_style, tooltip="How many bars to the right of the current bar to extend the lines.")
showLabels = input.bool(true, title="Show Point Labels", group=group_style, tooltip="Displays the point distance next to each line.")
labelSize = input.string(size.small, title="Label Size", options=[size.tiny, size.small, size.normal, size.large, size.huge], group=group_style)
labelOffsetBars = lineExtendBars + 1
// === VARIABLES FOR MANAGING DRAWINGS ===
// Persistent arrays to store the IDs of the lines and labels
var line[] tpLineIds = array.new_line()
var line[] slLineIds = array.new_line()
var label[] tpLabelIds = array.new_label()
var label[] slLabelIds = array.new_label()
var line[] atrLineIds = array.new_line()
atrValue = request.security(syminfo.tickerid, "1", ta.atr(atrLength))
atrValue := atrValue * atrMultiplier
// === LOGIC (Executes only on the last bar's updates) ===
if barstate.islast
// --- Get Current State ---
currentPrice = close // Use the close/current price of the last bar
currentBarIndex = bar_index
riskPerPoint = syminfo.pointvalue
// --- Determine Line Style ---
lineStyleActual = switch lineStyleInput
STYLE_DASHED => line.style_dashed
STYLE_DOTTED => line.style_dotted
=> line.style_solid // Default to solid
// --- Delete Excess Drawings (if numLevels decreased) ---
// TP Lines
if array.size(tpLineIds) > numLevels
start_index = array.size(tpLineIds) - 1
end_index = numLevels
if start_index >= end_index
for i = start_index to end_index by -1
line.delete(array.get(tpLineIds, i))
// SL Lines
if array.size(slLineIds) > numLevels
start_index = array.size(slLineIds) - 1
end_index = numLevels
if start_index >= end_index
for i = start_index to end_index by -1
line.delete(array.get(slLineIds, i))
// TP Labels
if showLabels and array.size(tpLabelIds) > numLevels
start_index = array.size(tpLabelIds) - 1
end_index = numLevels
if start_index >= end_index
for i = start_index to end_index by -1
label.delete(array.get(tpLabelIds, i))
// SL Labels
if showLabels and array.size(slLabelIds) > numLevels
start_index = array.size(slLabelIds) - 1
end_index = numLevels
if start_index >= end_index
for i = start_index to end_index by -1
label.delete(array.get(slLabelIds, i))
// ATR Lines
if array.size(atrLineIds) > 2
for i = 0 to array.size(atrLineIds) - 1
line.delete(array.get(atrLineIds, i))
array.clear(atrLineIds)
// Remove the extra IDs from arrays if numLevels decreased
if array.size(tpLineIds) > numLevels
array.slice(tpLineIds, 0, numLevels) // Keep only the first 'numLevels' IDs
if array.size(slLineIds) > numLevels
array.slice(slLineIds, 0, numLevels)
if array.size(tpLabelIds) > numLevels
array.slice(tpLabelIds, 0, numLevels)
if array.size(slLabelIds) > numLevels
array.slice(slLabelIds, 0, numLevels)
// If labels turned off, delete existing ones
if not showLabels and array.size(tpLabelIds) > 0
for id in tpLabelIds
label.delete(id)
array.clear(tpLabelIds)
if not showLabels and array.size(slLabelIds) > 0
for id in slLabelIds
label.delete(id)
array.clear(slLabelIds)
// --- Calculate ATR on 1-minute chart ---
// --- Calculate ATR Levels ---
atrUpperLevel = currentPrice + atrValue
atrLowerLevel = currentPrice - atrValue
// --- Draw ATR Lines ---
if array.size(atrLineIds) < 2
upperAtrLine = line.new(x1=currentBarIndex - 1, y1=atrUpperLevel, x2=currentBarIndex + lineExtendBars, y2=atrUpperLevel, color=atrColor, style=lineStyleActual, width=lineWidth)
lowerAtrLine = line.new(x1=currentBarIndex - 1, y1=atrLowerLevel, x2=currentBarIndex + lineExtendBars, y2=atrLowerLevel, color=atrColor, style=lineStyleActual, width=lineWidth)
array.push(atrLineIds, upperAtrLine)
array.push(atrLineIds, lowerAtrLine)
else
line.set_y1(array.get(atrLineIds, 0), atrUpperLevel)
line.set_y2(array.get(atrLineIds, 0), atrUpperLevel)
line.set_x1(array.get(atrLineIds, 0), currentBarIndex - 1)
line.set_x2(array.get(atrLineIds, 0), currentBarIndex + lineExtendBars)
line.set_y1(array.get(atrLineIds, 1), atrLowerLevel)
line.set_y2(array.get(atrLineIds, 1), atrLowerLevel)
line.set_x1(array.get(atrLineIds, 1), currentBarIndex - 1)
line.set_x2(array.get(atrLineIds, 1), currentBarIndex + lineExtendBars)
// --- Create / Modify TP/SL Drawings ---
// Loop from 0 to numLevels-1 (for array indexing)
for i = 0 to numLevels - 1
// Calculate distance and levels for this iteration (level i+1)
dist = startingNumber + pointIncrement * (i + 1)
tpLevel = currentPrice + dist
slLevel = currentPrice - dist
dist_txt = str.tostring(dist, syminfo.mintick < 0.01 ? "#.#####" : syminfo.mintick < 0.1 ? "#.###" : "#.##") + " Pts"
// --- TP Line ---
if i < array.size(tpLineIds) // Check if line for this level exists
// Modify existing line's Y and X positions
line.set_y1(array.get(tpLineIds, i), tpLevel)
line.set_y2(array.get(tpLineIds, i), tpLevel)
line.set_x1(array.get(tpLineIds, i), currentBarIndex - 1)
line.set_x2(array.get(tpLineIds, i), currentBarIndex + lineExtendBars)
// Optional: Update style/color if inputs change
else
// Create new line if it doesn't exist
newLine = line.new(x1=currentBarIndex - 1, y1=tpLevel, x2=currentBarIndex + lineExtendBars, y2=tpLevel, color=tpColor, style=lineStyleActual, width=lineWidth)
array.push(tpLineIds, newLine) // Store new ID
// --- SL Line ---
if i < array.size(slLineIds) // Check if line exists
// Modify existing line's Y and X positions
line.set_y1(array.get(slLineIds, i), slLevel)
line.set_y2(array.get(slLineIds, i), slLevel)
line.set_x1(array.get(slLineIds, i), currentBarIndex - 1)
line.set_x2(array.get(slLineIds, i), currentBarIndex + lineExtendBars)
else
// Create new line
newLine = line.new(x1=currentBarIndex - 1, y1=slLevel, x2=currentBarIndex + lineExtendBars, y2=slLevel, color=slColor, style=lineStyleActual, width=lineWidth)
array.push(slLineIds, newLine) // Store new ID
// --- Labels (if enabled) ---
if showLabels
// --- SL Label ---
var float contractsNeededSL = na
var float actualRiskSL = na
var float priceDifferenceSL = na // Declare priceDifferenceSL here
if positionType == "Long"
priceDifferenceSL := currentPrice - slLevel
else if positionType == "Short"
priceDifferenceSL := slLevel - currentPrice
riskPerContractSL = math.abs(priceDifferenceSL * riskPerPoint)
if riskPerContractSL > 0
contractsNeededSL := math.round(riskAmount / riskPerContractSL)
actualRiskSL := contractsNeededSL * riskPerContractSL
if (actualRiskSL > riskAmount)
contractsNeededSL -= 1
actualRiskSL := contractsNeededSL * riskPerContractSL
else
contractsNeededSL := 0
actualRiskSL := 0
contractsTextSL = " (" + str.tostring(contractsNeededSL) + " Cnt, $" + str.tostring(actualRiskSL, "#.##") + " Risk)"
// --- TP Label ---
if i < array.size(tpLabelIds) // Check if label exists
// Modify existing label's position and text
label.set_y(array.get(tpLabelIds, i), tpLevel)
label.set_x(array.get(tpLabelIds, i), currentBarIndex + labelOffsetBars)
label.set_text(array.get(tpLabelIds, i), dist_txt + contractsTextSL)
// Optional: Update color/size if inputs change
else
// Create new label
newLabel = label.new(x=currentBarIndex + labelOffsetBars, y=tpLevel, text=dist_txt + contractsTextSL, color=color.new(color.white, 100), textcolor=tpColor, style=label.style_label_left, size=labelSize)
array.push(tpLabelIds, newLabel) // Store new ID
if i < array.size(slLabelIds) // Check if label exists
// Modify existing label's position and text
label.set_y(array.get(slLabelIds, i), slLevel)
label.set_x(array.get(slLabelIds, i), currentBarIndex + labelOffsetBars)
label.set_text(array.get(slLabelIds, i), dist_txt + contractsTextSL)
else
// Create new label
newLabel = label.new(x=currentBarIndex + labelOffsetBars, y=slLevel, text=dist_txt + contractsTextSL, color=color.new(color.white, 100), textcolor=slColor, style=label.style_label_left, size=labelSize)
array.push(slLabelIds, newLabel) // Store new ID
// --- End of barstate.islast block ---
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment