Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor · · Updated 2026-08-21

Value at Risk کا حساب: 3 طریقے اور VaR فارمولہ

Historical، parametric اور Monte Carlo methods سے ایک ہی SPY return series پر VaR کا حساب، اور expected shortfall جو VaR سے رہ جانے والے tail losses دکھاتا ہے۔

Value at risk، یا VaR، کا حساب ایک مخصوص مدت اور confidence level طے کر کے return series سے متعلقہ percentile اخذ کرنے سے کیا جاتا ہے۔ 1-day 99% VaR اگر 2% ہو تو اس کا مطلب ہے کہ ہر 100 trading sessions میں 99 سیشنز کے دوران loss، 2% سے کم رہے گا، جبکہ سویں سیشن میں یہ حد عبور کر جائے گا۔ ایک ہی inputs سے اس سوال کا جواب دینے کے لیے تین standard methods استعمال کیے جاتے ہیں، اور ان کے نتائج میں اختلاف اکثر لوگوں کی توقع سے کہیں زیادہ ہوتا ہے۔

VaR دراصل کیا پیمائش کرتا ہے

VaR، losses کی distribution کا ایک quantile ہے۔ کسی sample میں ہر daily return کو بدترین سے بہترین ترتیب دیں، پھر منفی سرے سے ایک فیصد فاصلہ طے کریں۔ جس return پر پہنچیں، اسے positive loss کے طور پر لکھنے سے one-day 99% historical VaR حاصل ہوتا ہے۔ اس طریقۂ کار میں worst case کی کوئی ضمانت نہیں ہوتی۔ یہ صرف اس حصے کی حد متعین کرتا ہے جسے estimate مزید بیان نہیں کرتا۔

یہی خصوصیت readers سب سے زیادہ غلط جگہ استعمال کرتے ہیں۔ 99% VaR کا مطلب ہے کہ بدترین ایک فیصد دن اس threshold سے آگے واقع ہوتے ہیں، لیکن یہ نہیں بتایا جاتا کہ وہ کتنے آگے ہیں۔ Maximum drawdown ایک مختلف سوال کا جواب دیتا ہے: کسی book کو peak سے trough تک حقیقت میں کتنا loss برداشت کرنا پڑا۔ اسی لیے یہ دونوں measures ایک ہی دو portfolios کی ranking بالکل الٹ ترتیب میں کر سکتے ہیں۔

ذیل میں ہر figure ایک ہی series پر مبنی ہے: 2010 کے آغاز سے 2025 کے اختتام تک SPY کے daily closes، جنہیں close-to-close percent changes میں تبدیل کیا گیا ہے۔ یہ window rolling نہیں بلکہ fixed ہے۔ ہر panel انہی dates سے series دوبارہ بناتا ہے، اس لیے runs کے درمیان اعداد تبدیل نہیں ہوتے۔

استفسار کریںسال کے لحاظ سے pinned return series: SPY کے calendar year کے حساب سے روزانہ returns، 2010 تا 2025
ہر عدد کے پیچھے موجود درست SQL
WITH
px AS
(
    SELECT date, max(toFloat64(close)) AS close_px
    FROM global_markets.stocks_daily_aggs
    WHERE ticker = 'SPY'
      AND date >= '2009-12-01'
      AND date <  '2026-01-01'
    GROUP BY date
),
rets AS
(
    SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
    FROM
    (
        SELECT date, close_px,
               lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
        FROM px
    )
    WHERE date >= '2010-01-01' AND prev_close > 0
)
SELECT
    toString(toYear(date))        AS year,
    count()                       AS sessions,
    round(avg(ret_pct), 3)        AS mean_return_pct,
    round(stddevSamp(ret_pct), 2) AS daily_sigma_pct
FROM rets
GROUP BY year
ORDER BY year
Run this yourself

