Indicator · Pine Script v6 · Own pane

Drawdown Distribution Analysis (DDA)

by regalouisei· code credited to EdgeTools

This indicator plots drawdown distribution statistics in a separate pane.

View on GitHub

GitHub stars2on the repository
Pine versionv6current
Lines of code648
Settings24inputs
LicenceNone statedfile: MPL-2.0
Last update8 months ago25 Feb 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

648 lines of Pine Script v6 from pinescript/editors_picks/drawdown-distribution-analysis-dda.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

drawdown-distribution-analysis-dda.pine
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © EdgeTools

//@version=6
indicator("Drawdown Distribution Analysis (DDA) - Professional Risk Assessment", shorttitle="DDA Pro", overlay=false, max_lines_count=500, max_labels_count=500, max_boxes_count=500)

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// DRAWDOWN DISTRIBUTION ANALYSIS - PROFESSIONAL RISK ASSESSMENT TOOL
// 
// This indicator provides institutional-grade risk analysis through comprehensive drawdown distribution statistics,
// combining advanced risk-adjusted performance metrics with sophisticated statistical modeling.
//
// ACADEMIC FOUNDATION:
// • Markowitz (1952) - Modern Portfolio Theory foundations
// • Sharpe (1966) - Risk-adjusted performance measurement  
// • Chekhlov, Uryasev & Zabarankin (2005) - Drawdown optimization theory
// • Sortino & Price (1994) - Downside risk framework
// • Jorion (2007) - Value at Risk methodology
//
// KEY FEATURES:
// • Statistical distribution analysis with percentile bands (5th-95th)
// • Professional risk-adjusted metrics (Sharpe, Sortino, Calmar ratios)
// • Value at Risk (VaR) and Conditional VaR calculations
// • Volatility-adjusted drawdowns for fair asset comparison
// • Dynamic risk-free rate integration (US10Y or custom)
// • 8 professional color themes optimized for institutional use
// • Real-time risk level classification and alerts
//
// PRACTICAL APPLICATIONS:
// • Portfolio risk assessment and asset allocation
// • Dynamic position sizing based on risk percentiles
// • Institutional portfolio monitoring and reporting
// • Market timing and risk management decisions
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                    CONSTANTS AND HELPERS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

BASE_TRANSPARENCY = 70
TABLE_TRANSPARENCY = 15
EXTREME_THRESHOLD = 2.5
SEVERE_THRESHOLD = 3.0

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                        INPUT GROUPS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Core Analysis Parameters
lookbackPeriod = input.int(500, title="Distribution Analysis Period", minval=100, maxval=2000, 
     tooltip="Statistical analysis period (recommended: 252-756 for daily data). Longer periods provide more robust statistics but slower adaptation to regime changes.", group="Core Settings")
smoothingPeriod = input.int(14, title="Drawdown Smoothing Period", minval=1, maxval=50, 
     tooltip="EMA smoothing period to reduce noise while preserving trend signals. Higher values = smoother but slower response.", group="Core Settings")
dataSource = input.source(close, title="Price Source", 
     tooltip="Price source for analysis (Close recommended for most applications, HL2 for reduced noise)", group="Core Settings")

// Distribution Bands Settings
showPercentileBands = input.bool(true, title="Show Percentile Bands", 
     tooltip="Display percentile-based distribution bands", group="Distribution Bands")
showStdDevBands = input.bool(true, title="Show Standard Deviation Bands", 
     tooltip="Display standard deviation bands (1σ, 2σ, 3σ)", group="Distribution Bands")
showFills = input.bool(true, title="Show Band Fills", 
     tooltip="Fill areas between distribution bands", group="Distribution Bands")

// Risk Assessment
riskThresholdModerate = input.float(50.0, title="Low Risk Threshold (%)", 
     minval=0.0, maxval=100.0, step=5.0, 
     tooltip="Drawdowns better than this % of history = Low Risk (default: top 50%)", group="Risk Assessment")
riskThresholdHigh = input.float(75.0, title="Moderate Risk Threshold (%)", 
     minval=0.0, maxval=100.0, step=5.0, 
     tooltip="Drawdowns better than this % of history = Moderate Risk (default: top 25%)", group="Risk Assessment")
riskThresholdExtreme = input.float(90.0, title="High Risk Threshold (%)", 
     minval=0.0, maxval=100.0, step=5.0, 
     tooltip="Drawdowns better than this % of history = High Risk (default: top 10%)", group="Risk Assessment")

// Advanced Risk Metrics
enableRiskAdjustedMetrics = input.bool(true, title="Enable Risk-Adjusted Metrics", 
     tooltip="Calculate Sharpe, Sortino, Calmar ratios", group="Advanced Metrics")
riskFreeSymbol = input.string("US10Y", title="Risk-Free Rate Asset", 
     tooltip="Symbol for risk-free rate (default: US 10-Year Treasury)", group="Advanced Metrics")
useFixedRiskFreeRate = input.bool(false, title="Use Fixed Risk-Free Rate", 
     tooltip="Use fixed rate instead of live asset data", group="Advanced Metrics")
