σμ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›الوحدة 11 · أنظمة الإنتاج والنماذج المتقدمة›الموضوع 11.13·~4 سخبير

المشروع الختامي: مكتبة تسعير أو استراتيجية متكاملة

الموضع في المسارالوحدة 11 من 11 · الموضوع 13 من 13
11.13 المشروع الختامي: مكتبة تسعير أو استراتيجية متكاملة
—درجة المختبر— / 100إجمالي XP—التتابع—

من التمارين إلى مكتبة

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

# The shape of a small library: a package, its tests, its metadata and its automated checks
tree = """\
quantlib/
├── pyproject.toml            name, version, dependencies (numpy)
├── src/quantlib/
│   ├── __init__.py           the public API: sma_positions, strategy_returns, performance_summary, run_strategy
│   ├── signals.py            prices -> positions
│   ├── backtest.py           positions -> returns after costs
│   └── metrics.py            returns -> total return, volatility, Sharpe, drawdown
├── tests/                    one test file per module, fixed seeds, hand-checked cases
└── .github/workflows/ci.yml  lint, types, tests on every push
"""
print(tree.splitlines()[0])                          # quantlib/
print(sum(1 for line in tree.splitlines() if ".py" in line))     # 4   the four module files

الإشارة والاختبار الرجعي: بلا استباق ومع التكاليف

الإشارة هنا تقاطع متوسطين متحركين: كن طويلًا حين يكون متوسط الأسعار السريع فوق البطيء وقصيرًا حين يكون تحته ومحايدًا حين يتساويان أو لا يوجد البطيء بعد. والقاعدتان اللتان تحددان نزاهة الاختبار الرجعي ظاهرتان في الشيفرة. الأولى عدم الاستباق: فالمركز المقرر عند إغلاق اليوم t لا يستعمل إلا الأسعار حتى اليوم t ويكسب عائد اليوم t + 1 ولذلك يستعمل عائد الخطوة t القيمة positions[t - 1]. ويثبت ذلك اختبار: حذف آخر الأسعار يجب ألا يغير المراكز السابقة. والثانية التكاليف: كل تغيير في المركز يدفع cost * |التغيير| فقد تربح استراتيجية تقلب باستمرار قبل التكاليف وتخسر بعدها.

# The signal and the honest backtest: positions decided at the close are earned on the NEXT step, and trading costs money
import numpy as np

def sma_positions(prices, fast, slow):
    prices = np.asarray(prices, dtype=float)
    positions = np.zeros(len(prices), dtype=int)
    for t in range(slow - 1, len(prices)):
        f = prices[t - fast + 1 : t + 1].mean()
        s = prices[t - slow + 1 : t + 1].mean()
        positions[t] = 1 if f > s else -1 if f < s else 0
    return positions

def strategy_returns(prices, positions, cost):
    returns = []
    for t in range(1, len(prices)):
        before = positions[t - 2] if t >= 2 else 0
        returns.append(positions[t - 1] * (prices[t] / prices[t - 1] - 1) - cost * abs(positions[t - 1] - before))
    return np.array(returns)

prices = np.array([100, 101, 103, 102, 105, 108, 107, 110, 112, 111, 115, 118], dtype=float)
positions = sma_positions(prices, 2, 4)
print(positions)                                     # [0 0 0 1 1 1 1 1 1 1 1 1]   flat until the 4-day average exists, then long
print(np.allclose(sma_positions(prices[:8], 2, 4), positions[:8]))      # True   later prices never change earlier positions
print(np.round(strategy_returns(prices, positions, 0.0).sum() - strategy_returns(prices, positions, 0.001).sum(), 3))    # 0.001   one purchase at 0.1%

أرقام الأداء والمشغّل

تُلخَّص سلسلة العوائد بأرقام قليلة. العائد الإجمالي يركّب الفترات prod(1 + r) - 1؛ والعائد السنوي يعيده إلى سنة (1 + total)^(periods_per_year / n) - 1؛ والتقلب السنوي هو الانحراف المعياري للعينة مضروبًا في sqrt(periods_per_year)؛ ونسبة شارب تقسم متوسط العائد على ذلك الانحراف، مُسنَّنة، وهي المقياس الرئيس للعائد لكل وحدة مخاطرة (0 لسلسلة مسطحة بدل خطأ القسمة)؛ وأقصى سحب (drawdown) هو أسوأ هبوط من قمة منحنى رأس المال، الرقم الذي يقول كم ألمًا تطلب منك الاستراتيجية تحمله. وتربط دالة المشغّل الكل: المراكز ثم العوائد ثم الملخص. وينبغي أن تركّب الدوال الأخرى فقط ليُتتبَّع أي خطأ دائمًا إلى مرحلة واحدة.