یہ series 16 calendar years پر محیط ہے، جبکہ صرف 2010 میں 252 sessions شامل ہیں۔ اس کے دو پہلو آگے کی تمام بحث کے لیے اہم ہیں۔ اس horizon پر mean session تقریباً غیر اہم ہے: 2010 میں 0.054%، جبکہ daily standard deviation، sigma، 1.13% ہے۔ اور sigma مستقل نہیں رہتا۔ 2020 میں یہ روزانہ 2.11% تھا، جبکہ 2017 میں 0.43%۔ ایک sigma دونوں ادوار کی وضاحت نہیں کر سکتا۔

Value at risk کا حساب تین طریقوں سے

Historical VaR: جو کچھ ہوا، اس کے percentile سے نتیجہ اخذ کریں

حقیقی returns کو ترتیب دیں اور متعلقہ percentile حاصل کریں۔ اس میں کسی distribution کو فرض نہیں کیا جاتا، اور یہی اس طریقے کی کشش ہے۔ تاہم یہ طریقہ فرض کرتا ہے کہ sample میں پہلے ہی اس نوعیت کا دن موجود ہے جسے estimate میں شامل کرنا مقصود ہے۔ Confidence level کو بہت دور تک لے جائیں تو پورے window کے صرف چند بدترین sessions ہی نتیجہ متعین کرتے ہیں۔

Parametric VaR: mean منفی z ضرب sigma

Series کو اس کے mean اور sigma سے summarize کریں، پھر فرض کریں کہ returns normal distribution کی پیروی کرتے ہیں۔ VaR، z ضرب sigma منفی mean کے برابر ہوتا ہے۔ یہاں z standard normal quantile ہے: 95% پر 1.645، 99% پر 2.326، اور 99.9% پر 3.090۔ حساب فوری ہو جاتا ہے، مگر یہ مفروضہ ایک مخصوص سمت میں ناکام ہوتا ہے۔ Daily equity returns درمیان میں normal curve کے مقابلے میں زیادہ قریب قریب جمع ہوتے ہیں، جبکہ extremes پر کہیں زیادہ دور تک پھیلتے ہیں۔ یہاں sigma وہی denominator ہے جو Sharpe ratio میں بھی استعمال ہوتا ہے، اور fat-tailed data کے معاملے میں یہی blind spot برقرار رہتا ہے۔

Monte Carlo VaR: seed کو مقرر رکھتے ہوئے simulation کریں

کسی مفروضہ process سے ایک بڑا synthetic sample تیار کریں اور ان draws کا percentile حاصل کریں۔ ذیل کا panel hash-seeded uniform sequence سے Box-Muller transform کے ذریعے تیار کیے گئے 40,000 standard normal draws استعمال کرتا ہے۔ ان draws کو series کے mean اور sigma کے مطابق scale کیا گیا ہے۔ Seed SQL میں موجود ہے، اس لیے ہر rerun پر draws یکساں رہتے ہیں۔ Simulation flexibility، path dependence اور multi-asset correlation فراہم کرتا ہے، مگر realism نہیں۔ اگر اسے normal distribution دی جائے تو sampling noise کے ساتھ parametric جواب ہی واپس ملتا ہے۔ اس کے بجائے observed returns کو resample کرنا، جو bootstrapped confidence intervals کے پیچھے استعمال ہونے والی تکنیک ہے، حقیقی tail کو برقرار رکھتا ہے۔