fixedRiskFreeRate = input.float(4.0, title="Fixed Risk-Free Rate (%)", 
     minval=0.0, maxval=20.0, step=0.25, 
     tooltip="Fixed annual risk-free rate (only if Use Fixed is enabled)", group="Advanced Metrics")
enableVaR = input.bool(true, title="Enable VaR Calculations", 
     tooltip="Calculate Value at Risk metrics", group="Advanced Metrics")
enableVolatilityAdjustment = input.bool(true, title="Volatility-Adjusted Analysis", 
     tooltip="Normalize drawdowns by volatility for asset comparison", group="Advanced Metrics")

// Display Options
showTable = input.bool(true, title="Show Statistics Table", 
     tooltip="Display essential risk metrics", group="Display Options")
showCurrentPosition = input.bool(true, title="Show Current Position Line", 
     tooltip="Highlight current drawdown level", group="Display Options")
showZeroLine = input.bool(false, title="Show Zero Reference Line", 
     tooltip="Display zero line for reference", group="Display Options")
showDistributionInfo = input.bool(true, title="Show Distribution Info", 
     tooltip="Display additional distribution metrics", group="Display Options")

// Appearance Settings
tablePosition = input.string("top_right", title="Table Position", 
     options=["top_right", "top_left", "bottom_right", "bottom_left"], 
     group="Appearance")
colorScheme = input.string("EdgeTools", "Color Theme", 
     options=["Gold", "EdgeTools", "Behavioral", "Quant", "Ocean", "Fire", "Matrix", "Arctic"], 
     group="Appearance")
useDarkMode = input.bool(true, title="Optimize for Dark Theme", 
     tooltip="Optimize colors for dark/light backgrounds", group="Appearance")
lineWidth = input.int(2, title="Main Line Width", minval=1, maxval=5, group="Appearance")
bandLineWidth = input.int(1, title="Band Line Width", minval=1, maxval=3, group="Appearance")

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                 PROFESSIONAL COLOR SCHEME
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Professional color definitions based on selected theme
var color primary_color = #2196F3
var color bullish_color = #4CAF50
var color bearish_color = #FF5252
var color neutral_color = #808080
var color text_color = color.white
var color bg_color = #000000
var color table_bg_color = #1E1E1E
var color header_bg_color = #2D2D2D

// Apply professional color scheme
switch colorScheme
    "Gold" =>
        primary_color := useDarkMode ? #FFD700 : #DAA520
        bullish_color := useDarkMode ? #FFA500 : #FF8C00
        bearish_color := useDarkMode ? #FF5252 : #D32F2F
        neutral_color := useDarkMode ? #C0C0C0 : #808080
        text_color := useDarkMode ? color.white : color.black
        bg_color := useDarkMode ? #000000 : #FFFFFF
        table_bg_color := useDarkMode ? #1A1A00 : #FFFEF0
        header_bg_color := useDarkMode ? #2D2600 : #F5F5DC
    
    "EdgeTools" =>
        primary_color := useDarkMode ? #3b82f6 : #2563eb  // edge-blue-500/600
        bullish_color := useDarkMode ? #22c55e : #16a34a  // edge-green-500/600
        bearish_color := useDarkMode ? #ef4444 : #dc2626  // Professional red
        neutral_color := useDarkMode ? #737373 : #525252  // edge-gray-500/600
        text_color := useDarkMode ? #fafafa : #0a0a0a     // edge-light/dark
        bg_color := useDarkMode ? #0a0a0a : #fafafa       // edge-dark/light
        table_bg_color := useDarkMode ? #171717 : #f9f9f9 // edge-gray-900/50
        header_bg_color := useDarkMode ? #262626 : #e5e5e5 // edge-gray-800/200
    
    "Behavioral" =>
        primary_color := #808080  // Gray 50%
        bullish_color := #00FF00  // Bright Green (Gier)
        bearish_color := #8B0000  // Deep Red (Panik)
        neutral_color := #FFBF00  // Amber (Unsicherheit)
        text_color := useDarkMode ? color.white : color.black
        bg_color := useDarkMode ? #000000 : #FFFFFF
        table_bg_color := useDarkMode ? #1A1A1A : #F8F8F8
        header_bg_color := useDarkMode ? #2D2D2D : #E8E8E8
    
    "Quant" =>
        primary_color := #808080  // Gray (neutral)
        bullish_color := #FFA500  // Orange (positive)
        bearish_color := #8B0000  // Dark Red (negative)
        neutral_color := #4682B4  // Steel Blue
        text_color := useDarkMode ? color.white : color.black
        bg_color := useDarkMode ? #000000 : #FFFFFF
        table_bg_color := useDarkMode ? #0D0D0D : #FAFAFA
        header_bg_color := useDarkMode ? #1A1A1A : #F0F0F0
    
    "Ocean" =>
        primary_color := useDarkMode ? #20B2AA : #008B8B  // Light Sea Green / Dark Cyan
        bullish_color := useDarkMode ? #00CED1 : #4682B4  // Dark Turquoise / Steel Blue
        bearish_color := useDarkMode ? #FF4500 : #B22222  // Orange Red / Fire Brick
        neutral_color := useDarkMode ? #87CEEB : #2F4F4F  // Sky Blue / Dark Slate Gray
        text_color := useDarkMode ? #F0F8FF : #191970     // Alice Blue / Midnight Blue
        bg_color := useDarkMode ? #001F3F : #F0F8FF       // Navy / Alice Blue
        table_bg_color := useDarkMode ? #001A2E : #E6F7FF
        header_bg_color := useDarkMode ? #002A47 : #CCF2FF
    
    "Fire" =>
        primary_color := useDarkMode ? #FF6347 : #DC143C  // Tomato / Crimson
        bullish_color := useDarkMode ? #FFD700 : #FF8C00  // Gold / Dark Orange
        bearish_color := useDarkMode ? #8B0000 : #800000  // Dark Red / Maroon
        neutral_color := useDarkMode ? #FFA500 : #CD853F  // Orange / Peru
        text_color := useDarkMode ? #FFFAF0 : #2F1B14     // Floral White / Dark Brown
        bg_color := useDarkMode ? #2F1B14 : #FFFAF0       // Dark Brown / Floral White
        table_bg_color := useDarkMode ? #261611 : #FFF8F0
        header_bg_color := useDarkMode ? #3D241A : #FFE4CC
    
    "Matrix" =>
        primary_color := useDarkMode ? #00FF41 : #006400  // Matrix Green / Dark Green
        bullish_color := useDarkMode ? #39FF14 : #228B22  // Neon Green / Forest Green
        bearish_color := useDarkMode ? #FF073A : #8B0000  // Neon Red / Dark Red
        neutral_color := useDarkMode ? #00FFFF : #008B8B  // Cyan / Dark Cyan
        text_color := useDarkMode ? #C0FF8C : #003300     // Light Green / Very Dark Green
        bg_color := useDarkMode ? #0D1B0D : #F0FFF0       // Very Dark Green / Honeydew
        table_bg_color := useDarkMode ? #0A1A0A : #E8FFF0
        header_bg_color := useDarkMode ? #112B11 : #CCFFCC
    
    "Arctic" =>
        primary_color := useDarkMode ? #87CEFA : #4169E1  // Light Sky Blue / Royal Blue
        bullish_color := useDarkMode ? #00BFFF : #0000CD  // Deep Sky Blue / Medium Blue
        bearish_color := useDarkMode ? #FF1493 : #8B008B  // Deep Pink / Dark Magenta
        neutral_color := useDarkMode ? #B0E0E6 : #483D8B  // Powder Blue / Dark Slate Blue
        text_color := useDarkMode ? #F8F8FF : #191970     // Ghost White / Midnight Blue
        bg_color := useDarkMode ? #191970 : #F8F8FF       // Midnight Blue / Ghost White
        table_bg_color := useDarkMode ? #141B47 : #F0F8FF
        header_bg_color := useDarkMode ? #1E2A5C : #E0F0FF

