σμ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 AcademySkills
Ctrl K
AO
+1,2 Tsd. Lernende
AnmeldenBeitreten ↗
Skills
AO
+1,2 Tsd. Lernende
Anmelden
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python-Skill›Modul 9 · Marktdaten und Mikrostruktur›Thema 9.3·~1 Std.Fortgeschritten

Asynchroner Code mit asyncio

Position in der SkillModul 9 von 11 · Thema 3 von 5
9.3 Asynchroner Code mit asyncio
—Lab-Punkte— / 100XP gesamt—Serie—

Warten, ohne stillzustehen

Meistens rechnet ein Datenprogramm nicht, es wartet: auf die Antwort eines Preisservers, auf die Bestätigung einer Order, auf das Ende eines Downloads. Fragt es zehn Preise nacheinander ab, wartet es zehnmal hintereinander. Asynchroner Code lässt ein Programm eine Anfrage starten, sie beiseitelegen, solange sie wartet, und mit einer anderen weitermachen, alles in einem einzigen Thread. Das Python-Werkzeug dafür ist asyncio, gebaut aus zwei Schlüsselwörtern, async def und 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 und die Ereignisschleife

Eine mit async def definierte Funktion ist eine Coroutine-Funktion: Ihr Aufruf liefert ein Coroutine-Objekt und führt nichts vom Rumpf aus. Darin pausiert await etwas die Coroutine, bis etwas bereit ist, und gibt die Kontrolle an die Ereignisschleife zurück, die währenddessen andere Coroutinen ausführen kann. asyncio.run(coro) startet eine Schleife und führt eine Coroutine bis zum Ende aus. await gibt es nur innerhalb einer async def; es zu vergessen ist der klassische Fehler, denn der Aufruf liefert dann eine Coroutine statt der Antwort.

# 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

Fehler, Timeouts und von Hand fahren

Warten kann scheitern. Eine Anfrage, die nie antwortet, schneidet man mit asyncio.wait_for(coro, timeout) ab, was TimeoutError auslöst; ein await in try / except behandelt Fehler genau wie gewöhnlicher Code, ein Wiederholungsversuch ist also eine Schleife um einen erwarteten Aufruf. Unter der Haube ist eine Coroutine etwas, das man Schritt für Schritt vorantreiben kann: coro.send(None) führt sie bis zur nächsten Pause aus und löst beim Ende StopIteration mit dem Ergebnis aus. Eine Ereignisschleife ist der Code, der das für viele Coroutinen zugleich tut, und so führen auch die Tests dieses Labs Ihre aus.

# 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
Nebenläufigkeit ist keine Parallelitätasyncio führt jeweils eine Coroutine aus und wechselt nur bei einem await. Es beschleunigt das Warten aufs Netz, nicht schwere Arithmetik: Eine lange Rechnung in einer Coroutine blockiert die Schleife und damit alle anderen Coroutinen. Rechnen Sie in gewöhnlichen Funktionen und heben Sie Coroutinen für das Warten auf.
  • async def definiert eine Coroutine-Funktion; der Aufruf erzeugt nur eine Coroutine, noch läuft nichts.
  • await pausiert, bis das Ergebnis bereit ist, und lässt die Ereignisschleife andere ausführen; es gibt es nur in async def.
  • asyncio.run startet die Schleife, gather überlappt Wartezeiten, wait_for ergänzt ein Zeitlimit; Fehler behandelt man mit gewöhnlichem try / except.

Als Nächstes: Streaming-Daten mit Websockets, einen Live-Feed von Ticks empfangen, während sie passieren.

Lab: Was bewertet wird

  • Mit get_price auf einen Kurs warten25 Pkt.
  • Mit get_prices eine Watchlist abrufen25 Pkt.
  • Mit retry_price einen Timeout überstehen25 Pkt.
  • Mit drive die Ereignisschleife sein25 Pkt.
Explorer · lab-114-1
▾ lab-114-1
…
bash · im Browser
learner@quantcraft:~/lab-114-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-114-1 wird auf die Startdateien zurückgesetzt und das Terminal geleert. Ihre aktuelle Lösung geht verloren – das lässt sich nicht rückgängig machen.

Wird zurückgesetzt
  • main.py → Startcode
  • Terminal-Verlauf und Testausgabe
  • Nicht eingereichte Änderungen
Bleibt erhalten
  • Beste Lab-Punktzahl
  • Ihre XP und Ihre Serie
  • Vorlesungsfortschritt und Notizen

Melde dich an, um deinen Code auszuführen.

Alle Lektionen kannst du kostenlos lesen. Erstelle ein Konto oder melde dich an, um Code auszuführen, Tests zu starten und dieses Lab abzugeben.

  • IDE im Browser mit Bash-Terminal — nichts zu installieren
  • Sofortige Bewertung, XP und dein Platz auf der Skill
Konto erstellenAnmelden
ODER
Weiter mit GitHub