استفسار کریںایک series، تین methods: چھ confidence levels پر 1-day VaR
ہر عدد کے پیچھے موجود درست SQL
WITH
px AS
(
    SELECT date, max(toFloat64(close)) AS close_px
    FROM global_markets.stocks_daily_aggs
    WHERE ticker = 'SPY'
      AND date >= '2009-12-01'
      AND date <  '2026-01-01'
    GROUP BY date
),
rets AS
(
    SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
    FROM
    (
        SELECT date, close_px,
               lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
        FROM px
    )
    WHERE date >= '2010-01-01' AND prev_close > 0
),
emp AS
(
    SELECT
        avg(ret_pct)                  AS mu,
        stddevSamp(ret_pct)           AS sd,
        quantileExact(0.100)(ret_pct) AS h90,
        quantileExact(0.050)(ret_pct) AS h95,
        quantileExact(0.025)(ret_pct) AS h975,
        quantileExact(0.010)(ret_pct) AS h99,
        quantileExact(0.005)(ret_pct) AS h995,
        quantileExact(0.001)(ret_pct) AS h999
    FROM rets
),
draws AS
(
    SELECT
        quantileExact(0.100)(z) AS z90,
        quantileExact(0.050)(z) AS z95,
        quantileExact(0.025)(z) AS z975,
        quantileExact(0.010)(z) AS z99,
        quantileExact(0.005)(z) AS z995,
        quantileExact(0.001)(z) AS z999
    FROM
    (
        SELECT sqrt(-2 * log(u1)) * cos(2 * pi() * u2) AS z
        FROM
        (
            SELECT
                (cityHash64('var-seed-u1', i) % 999999937 + 1) / 999999938.0 AS u1,
                (cityHash64('var-seed-u2', i) % 999999937 + 1) / 999999938.0 AS u2
            FROM (SELECT arrayJoin(range(40000)) AS i)
        )
    )
)
SELECT
    tupleElement(lvl, 1)                                                  AS confidence,
    round(-1 * tupleElement(lvl, 2), 2)                                   AS historical_var_pct,
    round(tupleElement(lvl, 3) * sd - mu, 2)                              AS parametric_var_pct,
    round(-1 * (mu + sd * tupleElement(lvl, 4)), 2)                       AS monte_carlo_var_pct,
    round(-1 * tupleElement(lvl, 2) - (tupleElement(lvl, 3) * sd - mu), 2) AS method_spread
FROM
(
    SELECT
        mu,
        sd,
        arrayJoin([
            ('90.0%', h90,  1.281552, z90,  1),
            ('95.0%', h95,  1.644854, z95,  2),
            ('97.5%', h975, 1.959964, z975, 3),
            ('99.0%', h99,  2.326348, z99,  4),
            ('99.5%', h995, 2.575829, z995, 5),
            ('99.9%', h999, 3.090232, z999, 6)
        ]) AS lvl
    FROM emp
    CROSS JOIN draws
)
ORDER BY tupleElement(lvl, 5)
Run this yourself

95.0% کی سطح پر تینوں طریقے ایک دوسرے سے ایک percentage point کے اندر رہتے ہیں: 1.66% historical، 1.74% parametric، اور 1.71% simulated۔ 99.9% پر پہنچ کر ان کے نتائج الگ ہو جاتے ہیں: 5.85% historical کے مقابلے میں 3.31% parametric، جبکہ یکساں data پر فرق 2.54 percentage points کا ہے۔ Simulated column ہر level پر parametric column کے ساتھ رہتا ہے۔ یہی اصل سبق ہے، کوئی خامی نہیں۔ Simulation وہی distribution دوبارہ تیار کرتی ہے جو اسے دی گئی ہو۔

Column کو اوپر سے نیچے پڑھیں تو confidence میں ہر اضافہ threshold کو وسیع کرتا ہے۔ Row کو بائیں سے دائیں پڑھیں تو distribution کے درمیانی حصے میں method کا انتخاب بمشکل اثر انداز ہوتا ہے، جبکہ tail میں اس کا اثر غالب آ جاتا ہے۔ VaR limit اگر method اور window کے بغیر دی جائے تو وہ ایسا number نہیں جسے کوئی دوسرا شخص دوبارہ reproduce کر سکے۔

VaR آپ کو کیا نہیں بتاتا: expected shortfall

Expected shortfall، جسے conditional VaR بھی کہا جاتا ہے، ان دنوں کے نقصانات کی اوسط نکالتا ہے جب VaR کی حد ٹوٹ جائے۔ VaR یہ بتاتا ہے کہ tail کہاں سے شروع ہوتی ہے۔ Expected shortfall اس tail کے اندر موجود نقصان کی پیمائش کرتا ہے۔