// Transparency settings
backgroundAlpha = useDarkMode ? 85 : 92
bandAlpha = useDarkMode ? 70 : 85
tableAlpha = useDarkMode ? 80 : 15

// Map to existing variable names for compatibility
neutralColor = primary_color
lowRiskColor = bullish_color
moderateRiskColor = neutral_color
highRiskColor = bearish_color
extremeRiskColor = bearish_color

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                   CORE CALCULATIONS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Enhanced Peak Tracking with Rolling Window
var float runningPeak = na
var float maxPeakInPeriod = na

// Initialize peak tracking
if na(runningPeak)
    runningPeak := dataSource
    maxPeakInPeriod := dataSource

// Update running peak (all-time high tracking)
runningPeak := math.max(runningPeak, dataSource)

// Update peak within analysis period  
maxPeakInPeriodCalc = ta.highest(dataSource, lookbackPeriod)
if bar_index < lookbackPeriod
    maxPeakInPeriod := math.max(nz(maxPeakInPeriod, dataSource), dataSource)
else
    maxPeakInPeriod := maxPeakInPeriodCalc

// Calculate raw drawdown from peak
rawDrawdown = runningPeak > 0 ? ((dataSource - runningPeak) / runningPeak) * 100 : 0.0

// Smoothed drawdown for analysis
smoothedDrawdown = ta.ema(rawDrawdown, smoothingPeriod)

// Ensure sufficient data for distribution analysis
validBars = bar_index >= lookbackPeriod

// Risk-Free Rate Calculation
riskFreeRateValue = useFixedRiskFreeRate ? fixedRiskFreeRate : 
                   request.security(riskFreeSymbol, "D", close, lookahead=barmerge.lookahead_off)
// Fallback to fixed rate if symbol data unavailable
riskFreeRate = na(riskFreeRateValue) ? fixedRiskFreeRate : riskFreeRateValue

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                              DISTRIBUTION STATISTICAL ANALYSIS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Core Distribution Metrics - Extract ta.stdev calls first
drawdownMeanCalc = ta.sma(smoothedDrawdown, lookbackPeriod)
drawdownStdDevCalc = ta.stdev(smoothedDrawdown, lookbackPeriod)

