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

خطوط المعالجة المجدولة

الموضع في المسارالوحدة 11 من 11 · الموضوع 3 من 13
11.3 خطوط المعالجة المجدولة
—درجة المختبر— / 100إجمالي XP—التتابع—

عمل يجري بحسب ساعة

تمتلئ عمليات التداول بمهام يجب أن تقع في أوقات محددة: تنزيل أسعار الإغلاق بعد إغلاق السوق، وإعادة بناء تقرير المخاطر عند 06:00، وإعادة التوازن عند 15:55، وأرشفة السجلات ليلة الأحد. والمجدول يبدؤها دون شخص، والجيد منه يعرف الترتيب أيضًا: تقرير المخاطر يحتاج الأسعار والمراكز أولًا. وتكفي فكرتان لفهم أي مجدول: *متى* نشغّل (قاعدة تقويم مثل cron) و*ما الذي يجب أن يسبق* (مخطط تبعيات). وتختلف الأدوات (cron ومؤقتات systemd وAirflow وPrefect وDagster ومجدولات السحابة) لكنها كلها تقوم على هذا.

# A cron expression has five fields: minute hour day-of-month month day-of-week
expression = "30 9 * * 1-5"
minute, hour, day_of_month, month, day_of_week = expression.split()
print(minute, hour, day_of_week)                     # 30 9 1-5   09:30 on Monday to Friday
print(list(range(1, 6)))                             # [1, 2, 3, 4, 5]   day-of-week 0 is Sunday, so 1-5 is Monday to Friday

قراءة cron: الحقول والمجالات والخطوات

يختار كل حقل من الحقول الخمسة قيمًا: * كل القيم وa قيمة واحدة وa-b مجالًا و*/n كل n-ة قيمة وتصل الفواصل العناصر (1,15,20-22). فـ */15 * * * * كل خمس عشرة دقيقة و0 9 * * 1-5 الساعة 09:00 في أيام العمل. وتطابق اللحظةُ التعبيرَ حين تختارها الحقول الخمسة كلها. ولإيجاد التشغيل التالي تقدّم دقيقة دقيقة من الوقت الحالي حتى يطابق شيء؛ وهذا بطيء نظريًا لكنه تافه لتقويم ويعالج نهايات الأشهر والسنوات الكبيسة مجانًا. وفي cron الحقيقي غرابة (حين يُقيَّد يوم الشهر ويوم الأسبوع معًا يعمل إذا طابق *أحدهما*)؛ ويستعمل المختبر القاعدة الأبسط *كلاهما*.

# Which values does a cron field select? Ranges, steps and lists
def field_values(field, low, high):
    chosen = set()
    for item in field.split(","):
        body, _, step = item.partition("/")
        step = int(step) if step else 1
        if body == "*":
            first, last = low, high
        elif "-" in body:
            first, last = (int(part) for part in body.split("-"))
        else:
            first = int(body)
            last = high if "/" in item else first
        chosen.update(range(first, last + 1, step))
    return sorted(chosen)

print(field_values("*/15", 0, 59))                   # [0, 15, 30, 45]
print(field_values("1,15,20-22", 1, 31))             # [1, 15, 20, 21, 22]
print(field_values("10-30/10", 0, 59))               # [10, 20, 30]
# The next run: step forward minute by minute until the five fields all match
from datetime import datetime, timedelta

def matches(minute_set, hour_set, weekday_set, when):
    return when.minute in minute_set and when.hour in hour_set and (when.weekday() + 1) % 7 in weekday_set

def next_run(after):
    moment = after.replace(second=0, microsecond=0)
    while True:
        moment += timedelta(minutes=1)
        if matches({0}, {9}, {1, 2, 3, 4, 5}, moment):          # "0 9 * * 1-5"
            return moment

print(next_run(datetime(2024, 3, 8, 17, 0)))         # 2024-03-11 09:00:00   Friday evening: the next weekday 09:00 is Monday
print(next_run(datetime(2024, 3, 11, 8, 59, 30)))    # 2024-03-11 09:00:00   seconds are ignored

التبعيات وإعادة المحاولة والمناطق الزمنية

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

# A valid run order: every job after its dependencies, the alphabetically first among those that are ready
def run_order(tasks):
    done, remaining = [], set(tasks)
    while remaining:
        ready = sorted(name for name in remaining if all(dep in done for dep in tasks[name]))
        if not ready:
            raise ValueError("cycle detected")
        done.append(ready[0])
        remaining.remove(ready[0])
    return done

tasks = {"report": ["risk"], "risk": ["prices", "positions"], "prices": [], "positions": []}
print(run_order(tasks))                              # ['positions', 'prices', 'risk', 'report']
try:
    run_order({"a": ["b"], "b": ["a"]})
except ValueError as error:
    print(error)                                     # cycle detected
الخطر الحقيقي هو الفشل الصامتالمهمة التي تنهار بضجيج مزعجة، والتي لا تعمل بصمت كارثة، لأن أحدًا لا يلاحظ أن أسعار الأمس لم تُحمَّل أبدًا. اجعل كل مهمة تبلّغ بنجاحها أو فشلها في مكان مراقَب، ونبّه عند غياب تشغيل متوقع (لا عند فشل أحدها فقط)، وسجّل المدخلات والتاريخ المعالَج، وأبقِ طريقة لتعويض يوم فائت. واختبر منطق الجدولة بأوقات ثابتة كالتي في هذا المختبر بدل انتظار الساعة.
  • لتعبير cron خمسة حقول (الدقيقة والساعة ويوم الشهر والشهر ويوم الأسبوع) باستعمال * وa وa-b و*/n والفواصل؛ وتطابق اللحظةُ حين تختارها الحقول الخمسة.
  • اعثر على التشغيل التالي بالتقدم دقيقة دقيقة؛ وتشكّل المهام مخطط تبعيات وتعمل بترتيب طوبولوجي والدورة خطأ.
  • اجعل المهام متكافئة التكرار وأعد المحاولة بتراجع وتجنب التشغيلات المتداخلة وجدوِل بمنطقة زمنية صريحة مع تقويم تداول ونبّه عند غياب التشغيلات.

التالي: تنفيذ TWAP، تقسيم أمر كبير إلى أجزاء متساوية عبر الزمن.

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

  • اقرأ حقل cron باستخدام parse_cron_field25 نقطة
  • اختبر لحظة باستخدام cron_matches25 نقطة
  • اعثر على التشغيل التالي باستخدام next_run25 نقطة
  • رتّب المهام باستخدام run_order25 نقطة
المستكشف · lab-132-1
▾ lab-132-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-132-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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