Chained API

q.stats.returns(...) binds a return stream (and optional benchmark) once and exposes the same stats as methods. These code cells are executed live by Quarto every time the docs are built.

Real return streams

We use qrt’s bundled sample datasets — AAPL as the “strategy” and SPY as the benchmark — loaded offline via q.data.datasets.load, no network dependency:

import pandas as pd

import qrt as q

aapl = q.data.datasets.load("aapl")
spy = q.data.datasets.load("spy")

returns = pd.concat(
    {
        "AAPL": aapl["close"].pct_change(),
        "SPY": spy["close"].pct_change(),
    },
    axis=1,
).dropna()
strategy = returns["AAPL"]
benchmark = returns["SPY"]

returns.tail()
AAPL SPY
datetime
2026-07-13 0.006311 -0.007656
2026-07-14 -0.007721 0.003551
2026-07-15 0.040145 0.003964
2026-07-16 0.017588 -0.005419
2026-07-17 0.001440 -0.009897

Chained API: q.stats.returns(...)

For notebook exploration, q.stats.returns() binds a return stream (and optional benchmark) once and exposes the same stats as methods, plus .plot(kind=...) which delegates to q.plot. Each call creates a fresh, independent object — there is no hidden global state to reason about:

bound = q.stats.returns(strategy, benchmark=benchmark)

bound.performance()
Total Return     397.388914
CAGR               0.253714
Volatility         0.383092
Sharpe             0.789598
Sortino            1.128677
Calmar             0.310158
Max Drawdown      -0.818014
Win Rate           0.525824
Periods         6673.000000
Name: AAPL, dtype: float64

kind accepts "performance"/"tearsheet" (equity + drawdown report), "equity", "drawdown", or "monthly_heatmap". The bound benchmark is passed through automatically for the report variants:

print(f"Beta: {bound.beta():.2f}")
print(f"Alpha: {bound.alpha():.2%}")

fig = bound.plot("performance")
fig.show()
Beta: 1.13
Alpha: 19.19%
Back to top