استفسار کریںVaR بمقابلہ expected shortfall، threshold سے زیادہ اوسط loss
ہر عدد کے پیچھے موجود درست SQL
WITH
px AS
(
    SELECT date, max(toFloat64(close)) AS close_px
    FROM global_markets.stocks_daily_aggs
    WHERE ticker = 'SPY'
      AND date >= '2009-12-01'
      AND date <  '2026-01-01'
    GROUP BY date
),
rets AS
(
    SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
    FROM
    (
        SELECT date, close_px,
               lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
        FROM px
    )
    WHERE date >= '2010-01-01' AND prev_close > 0
),
qs AS
(
    SELECT
        quantileExact(0.100)(ret_pct) AS q90,
        quantileExact(0.050)(ret_pct) AS q95,
        quantileExact(0.025)(ret_pct) AS q975,
        quantileExact(0.010)(ret_pct) AS q99,
        quantileExact(0.005)(ret_pct) AS q995,
        quantileExact(0.001)(ret_pct) AS q999
    FROM rets
),
tails AS
(
    SELECT
        any(q90)                        AS var90,
        any(q95)                        AS var95,
        any(q975)                       AS var975,
        any(q99)                        AS var99,
        any(q995)                       AS var995,
        any(q999)                       AS var999,
        avgIf(ret_pct, ret_pct <= q90)  AS es90,
        avgIf(ret_pct, ret_pct <= q95)  AS es95,
        avgIf(ret_pct, ret_pct <= q975) AS es975,
        avgIf(ret_pct, ret_pct <= q99)  AS es99,
        avgIf(ret_pct, ret_pct <= q995) AS es995,
        avgIf(ret_pct, ret_pct <= q999) AS es999
    FROM rets
    CROSS JOIN qs
    HAVING countIf(ret_pct <= q999) > 0
)
SELECT
    tupleElement(lvl, 1)                                  AS confidence,
    round(-1 * tupleElement(lvl, 2), 2)                   AS historical_var_pct,
    round(-1 * tupleElement(lvl, 3), 2)                   AS expected_shortfall_pct,
    round(tupleElement(lvl, 3) / tupleElement(lvl, 2), 2) AS es_to_var_ratio
FROM
(
    SELECT
        arrayJoin([
            ('90.0%', var90,  es90,  1),
            ('95.0%', var95,  es95,  2),
            ('97.5%', var975, es975, 3),
            ('99.0%', var99,  es99,  4),
            ('99.5%', var995, es995, 5),
            ('99.9%', var999, es999, 6)
        ]) AS lvl
    FROM tails
)
ORDER BY tupleElement(lvl, 4)
Run this yourself

99.0% پر اس series کا VaR 3.09% اور expected shortfall 4.43% ہے، یعنی threshold سے 1.44 گنا۔ اسی level پر normal distribution کے تحت یہ ratio تقریباً 1.15 ہوتا۔ حتیٰ کہ 99.9% پر بھی، جہاں threshold پہلے ہی 5.85% تک پہنچ چکا ہے، breach والے دن کا اوسط نقصان 8.14% رہتا ہے۔ صرف VaR کی بنیاد پر مقرر کی گئی limit ہر breach کو ایک جیسا واقعہ سمجھتی ہے، جبکہ ratio column ظاہر کرتا ہے کہ یہ مفروضہ کس قدر غلط ہے۔

کیا 1-day 99% VaR کسی ادارے اور trader کے لیے ایک ہی معنی رکھتا ہے؟

نہیں، اور یہ فرق زیادہ تر horizon کا ہے۔ جو trader رات بھر position نہیں رکھتا، اس کا risk چند گھنٹوں تک رہتا ہے۔ اس لیے one session threshold اس کے holding period سے مطابقت رکھتا ہے، اگرچہ intraday اتار چڑھاؤ close-to-close اعداد سے کہیں آگے جا سکتا ہے۔ اس کے برعکس، long-dated liabilities کی funding کرنے والا ادارہ کئی سال تک positions رکھتا ہے۔ اس کی exposure کئی quarters پر محیط ہوتی ہے۔ لہٰذا اس کا 1-day 99% figure اس کے حقیقی risk کی عکاسی کرنے کے بجائے capital اور monitoring کے لیے استعمال ہونے والا ایک پیمانہ ہوتا ہے۔ کئی برس تک بینک capital rules کی بنیاد 1-day 99% VaR پر رہی، اور بعد میں Basel market risk framework نے پیمانے کو 97.5% expected shortfall پر منتقل کر دیا۔

