σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyالمسارات
Ctrl K
AO
+1.2k متعلّم
تسجيل الدخولانضم ↗
المسارات
AO
+1.2k متعلّم
تسجيل الدخول
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
مسار Python›الوحدة 6 · الاختبار الرجعي وتكاليف التداول›الموضوع 6.3·~50 دمتقدم

التحيز الاستباقي

الموضع في المسارالوحدة 6 من 11 · الموضوع 3 من 6
6.3 التحيز الاستباقي
—درجة المختبر— / 100إجمالي XP—التتابع—

معرفة أكثر من اللازم

انحياز النظر إلى المستقبل هو أن يستخدم الاختبار الرجعي معلومات لم تكن متاحة وقت القرار. وهو أشيع سبب لأن تبدو استراتيجية رائعة على الورق وتخسر في الواقع. وقلّما يكون سطرًا واضحًا؛ بل يختبئ في المحاذاة (إشارة إغلاق اليوم تُتداول عند هذا الإغلاق)، وفي إحصاءات تُحسب على العينة كلها، وفي بيانات صُححت لاحقًا، وفي مؤشرات اختيرت بعد وقوع الأحداث. والعلاج عادة: لكل رقم يستخدمه قرار اسأل متى أصبح معروفًا.

import numpy as np

rng = np.random.default_rng(5)
returns = rng.normal(0, 0.01, size=250)             # pure noise: no strategy can really make money here

signal = returns.copy()                              # "signal" = the return of the same day
position = np.sign(signal)

biased = np.prod(1 + position * returns) - 1         # trades on the return it is about to earn
honest_position = np.concatenate([[0.0], position[:-1]])
honest = np.prod(1 + honest_position * returns) - 1
print(round(float(biased), 2), round(float(honest), 2))        # 6.0 0.01: a 600% "return" on noise, against 1%

المحاذاة: تأخير يوم

علاج انحياز المحاذاة هو التأخير: قيمة حُسبت في اليوم t لا تُستخدم إلا من اليوم t + 1. وفي المصفوفات هو إزاحة مع أصفار في البداية، out[t] = signal[t - periods]. والاختبار فظ. فسلسلة الضجيج لا ميزة فيها، فأي قاعدة تجني ثروة من الضجيج تغش. قارن النسخة المنحازة بالمتأخرة على البيانات نفسها، والفرق هو حجم الانحياز.

# lag_signal: delay a series, with zeros where there is nothing to look back at
import numpy as np

def lag_signal(signal, periods=1):
    out = np.zeros(len(signal))
    if periods < len(signal):
        out[periods:] = signal[:len(signal) - periods]
    return out

s = np.array([1.0, -1.0, 1.0, 1.0, -1.0])
print(lag_signal(s))             # [ 0.  1. -1.  1.  1.]
print(lag_signal(s, 2))          # [ 0.  0.  1. -1.  1.]
# trailing_mean: the mean of the last `window` values, using only today and the past
import numpy as np

def trailing_mean(values, window):
    total = np.cumsum(values)
    out = np.full(len(values), np.nan)
    out[window - 1:] = (total[window - 1:] - np.concatenate([[0.0], total[:len(values) - window]])) / window
    return out

x = np.array([1.0, 2.0, 6.0, 7.0])
print(trailing_mean(x, 2))                         # [ nan 1.5 4.  6.5]
print(trailing_mean(x[:3], 2))                     # [ nan 1.5 4. ]: adding day 4 changed nothing before it

يجب أن تنمو الإحصاءات مع الزمن

التسرب الثاني خفي. توحيد سلسلة بمتوسط العينة كلها وانحرافها يستخدم أرقامًا لا توجد إلا في النهاية: فالقيم الأولى تُحجَّم بمعلومات من المستقبل. استخدم الماضي فقط: نافذة متحركة (آخر n قيمة حتى اليوم) أو متوسعة (كل شيء حتى اليوم). والاختبار لأي متغير كهذا: حسابه على أول k يوم فقط يجب أن يعطي أول k قيمة من الحساب الكامل.

# Whole-sample z-scores leak the future; expanding ones do not
import numpy as np

x = np.array([1.0, 3.0, 2.0, 8.0, 4.0])
whole = (x - x.mean()) / x.std()

n = np.arange(1, len(x) + 1)
mean = np.cumsum(x) / n
var = np.cumsum(x ** 2) / n - mean ** 2
with np.errstate(divide="ignore", invalid="ignore"):
    expanding = (x - mean) / np.sqrt(var)
expanding[0] = np.nan

print(np.round(whole, 3))
print(np.round(expanding, 3))
# Prefix test: computing on x[:3] gives the first three expanding values, but not the first three whole-sample ones
print(np.round((x[:3] - x[:3].mean()) / x[:3].std(), 3))
أماكن أخرى يختبئ فيها المستقبلأسعار تُعدَّل لاحقًا بسبب تجزئة الأسهم، وقوائم مالية مؤرخة بنهاية الفترة لا بتاريخ النشر، وقائمة أعضاء مؤشر كما هي اليوم، ونموذج مضبوط على العينة كلها ثم مُختبَر على جزء منها، ومعاملات مضبوطة على فترة الاختبار. وكلها الخطأ نفسه: رقم استُخدم قبل وقت معرفته.
  • انحياز النظر إلى المستقبل هو استخدام أي معلومة قبل معرفتها؛ والمحاذاة هي صورته الكلاسيكية: إشارة اليوم t تُتداول من اليوم t + 1.
  • يجب أن تُبنى المتغيرات من الماضي فقط: نوافذ متحركة أو متوسعة، لا متوسط العينة كلها أو انحرافها.
  • اختبار البادئة: متغير أو اختبار على أول k يوم يجب أن يساوي أول k نتيجة من التشغيل الكامل؛ وسلسلة الضجيج يجب ألا تربح.

التالي: تكاليف المعاملات، أول ما يجب أن يدفعه اختبار رجعي نظيف.

المختبر: ما الذي يُقيَّم

  • أخّر الإشارة باستخدام lag_signal25 نقطة
  • قِس الغش باستخدام biased_vs_honest25 نقطة
  • احسب متوسط الماضي فقط باستخدام trailing_mean25 نقطة
  • وحِّد دون تلصص باستخدام expanding_zscore25 نقطة
المستكشف · lab-89-1
▾ lab-89-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-89-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

هل تريد إعادة ضبط هذا الموضوع؟

سيعود كل ما في lab-89-1 إلى الملفات الابتدائية وستُمسح الطرفية. ستفقد حلّك الحالي ولا يمكن التراجع عن ذلك.

سيُعاد ضبطه
  • main.py ← الشيفرة الابتدائية
  • سجل الطرفية ومخرجات الاختبارات
  • التغييرات غير المُرسلة
سيُحتفظ به
  • أفضل درجة في المختبر
  • نقاط XP والتتابع
  • تقدّم المحاضرة والملاحظات

سجّل الدخول لتشغيل الكود الخاص بك.

قراءة كل المحاضرات مجانية. أنشئ حسابًا أو سجّل الدخول لتشغيل الكود وتنفيذ الاختبارات وتسليم هذا المختبر.

  • بيئة تطوير داخل المتصفح مع طرفية bash — لا حاجة لتثبيت أي شيء
  • تصحيح فوري ونقاط خبرة ومكانك في المسار
إنشاء حسابتسجيل الدخول
أو
المتابعة عبر GitHub