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-17 0.001440 -0.009897
2026-07-20 -0.021424 -0.001614
2026-07-21 0.003521 0.008341
2026-07-22 -0.005645 -0.001163
2026-07-23 -0.012980 -0.012349

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     382.968908
CAGR               0.251801
Volatility         0.383015
Sharpe             0.785685
Sortino            1.122999
Calmar             0.307819
Max Drawdown      -0.818014
Win Rate           0.525658
Periods         6677.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.07%
Back to top