حين تتحرك التقلبات أيضًا
يفترض بلاك-شولز تقلبًا ثابتًا لكن التقلب الحقيقي يرتفع في الانهيارات ويخبو في الهدوء، وسوق الخيارات يُظهر ذلك: يختلف التقلب الضمني باختلاف سعر التنفيذ (الابتسامة أو الانحياز). ويُبقي نموذج هستون على عملية السعر الهندسية لكنه يجعل *التباين* v عشوائيًا أيضًا: يُسحب نحو مستوى طويل الأمد theta بسرعة kappa ويُهز بضجيج بحجم xi يتناسب مع sqrt(v)، ولصدمات السعر والتباين ارتباط rho. وارتباط سالب (ينخفض السعر حين يرتفع التقلب، أثر الرافعة) ينتج الانحياز الهابط الملاحَظ في خيارات الأسهم.
# The Heston equations, in words: dS = mu S dt + sqrt(v) S dW dv = kappa (theta - v) dt + xi sqrt(v) dZ corr(dW, dZ) = rho
kappa, theta, xi = 2.0, 0.04, 0.3 # reversion speed, long-run variance (a 20% volatility), volatility of variance
print(round(theta ** 0.5, 2)) # 0.2 the long-run volatility
print(2 * kappa * theta, xi ** 2) # 0.16 0.09 the Feller condition 2 kappa theta >= xi^2 holds: the variance stays positiveمحاكاته: القطع والارتباط
للمحاكاة نتقدم بفترات صغيرة dt. تحديث التباين هو v + kappa * (theta - v) * dt + xi * sqrt(v * dt) * dz لكن خطوة أويلر البسيطة قد تدفع v تحت الصفر حيث يفشل الجذر التربيعي. ويستعمل مخطط القطع الكامل القيمة max(v, 0) حيثما ظهر v في الطرف الأيمن (فالقيمة السالبة تعمل كصفر) ويحتفظ بالناتج الخام للخطوة التالية. وشرط فيلر 2 * kappa * theta >= xi^2 هو نظام المعاملات الذي لا تلمس فيه العملية الحقيقية الصفر؛ وإن لم يتحقق ازدادت أهمية القطع. ويجب أن تكون الصدمتان مرتبطتين: اسحب طبيعيَّين مستقلين z1 وz2 وضع dz = z1 وdw = rho * z1 + sqrt(1 - rho^2) * z2.
# One variance step with full truncation, and the correlated shocks for the price
import math
def variance_step(v, kappa, theta, xi, dz, dt):
vp = max(v, 0.0)
return v + kappa * (theta - vp) * dt + xi * math.sqrt(vp * dt) * dz
def correlated_normals(z1, z2, rho):
return z1, rho * z1 + math.sqrt(1 - rho ** 2) * z2
print(round(variance_step(0.04, 2.0, 0.04, 0.3, 0.5, 1 / 252), 6)) # 0.04189 at the long-run level only the noise moves it
dz, dw = correlated_normals(1.0, 1.0, -0.7)
print(round(dz, 4), round(dw, 4)) # 1.0 0.0141 a negative rho: the price shock pulls against the variance shock
print(variance_step(-0.01, 2.0, 0.04, 0.3, 1.0, 1 / 252)) # -0.00968... still negative, but it moved up by kappa * theta * dt: the negative value acted as 0مسار كامل وفحص للصحة
تحدّث الخطوة الواحدة متغيّري الحالة معًا: يستعمل السعر التباين عند *بداية* الخطوة S * exp((mu - v/2) * dt + sqrt(v * dt) * dw) ثم يتحرك التباين. كرّر لعدد الخطوات في الأفق فيصير لديك مسار؛ وتعطي مسارات كثيرة توزيعًا لأسعار النهاية، ومتوسط عائد مخصوم عليها يسعّر خيارًا. وفحص صحة جيد: مع الانجراف mu ينبغي أن يقترب متوسط سعر النهاية من S0 * exp(mu * T) أيًّا كانت معاملات التقلب. وإلا ففي خطوة السعر خطأ. أما معايرة kappa, theta, xi, rho على أسعار الخيارات فتأتي في الموضوعات القادمة.
# A short Monte Carlo: simulate many paths, and check the average terminal price against S0 * exp(mu * T)
import math
import random
def simulate(s0, v0, mu, kappa, theta, xi, rho, steps, years, rng):
dt = years / steps
s, v = s0, v0
for _ in range(steps):
z1, z2 = rng.gauss(0, 1), rng.gauss(0, 1)
dz, dw = z1, rho * z1 + math.sqrt(1 - rho ** 2) * z2
vp = max(v, 0.0)
s *= math.exp((mu - vp / 2) * dt + math.sqrt(vp * dt) * dw)
v = v + kappa * (theta - vp) * dt + xi * math.sqrt(vp * dt) * dz
return s
rng = random.Random(11)
finals = [simulate(100.0, 0.04, 0.05, 2.0, 0.04, 0.3, -0.7, 50, 1.0, rng) for _ in range(4000)]
mean = sum(finals) / len(finals)
print(abs(mean / (100.0 * math.exp(0.05)) - 1) < 0.02) # True the average terminal price follows S0 * exp(mu * T)
print(min(finals) > 0) # True prices stay positive# A check that costs nothing: with xi = 0 and v0 = theta the variance never moves (Black-Scholes with volatility sqrt(theta))
import math
kappa, theta, xi = 2.0, 0.04, 0.0
v = theta
for z in (1.5, -2.0, 0.3, 0.9):
vp = max(v, 0.0)
v = v + kappa * (theta - vp) * (1 / 252) + xi * math.sqrt(vp / 252) * z
print(v == theta) # True no noise and already at the long-run level
print(round(math.sqrt(v), 2)) # 0.2 a constant 20% volatilitydt، والشبكة الخشنة تُحيز أسعار الخيارات. استعمل خطوات كافية ومسارات كثيرة (يتناقص الخطأ المعياري كمقلوب جذر عدد المسارات). وتحقق من المحاكاة بجواب معروف: ضع xi = 0 فيؤول النموذج إلى بلاك-شولز بتقلب sqrt(theta). وفي الإنتاج يكون تسعير هستون شبه التحليلي عبر الدالة المميزة أسرع وأدق؛ والمحاكاة هي الأداة المرنة حين تعتمد العوائد على المسار.- يجعل هستون التباين عشوائيًا: يعود إلى
thetaبسرعةkappaوله ضجيجxi * sqrt(v)ويرتبط بالسعر بـrho(سالب للأسهم). - حاكِ بالقطع الكامل (
max(v, 0)في الطرف الأيمن) واربط الصدمات بـdw = rho z1 + sqrt(1 - rho^2) z2وافحص شرط فيلر2 kappa theta >= xi^2. - تستعمل خطوة السعر التباين عند بداية الخطوة؛ تحقق من أن متوسط سعر النهاية يتبع
S0 * exp(mu * T)وأنxi = 0يعيد بلاك-شولز.
التالي: التقلب المحلي، سطح تقلب يعتمد على السعر والزمن.
المختبر: ما الذي يُقيَّم
- أبقِ التباين موجبًا باستخدام
feller_condition25 نقطة - حرّك التباين خطوة باستخدام
variance_step25 نقطة - اربط الصدمات باستخدام
correlated_normals25 نقطة - حرّك السعر والتباين باستخدام
heston_step25 نقطة