pomata¶
A Polars-native quant toolkit: technical indicators, PnL accounting, and performance & risk metrics. Every public
function is a composable pl.Expr, so an entire study is one lazy Polars pipeline, from price to performance.
And it doesn’t ask you to trust its numbers — it proves them: each function is verified to the float64 floor
against an independent reference, under 100% branch coverage.
Alpha
The API is not frozen until 1.0 — expect refinement. The correctness bar holds at every commit regardless.
Three families, one grammar¶
Family |
n |
What it covers |
|---|---|---|
|
75 |
moving averages, momentum, volatility, channels, cycles, directional movement, … |
|
18 |
returns & cash-flow accounting, transaction costs, dividends, equity curves |
|
60 |
Sharpe Ratio/Sortino Ratio/Calmar Ratio, drawdown, VaR/CVaR, capture, benchmark-relative, … |
They share a grammar — pure pl.Expr factories, one canonical name per concept — and a handoff: pnl emits exactly
the return and equity series that metrics consumes.
From price to performance, in one query¶
Signal, PnL, and metrics are all plain pl.Expr, so an entire study is a single Polars pipeline — no glue code, no
DataFrame ping-pong, no second dependency between the steps:
import polars as pl
from pomata.indicators import rsi
from pomata.pnl import returns_simple, returns_gross, returns_net, cost_proportional, equity_curve
from pomata.metrics import sharpe_ratio, max_drawdown
report = (
frame # a DataFrame (or LazyFrame) with a "close" column
.with_columns(
weight=(rsi(pl.col("close"), 14) < 30).cast(pl.Float64).shift(1), # long when oversold, act next bar
asset_returns=returns_simple(pl.col("close")),
)
.with_columns(
net=returns_net(
returns_gross(pl.col("weight"), pl.col("asset_returns")),
cost_proportional(pl.col("weight"), rate=0.001),
),
)
.select(
sharpe=sharpe_ratio(pl.col("net"), periods_per_year=252),
max_drawdown=max_drawdown(equity_curve(pl.col("net"))),
)
)
The indicator feeds the signal, the signal feeds the PnL, the PnL feeds the metrics — every arrow is a pl.Expr, so
it all fuses into one Polars query (eager or lazy, a single series or a multi-asset panel via .over). The .shift(1)
is the whole no-look-ahead story: a signal computed at the close acts on the next bar, by construction.
Start here¶
Installation — one runtime dependency (Polars), Python 3.12+.
Concepts — the five ideas that make everything compose.
Tutorial — raw bars to a costed, look-ahead-free report, end to end.
Why you can trust pomata — what pomata tests, and the precision it is confident to guarantee.
The families — indicators · pnl · metrics: the catalogs, and how
pomatasolves the classic pains.API reference — every function, generated from the docstrings.
Guides — FAQ · Troubleshooting · Versioning and stability.