مختلف horizons کے درمیان standard bridge وقت کے square root کے مطابق scaling ہے: one session figure کو horizon میں شامل sessions کی تعداد کے square root سے ضرب دی جاتی ہے۔ یہ طریقہ اس مفروضے پر مبنی ہے کہ returns باہم independent ہیں اور sigma مستقل رہتی ہے۔ اوپر year-by-year sigma column پہلے ہی دکھا رہا ہے کہ یہ مفروضہ کس حد تک ناکام ہوتا ہے۔

استفسار کریںمربع جذرِ وقت کی scaling بمقابلہ ناپے گئے multi-session losses، 99% level
ہر عدد کے پیچھے موجود درست SQL
WITH
px AS
(
    SELECT date, max(toFloat64(close)) AS close_px
    FROM global_markets.stocks_daily_aggs
    WHERE ticker = 'SPY'
      AND date >= '2009-11-01'
      AND date <  '2026-01-01'
    GROUP BY date
),
multi AS
(
    SELECT
        date,
        100 * (close_px / p1  - 1) AS r1,
        100 * (close_px / p5  - 1) AS r5,
        100 * (close_px / p10 - 1) AS r10,
        100 * (close_px / p20 - 1) AS r20
    FROM
    (
        SELECT
            date,
            close_px,
            lagInFrame(close_px, 1)  OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p1,
            lagInFrame(close_px, 5)  OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p5,
            lagInFrame(close_px, 10) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p10,
            lagInFrame(close_px, 20) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p20
        FROM px
    )
    WHERE date >= '2010-01-01' AND p20 > 0
),
q AS
(
    SELECT
        quantileExact(0.01)(r1)  AS q1,
        quantileExact(0.01)(r5)  AS q5,
        quantileExact(0.01)(r10) AS q10,
        quantileExact(0.01)(r20) AS q20
    FROM multi
)
SELECT
    tupleElement(h, 1)                                             AS horizon,
    round(-1 * tupleElement(h, 3), 2)                              AS actual_var_pct,
    round(-1 * q1 * sqrt(tupleElement(h, 2)), 2)                   AS sqrt_scaled_var_pct,
    round(tupleElement(h, 3) / (q1 * sqrt(tupleElement(h, 2))), 2) AS actual_to_scaled_ratio
FROM
(
    SELECT
        q1,
        arrayJoin([
            ('1 session',   1.0,  q1,  1),
            ('5 sessions',  5.0,  q5,  2),
            ('10 sessions', 10.0, q10, 3),
            ('20 sessions', 20.0, q20, 4)
        ]) AS h
    FROM q
)
ORDER BY tupleElement(h, 4)
Run this yourself

پہلی row identity check ہے: 1 session پر scaled figure، measured figure کے برابر ہے، اور ratio 1 بنتا ہے۔ 20 sessions پر دونوں الگ ہو جاتے ہیں، اور اس سمت میں نہیں جس کے بارے میں shortcut کے سلسلے میں عموماً خبردار کیا جاتا ہے: one session number کو scale کرنے سے 13.8% حاصل ہوتا ہے، جبکہ اسی horizon پر measured returns 10.7% دکھاتے ہیں، اور ratio 0.78 بنتا ہے۔ اس window میں scaled figure، measured multi-session tail سے زیادہ ہے۔ یہاں دو patterns ایک دوسرے کے خلاف کام کرتے ہیں۔ ایک session کی fat-tailed distribution، returns کو جمع کرنے پر کم موٹی ہو جاتی ہے، اور aggregated 99% quantile پھر horizon کے square root کے مقابلے میں زیادہ سست رفتاری سے پھیلتا ہے۔ Volatility clustering اس کے برعکس اثر ڈالتی ہے اور ایک ہی window میں شدید sessions کو جمع کر دیتی ہے۔ اس series میں پہلا pattern زیادہ طاقتور ہے۔ تاہم کسی دوسری window یا asset میں کسی بھی سمت کی ضمانت نہیں دی جا سکتی۔ یہی اصل نکتہ ہے: multiplier ایک مفروضہ ہے، measurement نہیں۔ یہی clustering وہ خاصیت بھی ہے جس پر volatility targeting positions کا حجم دوبارہ طے کرتے وقت انحصار کرتی ہے۔

