σμ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›الوحدة 8 · النماذج العشوائية والتعلم الآلي›الموضوع 8.9·~1 سمتقدم

هندسة الميزات للبيانات المالية

الموضع في المسارالوحدة 8 من 11 · الموضوع 9 من 10
8.9 هندسة الميزات للبيانات المالية
—درجة المختبر— / 100إجمالي XP—التتابع—

امنح النموذج مدخلات قابلة للمقارنة

السعر 250 لا يعني شيئًا لنموذج: فهو يعتمد على السهم ويميل إلى الصعود مع الزمن، فلا تشبه قيم 2020 قيم 2010 أبدًا. وهندسة السمات تحول البيانات الخام إلى مدخلات قابلة للمقارنة عبر الزمن وبين الأصول: عوائد بدل أسعار وتقلب بدل نطاقات ودرجات معيارية بدل مستويات. وللسمات الجيدة أثر في النتيجة أكبر من اختيار النموذج، ويجب أن تصف كل سمة ما كان معروفًا في ذلك اليوم فقط.

import numpy as np

prices = np.array([100.0, 101.0, 99.0, 102.0, 104.0, 103.0, 106.0])

window = 3
momentum = np.full(len(prices), np.nan)
momentum[window:] = prices[window:] / prices[:-window] - 1          # the return over the last 3 days
print(np.round(momentum, 4))                                        # nan for the first 3 days: no price 3 days back

نوافذ تنظر إلى الوراء

معظم السمات إحصاءات نافذة خلفية: آخر n قيمة حتى اليوم متضمنًا. فالزخم يقارن اليوم بما قبل n يومًا؛ والتقلب المتحرك هو الانحراف المعياري لآخر n عائد؛ والدرجة المعيارية المتحركة تقول بكم انحراف معياري للنافذة يبعد اليوم عن متوسطها. وبـsliding_window_view نحصل على كل النوافذ كصفوف في مصفوفة ونحسب الإحصاء على محور بلا حلقة. وأول n - 1 يوم بلا نافذة كاملة وتبقى nan.

import numpy as np

prices = np.array([100.0, 101.0, 99.0, 102.0, 104.0, 103.0, 106.0])
returns = np.diff(prices) / prices[:-1]
window = 3

windows = np.lib.stride_tricks.sliding_window_view(returns, window)        # every 3-day window as a row
vol = np.full(len(returns), np.nan)
vol[window - 1:] = windows.std(axis=1, ddof=1)
print(np.round(vol, 4))                                                    # nan nan then one value per complete window

p_windows = np.lib.stride_tricks.sliding_window_view(prices, window)
z = np.full(len(prices), np.nan)
z[window - 1:] = (prices[window - 1:] - p_windows.mean(axis=1)) / p_windows.std(axis=1, ddof=1)
print(np.round(z, 3))                                                      # how unusual each price is for its last 3 days
# Features put prices of different stocks on the same footing
import numpy as np

cheap = np.array([5.0, 5.2, 5.1, 5.4, 5.5])
dear = np.array([500.0, 520.0, 510.0, 540.0, 550.0])           # ten times the price, the same movements
print(cheap[-1] / cheap[-3] - 1, dear[-1] / dear[-3] - 1)        # identical momentum, about 0.0784 for both
print(dear[-1] - dear[-3], cheap[-1] - cheap[-3])                # price changes (40.0 and 0.4) would not be comparable

الهدف ينظر إلى الأمام

ما يتنبأ به النموذج هو الهدف، وعادة عائد الأيام h التالية: prices[t + h] / prices[t] - 1. وهو العمود الوحيد المسموح له بالنظر إلى الأمام، وقيمته nan لآخر h يوم لأن المستقبل لم يحدث بعد؛ فاحذف هذه الصفوف قبل التدريب. ومن الأخطاء الشائعة سمة تحتوي الهدف بالصدفة، كنافذة مركزية أو إحصاء محسوب على كل البيانات أو عائد مستقبلي أُعيد استخدامه مدخلًا. والاختبار بسيط: يجب ألا تتغير سمة اليوم t عند إضافة أيام لاحقة.

import numpy as np

def forward_return(prices, horizon):
    out = np.full(len(prices), np.nan)
    out[:-horizon] = prices[horizon:] / prices[:-horizon] - 1
    return out

def momentum(prices, window):
    out = np.full(len(prices), np.nan)
    out[window:] = prices[window:] / prices[:-window] - 1
    return out

prices = np.array([100.0, 101.0, 99.0, 102.0, 104.0, 103.0, 106.0])
print(np.round(momentum(prices, 2), 4))                 # looks back: known on each day
print(np.round(forward_return(prices, 2), 4))           # looks forward: the target, nan for the last 2 days

# The prefix test: a feature computed on the first 5 days equals the first 5 values of the full computation
print(np.allclose(momentum(prices[:5], 2), momentum(prices, 2)[:5], equal_nan=True))      # True
احذر السمات التي هي الهدف سرًّاالسمة التي تتنبأ بشكل جيد جدًا علامة تحذير. زخم بنافذة مركزية، أو تقلب يشمل عائد الغد، أو درجة معيارية موحَّدة على العينة كلها: كل منها يجعل الاختبارات الرجعية تتألق ويفشل في الواقع. ابنِ كل سمة بحيث يمكن حسابها في الإنتاج صباح اليوم t، وتحقق منها باختبار البادئة أعلاه.
  • حوّل الأسعار إلى سمات قابلة للمقارنة: زخم prices[t] / prices[t - n] - 1 وتقلب متحرك ودرجة معيارية متحركة، كل منها على نافذة خلفية تشمل اليوم.
  • يعطي sliding_window_view كل نافذة صفًّا فلا تحتاج الإحصاءات إلى حلقة؛ وأول n - 1 يوم تبقى nan.
  • العائد المستقبلي prices[t + h] / prices[t] - 1 هو الهدف لا سمة أبدًا؛ تحقق من كل سمة باختبار البادئة.

التالي: التحقق المتدرج (walk-forward)، اختبار نموذج بالترتيب الذي يجري به الزمن فعلًا.

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

  • قِس الاتجاه باستخدام momentum25 نقطة
  • تتبّع المخاطر الأخيرة باستخدام rolling_vol25 نقطة
  • حدّد مدى غرابة اليوم باستخدام rolling_zscore25 نقطة
  • عرّف الهدف باستخدام forward_return25 نقطة
المستكشف · lab-110-1
▾ lab-110-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-110-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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