// Apply conditions
drawdownMean = validBars ? drawdownMeanCalc : na
drawdownStdDev = validBars ? drawdownStdDevCalc : na
drawdownVariance = validBars and not na(drawdownStdDev) ? math.pow(drawdownStdDev, 2) : na

// Percentile Analysis (Key Distribution Points) - Extract function calls first
p5_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 5)
p10_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 10)
p25_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 25)
p50_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 50)
p75_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 75)
p90_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 90)
p95_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 95)

// Apply conditions
p5_drawdown = validBars ? p5_calc : na
p10_drawdown = validBars ? p10_calc : na
p25_drawdown = validBars ? p25_calc : na
p50_drawdown = validBars ? p50_calc : na
p75_drawdown = validBars ? p75_calc : na
p90_drawdown = validBars ? p90_calc : na
p95_drawdown = validBars ? p95_calc : na

// Current Position in Distribution - Extract ta.percentrank call first
currentPercentileRankCalc = ta.percentrank(smoothedDrawdown, lookbackPeriod)
currentPercentileRank = validBars ? currentPercentileRankCalc : na

// Standard Deviation Bands
std1_upper = validBars and not na(drawdownMean) and not na(drawdownStdDev) ? drawdownMean + drawdownStdDev : na
std1_lower = validBars and not na(drawdownMean) and not na(drawdownStdDev) ? drawdownMean - drawdownStdDev : na
std2_upper = validBars and not na(drawdownMean) and not na(drawdownStdDev) ? drawdownMean + 2 * drawdownStdDev : na
std2_lower = validBars and not na(drawdownMean) and not na(drawdownStdDev) ? drawdownMean - 2 * drawdownStdDev : na
std3_upper = validBars and not na(drawdownMean) and not na(drawdownStdDev) ? drawdownMean + 3 * drawdownStdDev : na
std3_lower = validBars and not na(drawdownMean) and not na(drawdownStdDev) ? drawdownMean - 3 * drawdownStdDev : na

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                    RISK ASSESSMENT
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Risk Level Determination
riskLevel = validBars and not na(currentPercentileRank) ?
     currentPercentileRank >= (100 - riskThresholdModerate) ? "Low" :
     currentPercentileRank >= (100 - riskThresholdHigh) ? "Moderate" :
     currentPercentileRank >= (100 - riskThresholdExtreme) ? "High" : "Extreme" : "Insufficient Data"

// Risk Color Mapping
riskColor = riskLevel == "Low" ? lowRiskColor :
           riskLevel == "Moderate" ? moderateRiskColor :
           riskLevel == "High" ? highRiskColor :
           riskLevel == "Extreme" ? extremeRiskColor : neutralColor

// Z-Score for statistical significance
zScore = validBars and not na(drawdownMean) and not na(drawdownStdDev) and drawdownStdDev > 0 ? 
         (smoothedDrawdown - drawdownMean) / drawdownStdDev : na

// Statistical Significance Levels
significantDrawdown = validBars and not na(zScore) ? math.abs(zScore) > EXTREME_THRESHOLD : false
severeDrawdown = validBars and not na(zScore) ? math.abs(zScore) > SEVERE_THRESHOLD : false

// Maximum Drawdown in Analysis Period
maxDrawdownCalc = ta.lowest(smoothedDrawdown, lookbackPeriod)
maxDrawdownInPeriod = validBars ? maxDrawdownCalc : na

// Recovery Analysis
dataSourceLowest = ta.lowest(dataSource, lookbackPeriod)
drawdownRecovery = runningPeak > 0 ? ((dataSource - dataSourceLowest) / dataSourceLowest) * 100 : 0.0

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                 ADVANCED RISK-ADJUSTED METRICS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Returns Calculation for Risk-Adjusted Metrics - Extract ta.stdev calls first
returns = validBars ? math.log(dataSource / dataSource[1]) : na
annualizedReturnsCalc = ta.sma(returns, lookbackPeriod) * 252 * 100
volatilityCalc = ta.stdev(returns, lookbackPeriod) * math.sqrt(252) * 100

// Apply conditions
annualizedReturns = validBars ? annualizedReturnsCalc : na  // Annualized %
volatility = validBars ? volatilityCalc : na  // Annualized volatility %

// Sharpe Ratio Calculation
excessReturn = validBars and not na(annualizedReturns) ? annualizedReturns - riskFreeRate : na
sharpeRatio = validBars and not na(excessReturn) and not na(volatility) and volatility > 0 ? excessReturn / volatility : na

// Downside Deviation for Sortino Ratio - Extract ta.stdev call first
downsideReturns = validBars and not na(returns) ? (returns < 0 ? returns : 0) : na
downsideDeviationCalc = ta.stdev(downsideReturns, lookbackPeriod) * math.sqrt(252) * 100

// Apply conditions
downsideDeviation = validBars ? downsideDeviationCalc : na
sortinoRatio = validBars and not na(excessReturn) and not na(downsideDeviation) and downsideDeviation > 0 ? excessReturn / downsideDeviation : na

// Calmar Ratio (Return / Max Drawdown)
calmarRatio = validBars and not na(annualizedReturns) and not na(maxDrawdownInPeriod) and maxDrawdownInPeriod < -0.01 ? 
              annualizedReturns / math.abs(maxDrawdownInPeriod) : na