ایک مزید حد بھی واضح طور پر سمجھ لیں۔ اوپر کی تمام calculations broad index fund پر single asset VaR سے متعلق ہیں۔ دس باہم correlated names پر مشتمل book میں concentration risk ہوتا ہے، جسے portfolio VaR correlation estimate کے ذریعے شامل کرتا ہے۔ اور correlations عموماً اسی وقت سب سے زیادہ تبدیل ہوتی ہیں جب estimate کی سب سے زیادہ ضرورت ہوتی ہے۔

طریقۂ کار کے نوٹس اور conventions
  • Percentiles sampled estimate کے بجائے exact quantile سے حاصل کیے گئے ہیں، جبکہ Monte Carlo draws SQL میں لکھی گئی hash-seeded uniform sequence سے لیے گئے ہیں۔ اس لیے یہاں موجود ہر figure دوبارہ calculation کرنے پر اسی value تک پہنچتا ہے۔
  • Returns close-to-close price changes پر مبنی ہیں اور ان میں dividend reinvestment شامل نہیں۔ one session VaR کے لیے یہی معمول کی convention ہے۔
  • Horizon panel میں overlapping windows استعمال کی گئی ہیں: مسلسل 20-session returns میں 19 دن مشترک ہوتے ہیں۔ اس لیے اس tail کی بنیاد row count کے ظاہر کردہ عدد سے کہیں کم independent observations پر ہے۔

FAQ

1-day 99% VaR کیا ہے؟

یہ وہ loss level ہے جس سے بدترین 100 میں سے 1 trading day کا نقصان ایک single session کے دوران زیادہ ہوتا ہے۔ اوپر دی گئی series میں historical estimate 3.09% ہے۔ یہ figure صرف ایک threshold بتاتا ہے؛ اس سے آگے ہونے والے losses کے حجم کے بارے میں کچھ نہیں کہا جاتا۔

VaR calculation کا سب سے درست طریقہ کون سا ہے؟

اصولی طور پر تینوں میں سے کوئی بھی مکمل طور پر accurate نہیں، کیونکہ ہر طریقہ مختلف assumptions کے تحت سوال کا جواب دیتا ہے۔ Historical VaR اسے دیے گئے sample کی عکاسی کرتا ہے، لیکن sample سے باہر رہ جانے والی صورتِ حال کے بارے میں خاموش رہتا ہے۔ Parametric VaR کم لاگت والا ہے، مگر equity کے tail losses کو کم ظاہر کرتا ہے۔ Monte Carlo کی accuracy اس distribution تک محدود ہے جو اسے فراہم کی جائے۔

VaR اور expected shortfall میں کیا فرق ہے؟

VaR منتخب confidence level پر loss threshold ہوتا ہے۔ Expected shortfall ان دنوں کے losses کا average لیتا ہے جن میں یہ threshold breach ہو جائے۔ اس series میں 99% level پر expected shortfall، VaR کے مقابلے میں 1.44 گنا ہے، جبکہ normal distribution کے تحت یہ تناسب تقریباً 1.15 گنا ہوتا ہے۔

کیا 1-day VaR کو 10-day VaR میں تبدیل کیا جا سکتا ہے؟

VaR کو 10 کے square root سے multiply کرنا standard shortcut ہے۔ اس میں یہ assumption شامل ہوتی ہے کہ returns باہم independent ہیں اور volatility مستقل رہتی ہے۔ Horizon panel اس فرق کو measure کرتا ہے: 20 sessions کے دوران scaled figure 13.8% رہی، جبکہ measured figure 10.7% تھی۔


اوپر موجود ہر panel میں اسے تیار کرنے والی SQL شامل ہے۔ کسی مختلف ticker یا window پر یہی تین calculations چلانے کے لیے Strasmore terminal میں plain English میں درخواست کریں۔

#risk#value at risk#expected shortfall#quant#position sizing