Calculating Drawdown Duration in Pine Script
This lesson demonstrates how to calculate the drawdown duration (in time) for your TradingView strategy scripts.
Check out my other free lessons!Source Code
Note: The code below is slightly different to the code shown in the video as I made some improvements.
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © ZenAndTheArtOfTrading // @version=5 ////////////////////////////////////////////////////////////////////////// // EXAMPLE STRATEGY (REPLACE THIS CODE WITH YOUR OWN) // ////////////////////////////////////////////////////////////////////////// strategy("Drawdown Time", overlay=true, initial_capital=100000, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.cash_per_contract, commission_value=0.005) // Get user input i_ma1 = input.int(title="MA 1 Length", defval=200, step=10, group="Strategy Parameters", tooltip="Long-term MA", display=display.none) i_ma2 = input.int(title="MA 2 Length", defval=10, step=10, group="Strategy Parameters", tooltip="Short-term MA", display=display.none) i_stopPercent = input.float(title="Stop Loss Percent", defval=0.10, step=0.1, group="Strategy Parameters", tooltip="Failsafe Stop Loss Percent Decline", display=display.none) i_lowerClose = input.bool(title="Exit On Lower Close", defval=false, group="Strategy Parameters", tooltip="Wait for a lower-close before exiting above MA2", display=display.none) i_startTime = input.time(title="Start Filter", defval=timestamp("01 Jan 1995 13:30 +0000"), group="Time Filter", tooltip="Start date & time to begin searching for setups", display=display.none) i_endTime = input.time(title="End Filter", defval=timestamp("1 Jan 2099 19:30 +0000"), group="Time Filter", tooltip="End date & time to stop searching for setups", display=display.none) // Get indicator values ma1 = ta.sma(close, i_ma1) ma2 = ta.sma(close, i_ma2) // Check filter(s) f_dateFilter = time >= i_startTime and time <= i_endTime // Check buy/sell conditions var float buyPrice = 0 buyCondition = close > ma1 and close < ma2 and strategy.position_size == 0 and f_dateFilter sellCondition = close > ma2 and strategy.position_size > 0 and (not i_lowerClose or close < low[1]) stopDistance = strategy.position_size > 0 ? ((buyPrice - close) / close) : na stopPrice = strategy.position_size > 0 ? buyPrice - (buyPrice * i_stopPercent) : na stopCondition = strategy.position_size > 0 and stopDistance > i_stopPercent // Enter positions if buyCondition strategy.entry(id="Long", direction=strategy.long, comment="Equity = $" + str.tostring(strategy.equity, "#.##")) if buyCondition[1] buyPrice := strategy.position_avg_price // Exit positions if sellCondition or stopCondition strategy.close(id="Long", comment="Exit" + (stopCondition ? "SL=true" : "")) buyPrice := na // Draw pretty colors plot(buyPrice, color=color.lime, style=plot.style_linebr) plot(stopPrice, color=color.red, style=plot.style_linebr, offset=-1) plot(ma1, color=color.blue) plot(ma2, color=color.orange) //////////////////////////////////////////////////////////// // END EXAMPLE STRATEGY (REPLACE THIS CODE WITH YOUR OWN) // //////////////////////////////////////////////////////////// // Drawdown time code var float equityPeak = strategy.initial_capital var int currentDrawdownBars = 0 var array<int> drawdownBarsArray = array.new<int>(0) if (barstate.isconfirmed) // If bar is closed, check the following: if (strategy.closedtrades != strategy.closedtrades[1]) // Check if a trade just closed if (strategy.equity > equityPeak) // If so, update REALIZED equity peak equityPeak := strategy.equity if (strategy.equity < equityPeak) // If current equity is lower than the peak, we're in drawdown currentDrawdownBars := currentDrawdownBars + 1 else // If current equity is not lower than the peak, we've cleared the drawdown if (currentDrawdownBars > 0) // Save this last drawdown so we can average all DD's later drawdownBarsArray.push(currentDrawdownBars) // Reset counter currentDrawdownBars := 0 // Calculate average drawdown int averageBarsInDD = drawdownBarsArray.avg() // Draw table information var table displayTable = na if (barstate.isconfirmed) displayTable := table.new(position.top_right, columns = 1, rows = 2, bgcolor = color.black, border_width = 1) // Get timeframe period string timeInDrawdown = "Timeframe Unsupported" string avgDrawdown = "Timeframe Unsupported" if (timeframe.isdwm) if (timeframe.isdaily) timeInDrawdown := str.tostring(drawdownBarsArray.max() * timeframe.multiplier) + " days" avgDrawdown := str.tostring(averageBarsInDD * timeframe.multiplier, "#.##") + " days" else displayTable.cell(0, 0, "Timeframe Unsupported") else int minutesInDrawdown = drawdownBarsArray.max() * int(str.tonumber(timeframe.period)) if (minutesInDrawdown <= 60) // Less than 1 hour timeInDrawdown := str.tostring(minutesInDrawdown) + " minutes" avgDrawdown := str.tostring(averageBarsInDD * str.tonumber(timeframe.period), "#.##") + " minutes" else if (minutesInDrawdown <= 1440) // Less than 1 day timeInDrawdown := str.tostring(minutesInDrawdown / 60, "#.##") + " hours" avgDrawdown := str.tostring((averageBarsInDD * str.tonumber(timeframe.period)) / 60, "#.##") + " hours" else // More than 1 day timeInDrawdown := str.tostring(minutesInDrawdown / 1440, "#.##") + " days" avgDrawdown := str.tostring((averageBarsInDD * str.tonumber(timeframe.period)) / 1440, "#.##") + " days" displayTable.cell(0, 0, "Worst Drawdown: " + timeInDrawdown, text_color=color.white) displayTable.cell(0, 1, "Avg Drawdown: " + avgDrawdown, tooltip="Total Drawdown Count: " + str.tostring(drawdownBarsArray.size()), text_color=color.white)