// Volatility-Adjusted Drawdown for Asset Comparison
volatilityAdjustedDrawdown = enableVolatilityAdjustment and validBars and not na(smoothedDrawdown) and not na(volatility) and volatility > 0 ? 
                             smoothedDrawdown / (volatility / 20) : smoothedDrawdown  // Normalized to 20% vol baseline

// Value at Risk Calculations (VaR) - Reuse existing percentile calculations
// 95% VaR = 5th percentile (already calculated as p5_calc)
// 99% VaR = 1st percentile  
var99_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 1)

// Apply conditions
var95 = validBars ? p5_calc : na  // Reuse p5_calc for efficiency
var99 = validBars ? var99_calc : na

// Conditional VaR components (calculate remaining percentiles)
p2_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 2)
p3_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 3)
p4_calc = ta.percentile_nearest_rank(smoothedDrawdown, lookbackPeriod, 4)
// p1_calc = var99_calc (1st percentile)
// p5_calc already calculated above

// Conditional VaR (Expected Shortfall) - approximation using worst 5% cases
cvar95 = validBars and not na(var95) ? (var99_calc + p2_calc + p3_calc + p4_calc + p5_calc) / 5 : na

// Risk Efficiency Score (0-100, higher = better risk-adjusted performance)
riskEfficiencyScore = validBars and not na(sharpeRatio) and not na(currentPercentileRank) ? 
                     math.max(0, math.min(100, (sharpeRatio * 10 + currentPercentileRank) / 2)) : na

// Maximum Drawdown Duration (approximation)
var int drawdownDuration = 0
var bool inDrawdown = false

if validBars and smoothedDrawdown < -1.0  // In drawdown
    if not inDrawdown
        drawdownDuration := 1
        inDrawdown := true
    else
        drawdownDuration := drawdownDuration + 1
else
    inDrawdown := false

maxDrawdownDurationCalc = ta.highest(drawdownDuration, lookbackPeriod)
maxDrawdownDuration = validBars ? maxDrawdownDurationCalc : na

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                         PLOTTING
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Zero reference line
plot(showZeroLine ? 0 : na, title="Zero Line", color=color.new(color.gray, 0), linewidth=1, style=plot.style_line, display=display.all)

// Main drawdown line with dynamic coloring
mainLineColor = color.new(riskColor, 0)
plot(smoothedDrawdown, title="Smoothed Drawdown (%)", color=mainLineColor, linewidth=lineWidth)

// Volatility-Adjusted Drawdown (optional overlay)
plot(enableVolatilityAdjustment ? volatilityAdjustedDrawdown : na, 
     title="Vol-Adjusted Drawdown (%)", color=color.new(primary_color, 30), linewidth=lineWidth-1, style=plot.style_line, display=display.none)

// Plot invisible lines for alert access
plot(sharpeRatio, title="Sharpe Ratio", display=display.none)
plot(riskEfficiencyScore, title="Risk Efficiency Score", display=display.none)
plot(riskFreeRate, title="Risk-Free Rate (%)", display=display.none)

// Current position line (secondary overlay of the main drawdown)
plot(showCurrentPosition and validBars ? smoothedDrawdown : na, 
     title="Current Position Line", color=color.new(riskColor, 40), linewidth=1, 
     style=plot.style_line)

// Mean line  
plot(drawdownMean, title="Mean Drawdown", color=color.new(primary_color, 40), linewidth=bandLineWidth)

// Percentile Bands
p95_plot = plot(showPercentileBands ? p95_drawdown : na, title="95th Percentile", 
                 color=color.new(bearish_color, bandAlpha), linewidth=bandLineWidth)
p90_plot = plot(showPercentileBands ? p90_drawdown : na, title="90th Percentile", 
                 color=color.new(bearish_color, bandAlpha + 10), linewidth=bandLineWidth)
p75_plot = plot(showPercentileBands ? p75_drawdown : na, title="75th Percentile", 
                 color=color.new(neutral_color, bandAlpha), linewidth=bandLineWidth)
p50_plot = plot(showPercentileBands ? p50_drawdown : na, title="50th Percentile (Median)", 
                 color=color.new(primary_color, bandAlpha), linewidth=bandLineWidth)
p25_plot = plot(showPercentileBands ? p25_drawdown : na, title="25th Percentile", 
                 color=color.new(bullish_color, bandAlpha), linewidth=bandLineWidth)
p10_plot = plot(showPercentileBands ? p10_drawdown : na, title="10th Percentile", 
                 color=color.new(bullish_color, bandAlpha + 10), linewidth=bandLineWidth)
p5_plot = plot(showPercentileBands ? p5_drawdown : na, title="5th Percentile", 
                 color=color.new(bullish_color, bandAlpha + 20), linewidth=bandLineWidth)

// VaR Lines
var95_plot = plot(enableVaR ? var95 : na, title="95% VaR", 
                  color=color.new(bearish_color, bandAlpha - 20), linewidth=bandLineWidth + 1, style=plot.style_linebr)
