σμ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›الوحدة 9 · بيانات السوق وبنيته الدقيقة›الموضوع 9.3·~1 سمتقدم

البرمجة غير المتزامنة باستخدام asyncio

الموضع في المسارالوحدة 9 من 11 · الموضوع 3 من 5
9.3 البرمجة غير المتزامنة باستخدام asyncio
—درجة المختبر— / 100إجمالي XP—التتابع—

الانتظار دون التوقف عن العمل

في معظم الوقت لا يحسب برنامج البيانات بل ينتظر: ردّ خادم الأسعار أو تأكيد أمر أو انتهاء تنزيل. وإذا طلب عشرة أسعار واحدًا تلو الآخر انتظر عشر مرات متتالية. والشيفرة غير المتزامنة تتيح للبرنامج أن يبدأ طلبًا ويضعه جانبًا أثناء انتظاره ويمضي إلى غيره، كل ذلك في خيط واحد. وأداة بايثون لذلك هي asyncio المبنية على كلمتين مفتاحيتين: async def وawait.

# A coroutine: calling it does nothing until it is awaited
import asyncio

async def get_price(symbol):
    await asyncio.sleep(0.01)                  # stands in for waiting on a network answer
    return {"AAPL": 184.25, "MSFT": 410.5}[symbol]

coro = get_price("AAPL")
print(type(coro).__name__)                     # coroutine  nothing has run yet
print(asyncio.run(coro))                       # 184.25     the event loop runs it

async def و await وحلقة الأحداث

الدالة المعرَّفة بـ async def هي دالة كوروتين: استدعاؤها يعيد كائن كوروتين ولا ينفذ شيئًا من جسمها. وداخلها يوقف await شيئًا الكوروتين حتى يجهز ذلك الشيء ويعيد التحكم إلى حلقة الأحداث التي تستطيع تشغيل كوروتينات أخرى في الأثناء. وasyncio.run(coro) تبدأ حلقة وتشغّل كوروتينًا حتى النهاية. ولا يُستعمل await إلا داخل async def؛ ونسيانه هو الخطأ الكلاسيكي لأن النداء يعيد حينها كوروتينًا بدل الجواب.

# Awaiting ten prices one after another waits ten times; gather overlaps the waits
import asyncio
import time

async def get_price(symbol):
    await asyncio.sleep(0.05)
    return len(symbol) * 10.0

async def one_by_one(symbols):
    return [await get_price(s) for s in symbols]

async def together(symbols):
    return await asyncio.gather(*(get_price(s) for s in symbols))

symbols = ["AAPL", "MSFT", "NVDA", "TSLA", "AMZN", "META", "GOOG", "NFLX", "ORCL", "INTC"]
t0 = time.perf_counter()
asyncio.run(one_by_one(symbols))
slow = time.perf_counter() - t0
t0 = time.perf_counter()
asyncio.run(together(symbols))
fast = time.perf_counter() - t0
print(f"one by one: {slow:.2f} s, gathered: {fast:.2f} s")      # about 0.50 s against 0.05 s
print(slow > 4 * fast)                                           # True

الأخطاء والمهلات والتنفيذ اليدوي

قد يفشل الانتظار. والطلب الذي لا يجيب أبدًا يجب قطعه بـ asyncio.wait_for(coro, timeout) التي ترفع TimeoutError؛ وawait داخل try / except يعالج الأخطاء كالشيفرة العادية تمامًا، فإعادة المحاولة حلقة حول نداء منتظَر. وفي الباطن الكوروتين شيء يمكن تقديمه خطوة خطوة: coro.send(None) يشغّله حتى توقفه التالي وعند انتهائه يرفع StopIteration حاملًا النتيجة. وحلقة الأحداث هي الشيفرة التي تكرر ذلك لكثير من الكوروتينات معًا، وهكذا تشغّل اختبارات هذا المختبر كوروتيناتك.

# Stepping a coroutine by hand: this is what an event loop does for many of them
class Pause:
    def __await__(self):
        yield

async def job():
    await Pause()
    await Pause()
    return 184.25

coro = job()
steps = 0
while True:
    try:
        coro.send(None)
    except StopIteration as stop:
        print("finished with", stop.value)                  # finished with 184.25
        break
    steps += 1
print("paused", steps, "times")                              # paused 2 times
# A timeout turns a slow answer into an error you can handle, then retry
import asyncio

async def slow_feed():
    await asyncio.sleep(1.0)
    return 184.25

async def main():
    for attempt in range(1, 4):
        try:
            return await asyncio.wait_for(slow_feed(), timeout=0.01)
        except TimeoutError:
            print(f"attempt {attempt} timed out")
    return None

print(asyncio.run(main()))                                   # three timeouts, then None
التزامن ليس تفرعًايشغّل asyncio كوروتينًا واحدًا في كل مرة ولا يبدّل إلا عند await. وهو يسرّع انتظار الشبكة لا الحساب الثقيل: فالحساب الطويل داخل كوروتين يحجب الحلقة وكل الكوروتينات معه. أجرِ الحساب في دوال عادية واحتفظ بالكوروتينات للانتظار.
  • async def تعرّف دالة كوروتين؛ واستدعاؤها ينشئ كوروتينًا فقط ولا يشغّل شيئًا بعد.
  • await يتوقف حتى تجهز النتيجة ويدع حلقة الأحداث تشغّل غيره؛ ولا يعمل إلا داخل async def.
  • asyncio.run تبدأ الحلقة وgather تداخل الانتظارات وwait_for تضيف مهلة؛ وتُعالج الأخطاء بـ try / except عادية.

التالي: بث البيانات عبر websockets، استقبال تدفق حي من التيكات لحظة حدوثها.

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

  • انتظر سعرًا واحدًا باستخدام get_price25 نقطة
  • اجلب قائمة المراقبة باستخدام get_prices25 نقطة
  • تجاوز انتهاء المهلة باستخدام retry_price25 نقطة
  • كن حلقة الأحداث باستخدام drive25 نقطة
المستكشف · lab-114-1
▾ lab-114-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-114-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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