σμ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›الوحدة 1 · أساسيات Python للمحللين الكميين›الموضوع 1.25·~40 دمبتدئ

سير عمل بحثي قابل للتكرار

الموضع في المسارالوحدة 1 من 11 · الموضوع 25 من 33
1.25 سير عمل بحثي قابل للتكرار
—درجة المختبر— / 100إجمالي XP—التتابع—

المدخلات نفسها، الجواب نفسه

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

import random

# Same seed, same "random" numbers
a = random.Random(42)
b = random.Random(42)
print([round(a.random(), 3) for _ in range(3)])   # [0.639, 0.025, 0.275]
print([round(b.random(), 3) for _ in range(3)])   # [0.639, 0.025, 0.275]

# A different seed gives a different but equally repeatable sequence
print(round(random.Random(7).random(), 3))        # 0.324

البذور وأي مولّد يملكها

تستخدم المحاكاة وإعادة العيّنات أرقامًا عشوائية، وهي في الحقيقة متتالية حتمية تبدأ من بذرة (seed). ثبّت البذرة فيتكرر التشغيل بالضبط. يهيّئ random.seed(42) المولّد العام الوحيد الذي يتشاركه البرنامج كله، فأي كود آخر يسحب أرقامًا يزيح متتاليتك. والأسلم أن تنشئ مولّدك الخاص rng = random.Random(42) (أو numpy.random.default_rng(42)) وتمرّره وتسحب منه. فتعتمد نتائجك على بذرتك وحدها، ولا تُخلّ تهيئتك بعشوائية غيرك.

import random

# The global generator is shared: seeding it changes everyone's numbers
random.seed(1)
first = random.random()
random.seed(1)
print(random.random() == first)        # True: global seeding repeats...

# ...but a private generator leaves the global one untouched
random.seed(1)
before = random.getstate()
mine = random.Random(99)
mine.random()
print(random.getstate() == before)     # True: your draws did not disturb it

بصمات للبيانات والإعدادات

كيف تعرف أن ملف البيانات هو الذي استخدمته الشهر الماضي؟ احسب مجموع تحقق: تحوّل دالة تجزئة مثل SHA-256 أي ملف إلى نص قصير ثابت الطول يتغير إن تغيّر بايت واحد. يعطيها hashlib.sha256(data).hexdigest()؛ واقرأ الملفات الكبيرة على دفعات. وتستحق الإعدادات المعاملة نفسها: سلسِل الإعداد بمفاتيح مرتّبة (json.dumps(config, sort_keys=True)) ثم جزّئ النص، فتكون البصمة واحدة لإعدادين لهما المعنى نفسه مهما كان ترتيب المفاتيح، وتختلف بمجرد تغيّر قيمة.

import hashlib
import json

# A checksum of bytes
print(hashlib.sha256(b"AAPL,184.25").hexdigest()[:12])   # 06ea4aa73ec1 (12 characters of 64)

# A fingerprint of settings, independent of key order
def fingerprint(config):
    text = json.dumps(config, sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(text.encode("utf-8")).hexdigest()[:12]

one = {"fee": 0.001, "window": 20}
two = {"window": 20, "fee": 0.001}
print(fingerprint(one) == fingerprint(two))              # True
print(fingerprint(one) == fingerprint({"fee": 0.002, "window": 20}))  # False

دوّن ما شغّلته

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

import json
import platform

# A manifest records what a run used
manifest = {
    "seed": 42,
    "config_fingerprint": "a1b2c3d4e5f6",
    "python": platform.python_version().split(".")[0] + ".x",
    "inputs": {"prices.csv": "9f86d081884c"},
}
print(json.dumps(manifest, indent=2, sort_keys=True))
# {
#   "config_fingerprint": "a1b2c3d4e5f6",
#   "inputs": {
#     "prices.csv": "9f86d081884c"
#   },
#   "python": "3.x",
#   "seed": 42
# }
قابل لإعادة الإنتاج لا يعني صحيحًاالخطأ البرمجي يتكرر بإتقان أيضًا. تتيح قابلية إعادة الإنتاج للآخرين فحص عملك وإيجاد الخطأ والوثوق بالإصلاح؛ لكنها لا تغني عن الاختبارات وفحوص سلامة البيانات ونظرة ناقدة إلى النتيجة. كما تخفي البذور الحظ: فإذا اعتمدت نتيجة على البذرة فشغّلها بعدة بذور وأبلغ عن التشتت.
  • استخدم random.Random(seed) خاصًا لتعتمد النتائج على بذرتك وحدها.
  • بصمة للبيانات (مجموع تحقق ملف) وللإعدادات (JSON مرتّب ثم SHA-256).
  • احفظ بيانًا مع كل تشغيل؛ بيئة مثبّتة + إيداع Git + أمر واحد لإعادة البناء.

التالي: الأصناف والكائنات، لجمع البيانات والدوال التي تعالجها في وحدة مرتبة.

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

  • ولّد عوائد عشوائية قابلة للتكرار باستخدام seeded_returns25 نقطة
  • خذ بصمة ملف بيانات باستخدام file_checksum25 نقطة
  • خذ بصمة إعداد باستخدام config_fingerprint25 نقطة
  • سجّل ما استخدمه تشغيل ما باستخدام run_manifest25 نقطة
المستكشف · lab-25-1
▾ lab-25-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-25-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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