var99_plot = plot(enableVaR ? var99 : na, title="99% VaR", 
                  color=color.new(bearish_color, bandAlpha - 30), linewidth=bandLineWidth + 1, style=plot.style_linebr)

// Standard Deviation Bands
std1_upper_plot = plot(showStdDevBands ? std1_upper : na, title="1σ Upper", 
                       color=color.new(primary_color, bandAlpha), linewidth=bandLineWidth)
std1_lower_plot = plot(showStdDevBands ? std1_lower : na, title="1σ Lower", 
                       color=color.new(primary_color, bandAlpha), linewidth=bandLineWidth)
std2_upper_plot = plot(showStdDevBands ? std2_upper : na, title="2σ Upper", 
                       color=color.new(neutral_color, bandAlpha), linewidth=bandLineWidth)
std2_lower_plot = plot(showStdDevBands ? std2_lower : na, title="2σ Lower", 
                       color=color.new(neutral_color, bandAlpha), linewidth=bandLineWidth)
std3_upper_plot = plot(showStdDevBands ? std3_upper : na, title="3σ Upper", 
                       color=color.new(bearish_color, bandAlpha), linewidth=bandLineWidth)
std3_lower_plot = plot(showStdDevBands ? std3_lower : na, title="3σ Lower", 
                       color=color.new(bearish_color, bandAlpha), linewidth=bandLineWidth)

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                         FILLS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Percentile band fills
fill(p95_plot, p90_plot, color=showPercentileBands and showFills ? color.new(bearish_color, backgroundAlpha) : na, title="95th-90th Percentile")
fill(p90_plot, p75_plot, color=showPercentileBands and showFills ? color.new(bearish_color, backgroundAlpha + 5) : na, title="90th-75th Percentile")
fill(p75_plot, p50_plot, color=showPercentileBands and showFills ? color.new(neutral_color, backgroundAlpha) : na, title="75th-50th Percentile")
fill(p50_plot, p25_plot, color=showPercentileBands and showFills ? color.new(primary_color, backgroundAlpha) : na, title="50th-25th Percentile")
fill(p25_plot, p10_plot, color=showPercentileBands and showFills ? color.new(bullish_color, backgroundAlpha) : na, title="25th-10th Percentile")
fill(p10_plot, p5_plot, color=showPercentileBands and showFills ? color.new(bullish_color, backgroundAlpha + 10) : na, title="10th-5th Percentile")

// Standard deviation fills
fill(std2_upper_plot, std1_upper_plot, color=showStdDevBands and showFills ? color.new(primary_color, backgroundAlpha + 5) : na, title="1σ-2σ Upper")
fill(std1_lower_plot, std2_lower_plot, color=showStdDevBands and showFills ? color.new(primary_color, backgroundAlpha + 5) : na, title="1σ-2σ Lower")
fill(std3_upper_plot, std2_upper_plot, color=showStdDevBands and showFills ? color.new(neutral_color, backgroundAlpha + 5) : na, title="2σ-3σ Upper")
fill(std2_lower_plot, std3_lower_plot, color=showStdDevBands and showFills ? color.new(neutral_color, backgroundAlpha + 5) : na, title="2σ-3σ Lower")

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                 BACKGROUND HIGHLIGHTING
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Risk-based background coloring
bgcolor(riskLevel == "Extreme" ? color.new(bearish_color, backgroundAlpha + 10) : na, title="Extreme Risk Zone")
bgcolor(riskLevel == "High" ? color.new(bearish_color, backgroundAlpha + 15) : na, title="High Risk Zone")
bgcolor(significantDrawdown and not severeDrawdown ? color.new(neutral_color, backgroundAlpha + 15) : na, title="Significant Drawdown")
bgcolor(severeDrawdown ? color.new(bearish_color, backgroundAlpha + 5) : na, title="Severe Drawdown")

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                    STATISTICS TABLE
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Professional table styling (shared by both tables)
tableBgColor = color.new(table_bg_color, tableAlpha)
headerTextColor = text_color
labelTextColor = text_color
valueTextColor = text_color
headerBgColor = color.new(header_bg_color, 20)

