σμ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.2·~1 سخبير

CI/CD للشيفرة الكمية

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

فحوص تعمل من تلقاء نفسها

لا تحميك الاختبارات إلا إن شُغِّلت في كل مرة بشيء غير ذاكرتك. والتكامل المستمر (CI) خادم يسحب الشيفرة عند كل push وطلب دمج في بيئة نظيفة ويشغّل الفحوص التي حددتها: lint وفحص الأنواع والاختبارات واختبار رجعي صغير. وإن فشل شيء حُجب التغيير. أما التسليم/النشر المستمر (CD) فيذهب أبعد: عند نجاح الفحوص على الفرع الرئيس يُبنى الإصدار الجديد ويُنشر تلقائيًا. وفي العمل الكمي الرهان ملموس: إعادة هيكلة تزحزح سعرًا بصمت نقطة أساس واحدة ينبغي أن تلتقطها آلة قبل أن تصل إلى محفظة.

# A test matrix: every operating system with every Python version, minus the combinations you skip
from itertools import product

os_list = ["linux", "macos", "windows"]
py_versions = ["3.11", "3.12"]
exclude = {("windows", "3.11")}

jobs = [(os_name, version) for os_name, version in product(os_list, py_versions) if (os_name, version) not in exclude]
print(len(jobs))                                     # 5
print(jobs[0], jobs[-1])                             # ('linux', '3.11') ('windows', '3.12')

ما الذي يفحصه خط معالجة كمي

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

# Test selection: run only the tests a change can affect; an unknown file means "run everything"
def select_tests(changed_files, mapping):
    chosen = set()
    for path in changed_files:
        matches = [tests for prefix, tests in mapping.items() if path.startswith(prefix)]
        if not matches:
            return sorted({test for tests in mapping.values() for test in tests})
        for tests in matches:
            chosen.update(tests)
    return sorted(chosen)

mapping = {"src/pricing/": ["tests/test_bs.py", "tests/test_greeks.py"], "src/risk/": ["tests/test_var.py"]}
print(select_tests(["src/risk/var.py"], mapping))                    # ['tests/test_var.py']
print(select_tests(["src/risk/var.py", "setup.cfg"], mapping))       # all three tests: setup.cfg could affect anything

البوابات والأسرار وملف سير العمل

يُوصَف خط المعالجة في ملف محفوظ في المستودع، مثل .github/workflows/ci.yml في GitHub Actions: متى يعمل (on:) والمهام والمصفوفة والخطوات، وكل خطوة إما uses: إجراء جاهزًا أو run: أمرًا. عامل الملف كشيفرة تُراجَع كغيرها. وأضف بوابة نشر: لا ينشر إلا الفرع main ولا ينشر إلا إذا نجحت كل المهام المطلوبة (المهمة المتجاوزة أو الغائبة ليست نجاحًا). واحمِ الفرع كي لا يُدمج دون فحوص ناجحة. وأبقِ مفاتيح API وكلمات المرور في أسرار نظام CI لا في المستودع أبدًا، وامنح كل مهمة الصلاحيات التي تحتاجها فقط. وانشر أولًا في بيئة تداول تجريبي أو بيئة مرحلية.

# The deploy gate: main branch only, and every required job must have succeeded
def can_deploy(results, required, branch):
    return branch == "main" and all(results.get(job) == "success" for job in required)

print(can_deploy({"lint": "success", "tests": "success"}, ["lint", "tests"], "main"))     # True
print(can_deploy({"lint": "success", "tests": "skipped"}, ["lint", "tests"], "main"))     # False  skipped is not success
print(can_deploy({"lint": "success"}, ["lint", "tests"], "main"))                         # False  a missing job is not success
print(can_deploy({"lint": "success", "tests": "success"}, ["lint", "tests"], "dev"))      # False  only main deploys
# The workflow file is plain text, so it can be generated and checked like any other output
def workflow_yaml(name, python_versions, command):
    versions = ", ".join(f'"{version}"' for version in python_versions)
    lines = [f"name: {name}", "on: [push, pull_request]", "jobs:", "  test:", "    runs-on: ubuntu-latest",
             "    strategy:", "      matrix:", f"        python-version: [{versions}]", "    steps:",
             "      - uses: actions/checkout@v4", "      - uses: actions/setup-python@v5", "        with:",
             "          python-version: ${{ matrix.python-version }}", "      - run: pip install -e .[test]",
             f"      - run: {command}"]
    return "\n".join(lines) + "\n"

text = workflow_yaml("ci", ["3.11", "3.12"], "pytest -q")
print(text.splitlines()[7])                          #         python-version: ["3.11", "3.12"]
print(text.splitlines()[-1])                         #       - run: pytest -q
خط المعالجة الأخضر بقدر اختباراتهتثبت CI أن الفحوص تنجح لا أن الاستراتيجية جيدة. أبقِ المجموعة سريعة ليشغّلها الناس، وأصلح الاختبار المتذبذب أو احذفه (فالاختبار الذي يفشل عشوائيًا يعلّم الجميع تجاهل اللون الأحمر)، وعامل البناء الفاشل كأولوية الفريق الأولى. ثبّت إصدارات الأدوات المستعملة في CI، وأبقِ طريقة لتشغيل الفحوص نفسها بالضبط على جهازك لئلا يكون «يعمل عندي» و«يفشل في CI» لغزًا.
  • تشغّل CI فحص lint والأنواع والاختبارات في بيئة نظيفة عند كل push؛ ولا ينشر CD تلقائيًا إلا إذا نجحت على main.
  • اجعل الفحوص حتمية (بذور ولقطات وبلا شبكة) وشغّلها على مصفوفة من الإصدارات والأنظمة واختر الاختبارات بحسب ما تغيّر.
  • صِف خط المعالجة في ملف سير عمل يُراجَع، واشترط للنشر main والمهام المطلوبة، وأبقِ الأسرار في نظام CI، وأصلح الاختبارات المتذبذبة.

التالي: خطوط المعالجة المجدولة، تشغيل مهام البيانات والتداول في الوقت الصحيح وبالترتيب الصحيح.

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

  • وسّع مصفوفة الاختبارات باستخدام matrix_jobs25 نقطة
  • شغّل ما يهم فقط باستخدام select_tests25 نقطة
  • احرس الإصدار باستخدام can_deploy25 نقطة
  • ولّد سير العمل باستخدام workflow_yaml25 نقطة
المستكشف · lab-131-1
▾ lab-131-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-131-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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