σμ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 10 · Hochleistungs-Python-Entwicklung›Thema 10.8·~1 Std.Fortgeschritten

C++ mit pybind11 aufrufen

Position in der SkillModul 10 von 11 · Thema 8 von 13
10.8 C++ mit pybind11 aufrufen
—Lab-Punkte— / 100XP gesamt—Serie—

Wenn Python C++ braucht

Ein großer Teil des ernsthaften Codes der Tradingwelt ist C++: Matching-Engines, Marktdaten-Handler, über fünfzehn Jahre abgestimmte Bewertungsbibliotheken. Man will ihn selten neu schreiben und selten Python für die Recherche aufgeben. pybind11 ist die Brücke: eine Header-only-C++-Bibliothek, in der Sie wenige Zeilen schreiben, die sagen „mache diese C++-Funktion unter diesem Namen für Python verfügbar“, sie zu einer Shared Library kompilieren und aus Python wie jedes Modul importieren. Argumente und Ergebnisse werden für Sie konvertiert: Eine Python-Liste von Floats wird zu einem std::vector<double> und zurück.

# A C++ function and the pybind11 file that exposes it to Python (shown here as text)
cpp = """\
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>

namespace py = pybind11;

double mean(const std::vector<double>& x) {
    double total = 0.0;
    for (double v : x) total += v;
    return x.empty() ? 0.0 : total / x.size();
}

PYBIND11_MODULE(fastmath, m) {
    m.def("mean", &mean, "Mean of a list of floats");
}
"""
lines = cpp.splitlines()
print(lines[-2].strip())                             # m.def("mean", &mean, "Mean of a list of floats");
print(len(lines))                                    # 15

Typen über die Brücke

Jeder Python-Typ hat ein C++-Gegenstück: int ist int64_t, float ist double, str ist std::string, eine Liste von Floats ist std::vector<double>; alles andere lässt sich als generisches py::object halten. Das Einbinden von <pybind11/stl.h> macht die Konvertierung von Standardcontainern automatisch. Übergeben Sie große Werte als const-Referenz (const std::vector<double>& x), damit die C++-Funktion sie nicht kopiert, und kleine Werte wie Zahlen als Wert. Die Umwandlung einer Python-Liste in einen Vektor kopiert dennoch einmal pro Aufruf, daher nutzen Sie für große Arrays py::array_t<double>, das den Speicher eines NumPy-Arrays direkt ohne Kopie sieht.

# Choosing the C++ type of each argument; big values are passed by const reference
CPP_TYPES = {"int": "int64_t", "float": "double", "str": "std::string", "list[float]": "std::vector<double>"}

def cpp_type(py_type):
    return CPP_TYPES.get(py_type, "py::object")

def cpp_signature(name, params, returns):
    result = "void" if returns is None else cpp_type(returns)
    arguments = []
    for param, py_type in params:
        ctype = cpp_type(py_type)
        arguments.append(f"const {ctype}& {param}" if ctype.startswith("std::") else f"{ctype} {param}")
    return f"{result} {name}({', '.join(arguments)})"

print(cpp_signature("mean", [("x", "list[float]"), ("n", "int")], "float"))      # double mean(const std::vector<double>& x, int64_t n)
print(cpp_signature("label", [("symbol", "str")], "str"))                       # std::string label(const std::string& symbol)

Build, GIL und Besitz

Gebaut wird mit CMake (pybind11_add_module) oder mit pybind11.setup_helpers in einer setup.py, und das Ergebnis ist eine .so- oder .pyd-Datei, die man importiert. Zwei Dinge sind wichtig. Erstens bleibt die Global Interpreter Lock (GIL) während der Ausführung von C++-Code gehalten, außer Sie geben sie mit py::gil_scoped_release frei; eine lange C++-Berechnung, die keine Python-Objekte anfasst, sollte sie freigeben, damit andere Python-Threads laufen können. Zweitens der Besitz: Gibt C++ eine Referenz oder einen Zeiger auf seinen eigenen Speicher zurück, darf Python ihn nicht überleben (py::return_value_policy steuert das), und ein Absturz ohne Python-Traceback deutet meist auf einen hängenden Zeiger. Testen Sie die gebundenen Funktionen aus Python gegen eine reine Python-Version, genau wie in den vorigen Labs.

# Binding lines and the module file, generated from a table of functions
BACKSLASH = chr(92)

def binding_line(py_name, cpp_name, doc):
    escaped = doc.replace(BACKSLASH, BACKSLASH + BACKSLASH).replace('"', BACKSLASH + '"')
    return f'm.def("{py_name}", &{cpp_name}, "{escaped}");'

def module_source(module, functions):
    lines = ["#include <pybind11/pybind11.h>", "#include <pybind11/stl.h>", "", "namespace py = pybind11;", ""]
    lines.append(f"PYBIND11_MODULE({module}, m) {{")
    for py_name, cpp_name, doc in functions:
        lines.append("    " + binding_line(py_name, cpp_name, doc))
    lines.append("}")
    return "\n".join(lines) + "\n"

source = module_source("pricing", [("mean", "mean_impl", "Mean of x"), ("price", "bs_price", 'Black-Scholes "call" price')])
print(source.splitlines()[-3])                       #     m.def("mean", &mean_impl, "Mean of x");
print(source.splitlines()[-2])                       #     m.def("price", &bs_price, "Black-Scholes \"call\" price");
# From Python the built module is used like any other; this stand-in has the same interface
import types

def mean(x):
    """Mean of a list of floats"""
    return sum(x) / len(x) if x else 0.0

fastmath = types.SimpleNamespace(mean=mean)          # stands in for `import fastmath` after the build
print(fastmath.mean([100.0, 102.0, 101.0]))          # 101.0
print(fastmath.mean.__doc__)                         # Mean of a list of floats   the doc string given to m.def
print(fastmath.mean([]))                             # 0.0   what the C++ code returns for an empty vector
Ein Absturz ist keine Python-AusnahmeEin Fehler in C++-Code kann den gesamten Python-Prozess mit einem Segmentation Fault und ohne Traceback beenden, und in einem Tradingsystem heißt das, der Prozess ist weg. Validieren Sie Größen und Werte an der Grenze und werfen Sie eine C++-Ausnahme (pybind11 macht daraus eine Python-Ausnahme), kompilieren Sie in der Entwicklung mit Warnungen und Sanitizern und halten Sie die C++-Oberfläche klein: wenige gut getestete Funktionen, die die schwere Arbeit erledigen, während Python orchestriert.
  • pybind11 stellt C++-Funktionen mit PYBIND11_MODULE und m.def(...)-Zeilen für Python bereit; das Ergebnis ist ein importierbares .so/.pyd-Modul.
  • Typen entsprechen sich: int→int64_t, float→double, str→std::string, Listen→std::vector; große Werte als const-Referenz, NumPy-Arrays als py::array_t übergeben.
  • Geben Sie die GIL bei langer reiner C++-Arbeit frei, achten Sie darauf, wem zurückgegebener Speicher gehört, validieren Sie Eingaben an der Grenze und testen Sie gegen eine reine Python-Version.

Als Nächstes: Threads und die GIL, was Python-Threads parallel können und was nicht.

Lab: Was bewertet wird

  • Python-Typen mit cpp_type auf C++ abbilden25 Pkt.
  • Mit cpp_signature eine Funktion deklarieren25 Pkt.
  • Mit binding_line eine Funktion freigeben25 Pkt.
  • Mit module_source das Modul zusammensetzen25 Pkt.
Explorer · lab-124-1
▾ lab-124-1
…
bash · im Browser
learner@quantcraft:~/lab-124-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-124-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