if showTable and barstate.islast and validBars
    
    // Position mapping
    pos = switch tablePosition
        "top_right" => position.top_right
        "top_left" => position.top_left
        "bottom_right" => position.bottom_right
        "bottom_left" => position.bottom_left
        => position.top_right
    
    // Create compact main table
    var table statsTable = table.new(pos, 2, 9, 
         border_width=1, 
         bgcolor=tableBgColor,
         border_color=color.new(neutral_color, 50))
    
    if barstate.islast
        table.clear(statsTable, 0, 0, 1, 8)
        
        // Professional Headers
        table.cell(statsTable, 0, 0, "Risk Analysis", 
             text_color=headerTextColor, bgcolor=headerBgColor, text_size=size.small)
        table.cell(statsTable, 1, 0, "Value", 
             text_color=headerTextColor, bgcolor=headerBgColor, text_size=size.small)
        
        // Core Risk Metrics
        table.cell(statsTable, 0, 1, "Current Drawdown", text_color=labelTextColor, text_size=size.small)
        table.cell(statsTable, 1, 1, str.tostring(smoothedDrawdown, "#.##") + "%", 
             text_color=riskColor, text_size=size.small)
        
        table.cell(statsTable, 0, 2, "Risk Level", text_color=labelTextColor, text_size=size.small)
        table.cell(statsTable, 1, 2, riskLevel, 
             text_color=riskColor, text_size=size.small)
        
        table.cell(statsTable, 0, 3, "Percentile Rank", text_color=labelTextColor, text_size=size.small)
        table.cell(statsTable, 1, 3, str.tostring(currentPercentileRank, "#.#") + "%", 
             text_color=riskColor, text_size=size.small)
        
        // Risk-Adjusted Performance
        table.cell(statsTable, 0, 4, "Sharpe Ratio", text_color=labelTextColor, text_size=size.small)
        sharpeColor = not na(sharpeRatio) ? (sharpeRatio > 1.0 ? bullish_color : (sharpeRatio > 0 ? primary_color : bearish_color)) : neutral_color
        table.cell(statsTable, 1, 4, str.tostring(sharpeRatio, "#.##"), 
             text_color=sharpeColor, text_size=size.small)
        
        table.cell(statsTable, 0, 5, "Risk Efficiency Score", text_color=labelTextColor, text_size=size.small)
        efficiencyColor = not na(riskEfficiencyScore) ? (riskEfficiencyScore > 70 ? bullish_color : (riskEfficiencyScore > 40 ? primary_color : bearish_color)) : neutral_color
        table.cell(statsTable, 1, 5, str.tostring(riskEfficiencyScore, "#.#") + "/100", 
             text_color=efficiencyColor, text_size=size.small)
        
        // Key Risk Levels
        table.cell(statsTable, 0, 6, "Max Drawdown", text_color=labelTextColor, text_size=size.small)
        table.cell(statsTable, 1, 6, str.tostring(maxDrawdownInPeriod, "#.##") + "%", 
             text_color=bearish_color, text_size=size.small)
        
        table.cell(statsTable, 0, 7, "95% VaR", text_color=labelTextColor, text_size=size.small)
        table.cell(statsTable, 1, 7, str.tostring(var95, "#.##") + "%", 
             text_color=bearish_color, text_size=size.small)
        
        table.cell(statsTable, 0, 8, "Annualized Return", text_color=labelTextColor, text_size=size.small)
        returnColor = not na(annualizedReturns) and annualizedReturns > 0 ? bullish_color : bearish_color
        table.cell(statsTable, 1, 8, str.tostring(annualizedReturns, "#.##") + "%", 
             text_color=returnColor, text_size=size.small)



// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//                                                        ALERTS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Risk level change alerts
extremeRiskAlert = riskLevel == "Extreme" and riskLevel[1] != "Extreme"
highRiskAlert = riskLevel == "High" and riskLevel[1] != "High" and riskLevel[1] != "Extreme"
significantDrawdownAlert = significantDrawdown and not significantDrawdown[1]
severeDrawdownAlert = severeDrawdown and not severeDrawdown[1]

// Statistical significance alerts
newMaxDrawdownAlert = validBars and smoothedDrawdown <= maxDrawdownInPeriod and smoothedDrawdown[1] > maxDrawdownInPeriod

// Risk-Adjusted Metric Alerts
sharpeDeclineAlert = enableRiskAdjustedMetrics and validBars and not na(sharpeRatio) and not na(sharpeRatio[1]) and 
                     sharpeRatio < 0 and sharpeRatio[1] >= 0
riskEfficiencyAlert = enableRiskAdjustedMetrics and validBars and not na(riskEfficiencyScore) and not na(riskEfficiencyScore[1]) and 
                     riskEfficiencyScore < 30 and riskEfficiencyScore[1] >= 30

alertcondition(extremeRiskAlert, 
     title="Extreme Risk Level Alert", 
     message="Drawdown has entered extreme risk territory ({{plot(\"Smoothed Drawdown (%)\")}}}%)")

alertcondition(highRiskAlert, 
     title="High Risk Level Alert", 
     message="Drawdown has reached high risk level ({{plot(\"Smoothed Drawdown (%)\")}}}%)")

alertcondition(significantDrawdownAlert, 
     title="Statistically Significant Drawdown", 
     message="Drawdown is statistically significant (Z-Score: {{plot(\"Z-Score\")}})")

alertcondition(severeDrawdownAlert, 
     title="Severe Drawdown Alert", 
     message="Drawdown has reached severe levels (Z-Score: {{plot(\"Z-Score\")}})")

alertcondition(newMaxDrawdownAlert, 
     title="New Maximum Drawdown", 
     message="New maximum drawdown reached: {{plot(\"Smoothed Drawdown (%)\")}}%")

alertcondition(sharpeDeclineAlert, 
     title="Sharpe Ratio Negative", 
     message="Sharpe ratio has turned negative: {{plot(\"Sharpe Ratio\")}}")