# Performance statistics of a return series, and the runner that wires the three stages together
import math
import numpy as np

def performance_summary(returns, periods_per_year):
    returns = np.asarray(returns, dtype=float)
    n = len(returns)
    equity = np.concatenate(([1.0], np.cumprod(1 + returns)))
    total = float(equity[-1] - 1)
    deviation = float(np.std(returns, ddof=1))
    peak = np.maximum.accumulate(equity)
    return {
        "total_return": total,
        "annual_return": float((1 + total) ** (periods_per_year / n) - 1),
        "annual_vol": deviation * math.sqrt(periods_per_year),
        "sharpe": float(returns.mean() / deviation * math.sqrt(periods_per_year)) if deviation > 0 else 0.0,
        "max_drawdown": float(np.max((peak - equity) / peak)),
    }

summary = performance_summary([0.10, -0.20, 0.05], 252)
print(round(summary["total_return"], 4), round(summary["max_drawdown"], 4))     # -0.076 0.2   equity 1 -> 1.1 -> 0.88 -> 0.924: a 20% fall from the peak
print(performance_summary([0.0, 0.0, 0.0], 252)["sharpe"])                       # 0.0   no variation: a Sharpe of 0, not an error
# The runner only composes: if a number looks wrong you can test each stage on its own
def run_strategy(prices, fast, slow, cost, periods_per_year=252):
    positions = sma_positions(prices, fast, slow)
    returns = strategy_returns(prices, positions, cost)
    return performance_summary(returns, periods_per_year)

# (sma_positions, strategy_returns and performance_summary are the functions you wrote in this lab)
steps = ["sma_positions", "strategy_returns", "performance_summary"]
print(" -> ".join(steps))                           # sma_positions -> strategy_returns -> performance_summary
print(len(steps), "stages, one result: a dict of five numbers")        # 3 stages, one result: a dict of five numbers

مشروعك الختامي

ابنِ الآن مشروعك في مستودعك الخاص. اختر واحدًا من اتجاهين. مكتبة تسعير: بلاك-شولز والمعاملات اليونانية ومسعّر مونت كارلو بمتغيرات متقابلة ومحلّل للتقلب الضمني ومعايرة نموذج على مجموعة أسعار. أو مكتبة استراتيجيات: عدة إشارات واختبار رجعي مع تكاليف وحدود مراكز وتقييم walk-forward وتقرير. وفي الحالتين سلّم الأشياء نفسها: حزمة بواجهة عامة واضحة وتلميحات أنواع؛ واختبارات ببذور ثابتة وحالات مفحوصة يدويًا؛ وملف pyproject.toml وREADME يبين كيفية التثبيت وتشغيل مثال؛ وسير عمل CI يشغّل lint والأنواع والاختبارات؛ وملاحظة أداء بعنق زجاجة مُحلَّل؛ ونصًّا موجزًا عن الافتراضات وما يكسر النموذج. ووزّع وقتك: صمّم الواجهة أولًا ثم ابنِ أصغر خط معالجة عامل ثم وسّعه.

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

بهذا ينتهي المسار. صار لديك الآن اللغة والأدوات العددية وقطع بيانات السوق والتنفيذ والنماذج وعادات الهندسة لمطوّر كوانت عامل. احتفظ بمستودع مشروعك الختامي: فهو أفضل دليل على المهارات التي بنيتها هنا.

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

  • حوّل الاتجاه إلى مراكز باستخدام sma_positions25 نقطة
  • اختبر رجعيًا مع التكاليف في strategy_returns25 نقطة
  • احكم على النتيجة باستخدام performance_summary25 نقطة
  • اربط كل شيء معًا في run_strategy25 نقطة
المستكشف · lab-142-1
▾ lab-142-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-142-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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