Useful Pine Script v5 code snippets
Just copy & paste the ones you like and enjoy. Happy Trading!
Cutting-edge code, all day long.
Accurately calculate Peak-to-Trough cycles (Run-up and Drawdown)
Did you know that TradingView strategies calculate the drawdown for each trade but not for multiple trades together? That has a big impact.
TradingView’s strategy metrics might show you a max drawdown of 8.9%, representing the largest loss for any individual trade in the strategy. However, strategy’s drawdown from a relative peak to trough over multiple trades might be much larger. This insight is so critical, yet many traders are unaware that TradingView’s backtest results for drawdown can be misleading (albeit unintentionally). For that reason we are offering this free code to identify the peak-to-trough drawdown in your strategy. You can also use to automatically stop your strategy in case the drawdown exceeds your limit.
- Accurately calculates peaks and troughs / drawdowns.
- Let's you pause your strategy when the drawdown exceeds a level you specify.
- Rows automatically switch color based on the year of when the trough occured.
- Change the minimum trough percentage to see more or fewer cycles.
showTable = input(true, title="Show Peak/Trough Table?")
min_trough = input.float(defval=20.0, title="Minimum Trough Percentage (0.1-100)")
maxdraw = input.float(20.0, title = "Max Loss from Peak Startegy Equity at which Strategy will stop executing trades.")
// Peak-Trough Cycles with Date
// Initialize variables
var float equityPeak = na
var float equityTrough = na
var int cycleCount = 0
var bool inDrawdown = false
var float initialCapital = capital
var float prevTrough = initialCapital
var float prevRunUp = na
var bool useLighterGray = true
var int lastYear = na
var float highestDrawdown = na
var string dateOfHighestDrawdown = na
// Variable to indicate whether the strategy should end
var bool end_strategy = false
// Collect Drawdown(%) values during the cycle tracking
var float[] drawdownValues = array.new_float()
// Table to display data
var table resultTable = table.new(position.top_right, 5, 30, bgcolor=#ffffff00, frame_color=#4f4040, frame_width=1)
// Function to convert float to percentage string
f_to_percent(value) =>
str.tostring(value, "#.##") + "%"
// Function to get month/year string without commas
get_month_year_string() =>
str.tostring(year) + "/" + str.tostring(month)
// Track peaks and troughs in equity based on closed trades
float currentEquity = initialCapital + strategy.netprofit
if (na(equityPeak) or currentEquity > equityPeak)
if (inDrawdown and not na(equityTrough)) // Confirm end of drawdown cycle
float drawdownPercentage = (equityPeak - equityTrough) / equityPeak * 100
if na(highestDrawdown) or drawdownPercentage > highestDrawdown // Check if this is the highest drawdown
highestDrawdown := drawdownPercentage // Update the highest drawdown
dateOfHighestDrawdown = timenow // Record the date of the highest drawdown
if drawdownPercentage > min_trough // Minimum drawdown threshold
cycleCount += 1
prevRunUp := (equityPeak - prevTrough) / prevTrough * 100
if cycleCount <= max_dd_rows and showTable
table.cell(resultTable, 0, 0, "Show MinDraw: " + f_to_percent(min_trough), bgcolor=#a8a8a88f, text_size=size.tiny)
table.cell(resultTable, 1, 0, "Cycle Count", bgcolor=#a8a8a88f, text_size=size.tiny)
if plot_runups
table.cell(resultTable, 2, 0, "Prev.RunUp(%)", bgcolor=#a8a8a88f, text_size=size.tiny)
table.cell(resultTable, 3, 0, "MaxDraw(%)", bgcolor=#a8a8a88f, text_size=size.tiny)
table.cell(resultTable, 4, 0, "Year/Month", bgcolor=#a8a8a88f, text_size=size.tiny)
int currentYear = year(timenow)
if na(lastYear) or currentYear != lastYear
useLighterGray := not useLighterGray
lastYear := currentYear
color rowColor = useLighterGray ? color.new(color.gray, 80) : color.new(color.gray, 50)
table.cell(resultTable, 1, cycleCount, str.tostring(cycleCount), bgcolor=rowColor, text_size=size.tiny)
if plot_runups
table.cell(resultTable, 2, cycleCount, f_to_percent(prevRunUp), bgcolor=rowColor, text_size=size.tiny)
table.cell(resultTable, 3, cycleCount, f_to_percent(highestDrawdown), bgcolor=rowColor, text_size=size.tiny)
table.cell(resultTable, 4, cycleCount, get_month_year_string(), bgcolor=rowColor, text_size=size.tiny)
array.push(drawdownValues, highestDrawdown)
prevTrough := equityTrough
highestDrawdown := na // Reset the highest drawdown after recording
dateOfHighestDrawdown := na // Reset the date of the highest drawdown after recording
equityPeak := currentEquity
equityTrough := na
inDrawdown := false
else if (currentEquity < equityPeak)
equityTrough := na(equityTrough) ? currentEquity : math.min(equityTrough, currentEquity)
inDrawdown := true
// Calculate if the strategy should end
if not na(equityPeak) and not na(equityTrough)
drawdownPercentage = (equityPeak - equityTrough) / equityPeak * 100
if drawdownPercentage >= maxdraw
end_strategy := true