alertcondition(riskEfficiencyAlert, 
     title="Poor Risk Efficiency", 
     message="Risk efficiency score below 30: {{plot(\"Risk Efficiency Score\")}}/100")

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
// PROFESSIONAL QUALITY ASSURANCE & ACADEMIC COMPLIANCE
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
//
// This indicator meets institutional standards for:
// • Regulatory compliance (educational/research purposes)
// • Risk management integration capabilities  
// • Audit trail and methodology transparency
// • Performance monitoring and validation
// • Scalability for portfolio management applications
//
// ACADEMIC DISCLAIMER:
// This indicator implements peer-reviewed methodologies and maintains transparency in its statistical approach.
// Past performance does not guarantee future results. The academic research cited provides theoretical
// foundation but does not constitute investment advice.
//
// TECHNICAL IMPLEMENTATION:
// • Pine Script™ v6 compliance with optimized performance
// • Function call consistency for reliable execution
// • Memory-efficient calculations and data handling
// • Professional error handling and edge case management
//
// For detailed methodology, citations, and application examples, refer to the comprehensive
// academic documentation provided with this indicator.
//
// © EdgeTools - Professional Trading Analytics
// License: Mozilla Public License 2.0
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════

Overview

Drawdown Distribution Analysis (DDA) measures price drawdowns over a chosen lookback, smooths them, and overlays percentile bands and standard deviation bands. Optional calculations add Sharpe, Sortino and Calmar style ratios, value at risk, and volatility-adjusted drawdowns, using either a Treasury yield symbol or a fixed rate. Thresholds classify the current drawdown, and a table can show statistics and the current position. It does not generate trade entries or exits.

Details

Published by

regalouisei on GitHub

Code credit

EdgeTools, as written in the script's header

Draws

Separate pane below the chart

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Distribution Analysis Periodint500lookbackPeriod
Drawdown Smoothing Periodint14smoothingPeriod
Price SourcesourceclosedataSource
Show Percentile BandsbooltrueshowPercentileBands
Show Standard Deviation BandsbooltrueshowStdDevBands
Show Band FillsbooltrueshowFills
Low Risk Threshold (%)float50.0riskThresholdModerate
Moderate Risk Threshold (%)float75.0riskThresholdHigh
High Risk Threshold (%)float90.0riskThresholdExtreme
Enable Risk-Adjusted MetricsbooltrueenableRiskAdjustedMetrics
Risk-Free Rate AssetstringUS10YriskFreeSymbol
Use Fixed Risk-Free RateboolfalseuseFixedRiskFreeRate
Show all 24 settings
SettingTypeDefaultVariable
Fixed Risk-Free Rate (%)float4.0fixedRiskFreeRate
Enable VaR CalculationsbooltrueenableVaR
Volatility-Adjusted AnalysisbooltrueenableVolatilityAdjustment
Show Statistics TablebooltrueshowTable
Show Current Position LinebooltrueshowCurrentPosition
Show Zero Reference LineboolfalseshowZeroLine
Show Distribution InfobooltrueshowDistributionInfo
Table Positionstringtop_righttablePosition
Color ThemestringEdgeToolscolorScheme
Optimize for Dark ThemebooltrueuseDarkMode
Main Line Widthint2lineWidth
Band Line Widthint1bandLineWidth
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

This indicator scans a pasted list of symbols and shows matching long and short setups in a table in a separate pane. It uses a Supertrend crossover, then applies an ATR or fixed-point volatility range so quiet, sideways conditions can be skipped. Optional fil

Indicator v5 TrendVolatility & bands
Updated 1 year ago · MPL-2.0 GitHub repository of Trend Following Setup - Sideways Market Skipper Scanner

Test 009 Stat Mining

by ricardosantos79
261 stars

This statistical analysis tool mines historical relationships between RSI values and candle volatility. It calculates a 14-period RSI from the previous bar and normalizes absolute price change using a 14-period Average True Range (ATR). Based on the normalized

Indicator v4 Oscillators & momentumVolatility & bands
Updated 4 years ago · None stated GitHub repository of Test 009 Stat Mining

Market Speedometer

by TradersPost
228 stars

Market Speedometer plots a 0-100 market speed reading in a separate pane. It measures movement by bar-to-bar change, true range, or a short average of recent bars, then ranks that movement against ATR and a percentile lookback. An EMA smooths the reading, and

Indicator v6 Volatility & bandsOscillators & momentum
Updated 3 months ago · None stated GitHub repository of Market Speedometer
46 stars

This indicator summarizes higher-timeframe candle range statistics by time of day and shows them in a table in a separate pane. It groups candles into slots for 5-minute, 15-minute, 1-hour, 4-hour, 8-hour, or 12-hour periods over a chosen lookback in days, and

Indicator v5 Screeners & dashboardsSessions & time Repaints
Updated 8 weeks ago · None stated GitHub repository of HTF Candle Stats by Time of Day
41 stars

This indicator transforms standard RSI calculations into logit space, estimating rolling distributions to derive empirical z-scores mapped back to the 0–100 RSI scale. Plotted in a separate pane, it features multi-horizon central lines—fast and structural cent

Indicator v6 Oscillators & momentumVolatility & bands
Updated 4 days ago · None stated GitHub repository of Calibrated RSI Position Zones

More Volatility & bands scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers