Rust میں QuantLib: libitofin اور اس کے استعمال کا طریقہ
libitofin دراصل QuantLib کا Rust میں پورٹ ہے جسے Python کے ذریعے استعمال کیا جا سکتا ہے۔ یہ لائبریری اسپریڈشیٹ کے مقابلے میں پیچیدہ مالیاتی ماڈلنگ اور درستگی فراہم کرتی ہے۔
QuantLib in Rust، libitofin کی ایک سطری تعریف ہے: یہ C++ کی لائبریری QuantLib کا Rust میں ایک پورٹ ہے، جو 2000 کی دہائی کے اوائل سے derivatives pricing کے لیے اوپن سورس حوالہ رہی ہے۔ اس کے ساتھ itofin نام کا ایک Python پیکیج بھی موجود ہے۔ اگست 2026 تک، یہ پروجیکٹ خود کو pre-1.0 قرار دیتا ہے، اور یہی لیبل اس کے استعمال کے تمام عملی پہلوؤں کا تعین کرتا ہے۔ ایک pricing لائبریری اپنی اہمیت فارمولے کے گرد موجود مشینری سے حاصل کرتی ہے، اور یہ مشینری کسی بھی زبان میں ایک جیسا کام کرتی ہے۔
ایک pricing لائبریری آپ کو کیا دیتی ہے جو اسپریڈشیٹ کا فارمولا نہیں دیتا
اسپریڈشیٹ میں Black-Scholes کا ایک سیل پانچ ان پٹس لیتا ہے اور ایک قیمت واپس کرتا ہے۔ فارمولا تو آسان حصہ ہے۔ اس کے گرد چار تہیں (layers) ہوتی ہیں، اور وہی تہیں دراصل لائبریری ہیں۔
Term structures۔ ڈسکاؤنٹ ریٹ دراصل maturities پر پھیلی ہوئی ایک curve ہوتی ہے، جس میں ان پوائنٹس کے درمیان وقفوں کے لیے interpolation کا اصول ہوتا ہے جن کے ریٹس مارکیٹ میں کوٹ کیے جاتے ہیں۔ نیچے دیا گیا پینل خام مواد ہے: ایک مخصوص تاریخ پر کوٹ کیے گئے Treasury tenors۔
ہر عدد کے پیچھے موجود درست SQL
SELECT
arrayElement(tenors, i) AS tenor,
round(arrayElement(rates, i), 2) AS yield_pct,
formatDateTime(curve_date, '%b %e, %Y') AS as_of
FROM
(
SELECT
date AS curve_date,
['1 month', '3 months', '6 months', '1 year', '2 years', '3 years',
'5 years', '7 years', '10 years', '20 years', '30 years'] AS tenors,
[toFloat64(yield_1_month), toFloat64(yield_3_month), toFloat64(yield_6_month),
toFloat64(yield_1_year), toFloat64(yield_2_year), toFloat64(yield_3_year),
toFloat64(yield_5_year), toFloat64(yield_7_year), toFloat64(yield_10_year),
toFloat64(yield_20_year), toFloat64(yield_30_year)] AS rates,
arrayJoin(range(1, 12)) AS i
FROM global_markets.treasury_yields
WHERE date = (SELECT max(date) FROM global_markets.treasury_yields)
)
WHERE yield_pct > 0
ORDER BY iAug 10, 2026 تک، کوٹ کی گئی curve میں 7 tenors شامل تھے، جو 3.79% کے 1 month سے لے کر 5.25% کے 30 years تک پھیلے ہوئے تھے۔ اسپریڈشیٹ اسے ایک lookup اور ہارڈ کوڈڈ 4 فیصد کے ساتھ حل کرتی ہے۔ ایک لائبریری اسے ایک curve آبجیکٹ کے ساتھ حل کرتی ہے جس سے ہر انسٹرومنٹ پرائسنگ کرتا ہے، جس میں ایک متعین interpolation (zero rates پر لکیری، discount factors پر log-linear، monotone splines) اور آخری پوائنٹ کے بعد ایک متعین extrapolation پالیسی ہوتی ہے۔ اس ایک آبجیکٹ کو ایک basis point سے تبدیل کریں تو کتاب میں موجود ہر sensitivity اس کے ساتھ مستقل مزاجی سے تبدیل ہو جاتی ہے۔
Day-count conventions۔ سود سال کے ایک حصے پر جمع ہوتا ہے، اور اس حصے کی تعریف وہ کنونشن ہے جو انسٹرومنٹ کے ساتھ منسلک ہوتا ہے۔ Actual/360 گزرے ہوئے دنوں کو 360 پر تقسیم کرتا ہے۔ Actual/365 اسے 365 پر تقسیم کرتا ہے۔ 30/360 فیملی یہ فرض کرتی ہے کہ ہر مہینے میں 30 دن ہوتے ہیں۔ Business/252 ٹریڈنگ سیشنز کو 252 دن کے سال کے حساب سے گنتا ہے، جس کے لیے ایک حقیقی ایکسچینج کیلنڈر درکار ہوتا ہے جس میں چھٹیاں پہلے سے شامل ہوں۔ فرض کریں کہ 5 فیصد پر 90 دنوں کے لیے دس لاکھ ڈالر ادھار لیے گئے: actual/360 پر 12,500 ڈالر اور actual/365 پر 12,329 ڈالر کا سود بنتا ہے۔ نیچے دیا گیا پینل دکھاتا ہے کہ business-day basis کو تقسیم کار (divisor) کے بجائے کیلنڈر کی ضرورت کیوں ہوتی ہے۔
ہر عدد کے پیچھے موجود درست SQL
SELECT
formatDateTime(toStartOfMonth(date), '%Y-%m') AS month,
countDistinct(date) AS trading_days,
toUInt8(toDayOfMonth(toLastDayOfMonth(max(date)))) AS calendar_days
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= toStartOfMonth(today() - 365)
AND date < toStartOfMonth(today())
GROUP BY month
ORDER BY monthدیکھے گئے 12 مہینوں کے دوران، 2026-07 میں 22 سیشنز تھے جبکہ کیلنڈر کے دن 31 تھے۔ کوئی حسابی اصول یہ پہلا نمبر پیدا نہیں کرتا۔ یہ ایک چھٹیوں کے کیلنڈر سے آتا ہے، اور ہر مہینے کا اپنا جواب ہوتا ہے۔ ایک لائبریری ہر مقام اور ہر ملک کے لیے وہ کیلنڈرز فراہم کرتی ہے؛ اسپریڈشیٹ آپ سے انہیں خود برقرار رکھنے کا تقاضا کرتی ہے۔
Calibration machinery۔ ماڈل کے پیرامیٹرز کہیں بھی کوٹ نہیں کیے جاتے۔ آپ انہیں مارکیٹ کی کوٹس کی پوری سطح پر ماڈل کی قیمتوں کو فٹ کر کے منتخب کرتے ہیں، پھر جیسے جیسے سطح تبدیل ہوتی ہے، دوبارہ فٹ کرتے ہیں۔ یہ ایک bounded least-squares مسئلہ ہے، اور لائبریری اس کے گرد لوپ فراہم کرتی ہے: ایک Levenberg-Marquardt آپٹیمائزر، پیرامیٹر ٹرانسفارمز جو سخت رکاوٹوں کے بغیر variance کو مثبت رکھتے ہیں، کوٹ سیٹ پر ایک cost function، اور convergence کے معیارات جو خاموشی سے غلط جواب دینے کے بجائے واضح طور پر ناکام ہو جاتے ہیں۔
ایک numerics تہہ۔ ہر چیز کے نیچے لکیری الجبرا اور انٹیگریشن موجود ہے۔ QR اور SVD decompositions ان سسٹمز کو حل کرتی ہیں جو فٹنگ سے پیدا ہوتے ہیں، quadrature اور Fourier انٹیگریشن ان ماڈلز کی پرائسنگ کرتی ہیں جن کے فارمولے انٹیگرلز ہوتے ہیں، اور root finders implied volatility کو نکالتے ہیں۔ یہ تہہ بورنگ ہے، اور یہی وہ تہہ ہے جسے اکثر غلط طریقے سے دوبارہ بنایا جاتا ہے۔ کلاسک ورژن ایک ہاتھ سے تیار کردہ Newton solver ہے جو liquid at-the-money کوٹس پر تو کام کرتا ہے لیکن deep out-of-the-money پر بھٹک جاتا ہے۔ اس کے بعد دوسرا نمبر ایک matrix inverse کا ہے جو near-singular فٹ پر درستگی کھو دیتا ہے اور ایسے پیرامیٹرز دیتا ہے جو بظاہر بالکل ٹھیک لگتے ہیں۔ اگر آپ شروع سے ذہنی ماڈل بنا رہے ہیں، تو ایک اوپن سورس کوانٹ ٹریڈنگ کتاب کسی بھی لائبریری کے API ریفرنس سے بہتر نقطہ آغاز ہے۔
libitofin کیا ہے، اور کیا یہ Rust میں QuantLib ہے؟
جی ہاں، اس لحاظ سے جو اہم ہے۔ یہ QuantLib کے ڈیزائن کا Rust میں پورٹ ہے، اور پروجیکٹ کا کہنا ہے کہ اسے QuantLib کے اپنے ٹیسٹ سوٹ کے خلاف ٹیسٹ کیا گیا ہے۔ ایک numerics لائبریری کو پورٹ کرنے کا یہی ایماندارانہ طریقہ ہے: نتائج کا موازنہ حوالہ جاتی نفاذ (reference implementation) سے کیا جاتا ہے، نہ کہ اس سے کہ جواب کیا ہونا چاہیے۔ Python کا راستہ itofin نامی پیکیج ہے، لہذا ایک Python پروسیس C++ ٹول چین کے بغیر Rust انجن تک رسائی حاصل کر سکتا ہے۔
جو لیبل زیادہ اہم ہے وہ pre-1.0 ہے۔ Rust کے ورژننگ کنونشن کے تحت، 0.x ریلیز مائنر ورژنز کے درمیان مطابقت (compatibility) کا کوئی وعدہ نہیں کرتی: 0.4 سے 0.5 میں کسی بھی چیز کا نام تبدیل، منتقل یا حذف کیا جا سکتا ہے۔ API کو ایک متحرک ہدف سمجھیں، اور اس کے ساتھ چند عادات اپنائیں:
- اپنی lockfile میں ایک درست tagged ریلیز کو پن (pin) کریں اور جان بوجھ کر اپ گریڈ کریں، جس میں آپ کا اپنا ٹیسٹ سوٹ گیٹ کے طور پر کام کرے۔
- لائبریری کی اقسام کے گرد اپنا ایک پتلا wrapper رکھیں، تاکہ نام کی تبدیلی چالیس فائلوں کے بجائے صرف ایک میں کرنی پڑے۔
- لائبریری ورژن کو ان نمبروں کے ساتھ ریکارڈ کریں جو اس نے پیدا کیے ہیں، تاکہ اگر دوبارہ چلانے پر نتائج مختلف آئیں تو آپ اپ گریڈ کی طرف دیکھ سکیں نہ کہ مارکیٹ کی طرف۔
- پروڈکشن مارجن، کولیٹرل، اور ریگولیٹری رسک نمبرز کو ایسی چیز پر رکھیں جو 1.0 آنے تک مطابقت کا وعدہ رکھتی ہو۔
اس میں سے کچھ بھی پروجیکٹ پر تنقید نہیں ہے۔ Pre-1.0 ایک درست خود تشریح ہے اور ایک بہت بڑی لائبریری کے نوجوان پورٹ کے لیے صحیح جگہ ہے۔ ناکامی کا طریقہ یہ ہے کہ کوئی قاری اسے QuantLib کا متبادل سمجھے اور ایک مائنر ریلیز میں تبدیل شدہ سگنیچر کا سامنا کرے۔ انسٹالیشن کی ہدایات بھی ورژن کے ساتھ بدلتی ہیں، اور cargo اور pip دونوں کو کچھ بھی حل کرنے کے لیے نیٹ ورک تک رسائی درکار ہوتی ہے، لہذا پروجیکٹ کی اپنی README کو اس ٹیگ پر پڑھیں جسے آپ پن کرنا چاہتے ہیں، نہ کہ کسی بلاگ پوسٹ سے کاپی کیے گئے ٹکڑے کو۔
Python، ایک کمپائلڈ انجن، یا Rust؟
دو سوالات اس کا فیصلہ کرتے ہیں، اور ان کا تعلق ذوق سے نہیں ہے۔ آپ ایک سیکنڈ میں کتنی بار ری پرائسنگ کرتے ہیں، اور کیا آپ کے نمبرز الگ الگ پروسیسز میں ایک جیسے ہونے چاہئیں؟ چین کا سائز پہلے سوال کا پیمانہ طے کرتا ہے۔
ہر عدد کے پیچھے موجود درست SQL
WITH (SELECT max(date) FROM global_markets.options_greeks) AS last_session
SELECT
underlying_symbol AS symbol,
countDistinct(ticker) AS contracts_priced,
formatDateTime(max(date), '%b %e, %Y') AS as_of
FROM global_markets.options_greeks
WHERE date = last_session
AND underlying_symbol IN ('SPY', 'AAPL', 'NVDA', 'MSFT', 'KO')
AND volume > 0
GROUP BY symbol
ORDER BY contracts_priced DESCAug 11, 2026 کو، SPY میں ایک ہی سیشن میں 5336 الگ الگ کانٹریکٹس ٹریڈ ہوئے، جبکہ KO کے لیے یہ تعداد 360 تھی۔ ایک وسیع چین کی پرائسنگ کرنا کوئی بڑی بات نہیں ہے۔ ہر کوٹ اپ ڈیٹ پر، ہر کانٹریکٹ کے لیے پانچ sensitivities کے ساتھ، انڈرلائنگز کی ایک کتاب پر اس کی پرائسنگ کرنا، مختلف رکاوٹوں کے ساتھ ایک مختلف پروگرام ہے۔
جب لوپ کی پیمائش ہزاروں ویلیوایشنز فی منٹ میں ہو اور ارد گرد کا کام تحقیق، تجزیہ، یا دن کے اختتام کے مارکس ہوں، تو ایک قائم شدہ لائبریری کے ساتھ Python میں رہیں۔ QuantLib کے اپنے Python بائنڈنگز ہی پختہ انتخاب ہیں: وہی C++ انجن، وسیع ترین انسٹرومنٹ کوریج، اور برسوں کا پروڈکشن تجربہ۔ ریسرچ کوڈ میں رفتار شاذ و نادر ہی رکاوٹ بنتی ہے؛ کوریج اور درستگی زیادہ اہم ہیں۔
جب لوپ تیز ہو اور اس کے گرد کوڈ نہ ہو تو Python سے ایک کمپائلڈ انجن کو کال کریں۔ جس لاگت پر نظر رکھنی ہے وہ خود باؤنڈری ہے۔ Python سے فی کانٹریکٹ کال ہر کراسنگ پر اوور ہیڈ ادا کرتی ہے، اور اس کا حل یہ ہے کہ انجن کو ایک array دیں اور ایک array واپس لیں۔ یہ وہی جگہ ہے جہاں itofin، QuantLib-Python کے ساتھ، اپنی جگہ بنانے کی کوشش کر رہا ہے۔
Rust تب لکھیں جب پرائسنگ لوپ ہی پروڈکٹ ہو: ایک کوٹنگ سروس کے اندر پرائسر، ایک رسک رن جو آپ مس نہیں کر سکتے، یا کوئی بائنری جو ایسی مشین پر بھیجی جائے جس میں Python نہ ہو۔ دوسرا سوال بھی یہیں آتا ہے۔ فلوٹنگ پوائنٹ کے نتائج آپریشنز کی ترتیب پر منحصر ہوتے ہیں، لہذا ایک ہی ماڈل کے دو نفاذ آخری ہندسوں میں اختلاف کر سکتے ہیں، اور ایک ریسرچ نوٹ بک جو پروڈکشن سروس سے اختلاف کرے، وہ ایک ہفتے کی فرانزک کا باعث بنتی ہے۔ دونوں طرف سے استعمال ہونے والا ایک ہی انجن اس قسم کے تضاد کو ختم کر دیتا ہے، جو کسی بھی زبان میں لکھی گئی بائنڈنگز کے ساتھ ایک کمپائلڈ کور کے لیے پائیدار دلیل ہے۔ یہی جبلت حکمت عملی کے کام پر بھی لاگو ہوتی ہے، جیسا کہ ایک قابلِ اعادہ بیک ٹیسٹ دکھاتا ہے۔
کیلیبریشن کا ہدف اصل میں کہاں رہتا ہے
کیلیبریشن کو فٹ کرنے کے لیے کسی چیز کی ضرورت ہوتی ہے، اور وہ چیز مارکیٹ کی implied volatilities کی سطح ہے۔ اس کا root-finding پہلو implied volatility کا حساب کیسے لگایا جاتا ہے میں کور کیا گیا ہے۔ نیچے دی گئی شکل وہ ہے جس سے ماڈل کو میچ کرنا ہوتا ہے۔
ہر عدد کے پیچھے موجود درست SQL
SELECT
multiIf(days_to_expiry <= 7, '0 to 7 days',
days_to_expiry <= 30, '8 to 30 days',
days_to_expiry <= 60, '31 to 60 days',
days_to_expiry <= 120, '61 to 120 days',
days_to_expiry <= 240, '121 to 240 days',
'241 days or more') AS dte_bucket,
round(avg(implied_volatility) * 100, 1) AS iv_pct,
countDistinct(ticker) AS contracts
FROM global_markets.options_greeks
WHERE underlying_symbol = 'AAPL'
AND date >= today() - 10
AND days_to_expiry >= 0
AND iv_converged = 1
AND volume > 0
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.05
GROUP BY dte_bucket
ORDER BY min(days_to_expiry)منی کے قریب، 0 to 7 days بکٹ میں AAPL کانٹریکٹس نے دیکھے گئے سیشنز میں اوسطاً 29.6% implied volatility ظاہر کی، جبکہ 241 days or more پر یہ 29.3% تھی۔ ایک volatility پیرامیٹر والا ماڈل ایک ہی وقت میں دونوں پوائنٹس پر نہیں بیٹھ سکتا، یہی وجہ ہے کہ volatility term structure والے ماڈلز موجود ہیں۔ اس جیسی سطح پر کسی کو فٹ کرنا کیلیبریشن کا مرحلہ ہے، اور فٹ شدہ ماڈل سے نکلنے والی sensitivities کو Greeks کہتے ہیں، جو آپشن Greeks کی وضاحت میں کور کیے گئے ہیں۔
یہ پینلز کیسے بنائے گئے
curve پینل Treasury سیریز میں سب سے حالیہ کوٹ کی گئی تاریخ کو پڑھتا ہے اور اس کے گیارہ tenor کالمز کو قطاروں میں کھولتا ہے، اس دن کسی بھی ایسے tenor کو چھوڑ دیتا ہے جس کی کوئی کوٹ نہ ہو۔ سیشن پینل ہر مہینے SPY ٹیپ پر الگ الگ تاریخوں کو گنتا ہے، جو مکمل ایکسچینج سیشن کی گنتی کے لیے ایک صاف ستھرا پراکسی ہے۔ چین پینل تازہ ترین دستیاب سیشن پر غیر صفر والیوم کے ساتھ الگ الگ کانٹریکٹ کوڈز کو گنتا ہے، جو انڈرلائنگ کے لحاظ سے گروپ کیے گئے ہیں۔ volatility پینل صرف ان converged solves کو رکھتا ہے جن کا والیوم غیر صفر ہو اور اسٹرائیکس انڈرلائنگ کلوز کے 5 فیصد کے اندر ہوں، جو کہ معیاری near-the-money بینڈ ہے؛ فرنٹ بکٹ میں اسی دن کی expiries شامل ہیں۔
اکثر پوچھے گئے سوالات
کیا libitofin، QuantLib کا متبادل ہے؟
نہیں۔ اگست 2026 تک یہ ایک pre-1.0 پورٹ ہے جو QuantLib کی سطح کا کچھ حصہ کور کرتا ہے اور اس کے نتائج کو QuantLib کے اپنے ٹیسٹ سوٹ کے خلاف ویلیڈیٹ کرتا ہے۔ QuantLib خود، جو اپنی Python بائنڈنگز کے ذریعے حاصل کیا جاتا ہے، پروڈکشن کے کام کے لیے زیادہ وسیع اور مستحکم آپشن ہے۔
ایک پرائسنگ لائبریری کے لیے pre-1.0 کا کیا مطلب ہے؟
Rust کے ورژننگ کنونشن کے تحت، 0.x ریلیز مطابقت کا کوئی وعدہ نہیں کرتی: اگلا مائنر ورژن کسی بھی چیز کا نام تبدیل کرنے یا حذف کرنے کے لیے آزاد ہے۔ عملی طور پر اس کا مطلب ایک درست ٹیگ شدہ ریلیز کو پن کرنا اور ہر اپ گریڈ پر اپنے ٹیسٹ سوٹ کو دوبارہ چلانا ہے۔
کیا libitofin استعمال کرنے کے لیے مجھے Rust لکھنے کی ضرورت ہے؟
نہیں۔ پروجیکٹ itofin نامی ایک Python پیکیج شائع کرتا ہے، لہذا انجن کو ایک عام Python پروسیس سے کال کیا جا سکتا ہے۔ Rust لکھنا تب متعلقہ ہو جاتا ہے جب پرائسنگ لوپ خود وہ چیز ہو جسے آپ شپ کر رہے ہیں۔
ایک پرائسنگ لائبریری مجھے کیا دیتی ہے جو اسپریڈشیٹ کا فارمولا نہیں دیتا؟
سنگل ریٹس کے بجائے کروز، حقیقی ایکسچینج کیلنڈرز کے ساتھ ڈے-کاؤنٹ کنونشنز، ایک کیلیبریشن لوپ جو ماڈل پیرامیٹرز کو کوٹ کی گئی قیمتوں پر فٹ کرتا ہے، اور ان تینوں کے نیچے ایک ٹیسٹ شدہ numerics تہہ۔ کلوزڈ فارم فارمولا کام کا چھوٹا حصہ ہے۔
کیا پروگرامنگ زبان آپشن کی قیمت کو تبدیل کرتی ہے؟
ریاضیاتی طور پر نہیں۔ یہ اعادہ پذیری (reproducibility) کو تبدیل کرتی ہے: فلوٹنگ پوائنٹ کے نتائج آپریشنز کی ترتیب پر منحصر ہوتے ہیں، لہذا ایک ماڈل کے دو نفاذ آخری ہندسوں میں اختلاف کر سکتے ہیں۔ ریسرچ اور پروڈکشن کو ایک ہی انجن سے چلانا اس فرق کو ختم کر دیتا ہے۔
یہاں ہر پینل کے نیچے اس کا درست SQL موجود ہے، لہذا یہ دیکھنے کے لیے کہ گنتی کیسے کی گئی، کسی ایک کو پھیلائیں۔ وہی curve، کیلنڈر، اور چین کے سوالات Strasmore ٹرمینل پر سادہ انگریزی میں پوچھے جا سکتے ہیں۔