σμ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›الوحدة 2 · NumPy وpandas لبيانات السوق›الموضوع 2.14·~40 دمتوسط

النوافذ المتحركة

الموضع في المسارالوحدة 2 من 11 · الموضوع 14 من 20
2.14 النوافذ المتحركة
—درجة المختبر— / 100إجمالي XP—التتابع—

نافذة تنزلق

سعر اليوم لا يعني الكثير وحده؛ يقارنه المتداولون بالماضي القريب. تحتفظ النافذة المتحركة بآخر n ملاحظة وتتقدم خطوة خطوة، فيحصل كل تاريخ على إحصاء محسوب من تاريخه القريب: متوسط متحرك أو تقلب حديث أو قمة حديثة. وفي pandas تصف series.rolling(n) النافذة، ويحسبها إحصاء مثل .mean() عند كل موضع دفعة واحدة.

import pandas as pd

prices = pd.Series(
    [100.0, 102, 101, 105, 107, 106, 110],
    index=pd.bdate_range("2026-03-02", periods=7),
    name="close",
)

moving_average = prices.rolling(3).mean()
print(moving_average.round(2).tolist())
# [nan, nan, 101.0, 102.67, 104.33, 106.0, 107.67]

print(prices.rolling(3).max().tolist())   # [nan, nan, 102.0, 105.0, 107.0, 107.0, 110.0]   the 3-day high

بداية السلسلة

المواضع الأولى n - 1 ليس لها نافذة كاملة بعد، لذا تكون النتيجة NaN فيها. وهذا صادق: متوسط سعرين ليس متوسط 3 أيام. وإن أردت قيمة أبكر فعلًا فإن min_periods=1 تحسب بما هو متاح، وتستخدم expanding() كل ما منذ البداية بدل نافذة ثابتة. والإحصاءات التي تحتاج نقاطًا عدة، كالانحراف المعياري، تبقى NaN حتى تصل ملاحظات كافية. والسلسلة التي تبدأ أصلًا بـ NaN، مثل العوائد البسيطة، تؤخر أول نافذة صالحة خطوة.

# min_periods=1: use whatever is available at the start
print(prices.rolling(3, min_periods=1).mean().round(2).tolist())   # [100.0, 101.0, 101.0, 102.67, 104.33, 106.0, 107.67]

# expanding(): everything since the first day, not a fixed window
print(prices.expanding().mean().round(2).tolist())   # [100.0, 101.0, 101.0, 102.0, 103.0, 103.5, 104.43]

# Rolling volatility of the returns: the first return is NaN, so three returns exist only from the 4th day
returns = prices.pct_change()
print(returns.rolling(3).std().round(4).tolist())   # [nan, nan, nan, 0.0249, 0.0248, 0.0246, 0.0237]

من النوافذ إلى الإشارات

تصبح الإحصاءات المتحركة إشارات تداول عند مقارنتها. يبيّن المعيار z كم يبعد سعر اليوم عن متوسطه الحديث بوحدات انحرافه المعياري الحديث: (price - rolling mean) / rolling std. أنشئ كائن النافذة مرة واحدة (r = prices.rolling(3)) واستخدمه مرتين. ويقارن تقاطع المتوسطات المتحركة متوسطًا سريعًا بآخر بطيء: ما دام السريع أعلى فالاتجاه الحديث صاعد. تعطي المقارنة قيمًا منطقية، ويحوّلها astype("int64") إلى إشارة 0/1. والمقارنات مع NaN تساوي False، فتبقى الإشارة 0 حتى يوجد المتوسطان.

# z-score of each price against its own 3-day window
rolling = prices.rolling(3)
zscore = (prices - rolling.mean()) / rolling.std()
print(zscore.round(2).tolist())   # [nan, nan, 0.0, 1.12, 0.87, 0.0, 1.12]
# Moving-average crossover: 1 while the 2-day average is above the 4-day average
fast = prices.rolling(2).mean()
slow = prices.rolling(4).mean()
signal = (fast > slow).astype("int64")
print(signal.tolist())   # [0, 0, 0, 1, 1, 1, 1]

# Trade on the next day: the signal of today's close cannot be traded before tomorrow
print(signal.shift(1).fillna(0).astype("int64").tolist())   # [0, 0, 0, 0, 1, 1, 1]
لا تنظر إلى المستقبلتنتهي النافذة المتحركة عند الصف الحالي فتستخدم الماضي فقط. أما center=True فتضع الصف الحالي في وسط النافذة فتستخدم أسعارًا مستقبلية: تبدو رائعة على الرسم ولا يمكن التداول بها. والإشارة المحسوبة من إغلاق اليوم يجب تطبيقها غدًا، ومن هنا shift(1).
  • series.rolling(n).mean() (أو std() أو max()...) تحسب إحصاءً على آخر n ملاحظة عند كل موضع.
  • العناصر الأولى n - 1 تكون NaN؛ ويغيّر min_periods وexpanding() ذلك عمدًا.
  • تحوّل المعايير z وتقاطعات المتوسطات المتحركة النوافذ إلى إشارات؛ أزِح الإشارة قبل التداول بها وتجنب center=True.

التالي: التعامل مع البيانات المفقودة، أي ما نفعله بقيم NaN التي تحتويها جداول الأسعار الحقيقية دائمًا.

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

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

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

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

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

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

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

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