Finance¶
The sekai.finance toolkit. Classes are exported from sekai.finance; functions from
their modules (sekai.finance.features, sekai.finance.metrics, ...). See the
Finance toolkit pages for explanations and examples.
Market data¶
sekai.finance.data. See Market data and backtesting.
MarketData
¶
MarketData(prices: ArrayLike | None = None, *, fields: Mapping[str, ArrayLike] | None = None, timestamps: ArrayLike | None = None, assets: Sequence[Any] | None = None, exogenous: Mapping[str, ArrayLike] | None = None, price_field: str = 'close', warmup: int = 0)
An immutable panel of market data aligned on one time axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prices
|
ArrayLike | None
|
Prices shaped |
None
|
fields
|
Mapping[str, ArrayLike] | None
|
More per-asset data, each |
None
|
timestamps
|
ArrayLike | None
|
|
None
|
assets
|
Sequence[Any] | None
|
|
None
|
exogenous
|
Mapping[str, ArrayLike] | None
|
Market-wide series, each |
None
|
price_field
|
str
|
Name of the field that holds the prices. |
'close'
|
warmup
|
int
|
Number of leading rows that are lookback-only history ( |
0
|
Example
prices
property
¶
Prices (T, N), NaN where an asset is not listed (read-only).
mask
property
¶
(T, N) True where the asset has a price (is listed and tradable).
exogenous
property
¶
Market-wide series, each (T,) or (T, k).
warmup
property
¶
warmup: int
Leading rows that are lookback-only history: observable, but never a decision row.
split and walk_forward set it to the history rows they prepend to a test
period; slicing keeps it correct (a slice starting inside the warm-up keeps the
remaining warm-up rows), and it is 0 for data built directly.
periods_per_year
property
¶
periods_per_year: float | None
Rows per year implied by datetime timestamps (about 252 for trading days), else None.
from_pandas
classmethod
¶
from_pandas(prices: Any, *, fields: Mapping[str, Any] | None = None, exogenous: Any = None, price_field: str = 'close') -> MarketData
Build from wide pandas DataFrames (index = timestamps, columns = assets).
Every field is aligned to the prices' index and columns (missing → NaN).
exogenous is a DataFrame (one series per column) or a mapping of name
to Series/DataFrame, aligned to the same index.
from_long
classmethod
¶
from_long(frame: Any, *, time: str = 'date', asset: str = 'symbol', price: str = 'close', fields: Sequence[str] = ()) -> MarketData
Build from a long ("tidy") DataFrame with one row per (time, asset).
Columns time and asset identify the row, price holds the price, and
each column in fields becomes a field of the same name.
exogenous_width
¶
Number of columns of an exogenous series (1 for a 1-D series).
log_returns
¶
(T, N) log returns of the prices; NaN in row 0 and wherever either price is missing.
index_of
¶
Row position of a point in time: a row position or a timestamp.
- An
intis a row position on every time axis (negative counts from the end), returned as is. - A timestamp gives the first row at or after it (after it with
side="right"), orn_stepsif there is none. On datetime timestamps it is anythingnumpy.datetime64accepts (adatetime64,datetime,date, pandasTimestampor date string); on numeric timestamps, a float. Time(t)is a timestamp on either kind of axis, so it also looks up integer timestamps (epoch seconds, or the timestamps of a split).
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ValueError
|
If a timestamp does not suit the axis (a date on numeric timestamps, a number on datetime ones), is NaN or NaT, or is timezone-aware. |
between
¶
between(start: TimeLike | None = None, end: TimeLike | None = None) -> MarketData
Rows from start up to, not including, end (either bound optional).
Each bound is read as by index_of: timestamps select start <= timestamp <
end (between("2020-01-01", "2021-01-01") is the rows of 2020, and on numeric
timestamps between(Time(100), Time(200)) the rows stamped 100 to 199), while
an int is a row position (between(100, 200) is data[100:200]).
with_fields
¶
with_fields(**arrays: ArrayLike) -> MarketData
A copy with fields added or replaced (each (T, N)).
with_exogenous
¶
with_exogenous(**arrays: ArrayLike) -> MarketData
A copy with exogenous series added or replaced (each (T,) or (T, k)).
split
¶
split(*boundaries: TimeLike, embargo: int = 0, history: int = 0) -> list[MarketData]
Split chronologically at the given points.
A point is a fraction of the rows (a float in (0, 1), such as 0.8), a row
position (an int, counted within this data on every time axis, so
test.split(50) cuts test at its own row 50; negative counts from the
end), or a timestamp: on datetime timestamps anything numpy.datetime64
accepts ("2021-01-01"), on any axis Time(t) (as in index_of; a float is
a fraction here, so numeric timestamps need Time).
Every part after the first starts embargo rows after its split point (a
gap that keeps information from straddling the boundary) and then
prepends history rows before that start, which an environment may
observe as lookback without trading on them. The part records them as its
warmup, and the finance environments never make a decision on a warm-up
row, whatever their lookback (a shorter lookback just observes fewer of
them). Pass at least the env's lookback as history so the first decision
of a test episode can fall right at the start of the test period.
walk_forward
¶
walk_forward(train_size: int, test_size: int, *, step: int | None = None, embargo: int = 0, history: int = 0, expanding: bool = False) -> Iterator[tuple[MarketData, MarketData]]
Rolling (or expanding) train/test folds for walk-forward evaluation.
Fold k trains on train_size rows (all rows so far with expanding=True)
and tests on the next test_size rows after an embargo gap, with
history extra rows before the test period available as lookback (recorded
as the test part's warmup, so no decision falls on them). Folds advance by
step rows (default: test_size, so test periods tile the data without
overlap).
Time
dataclass
¶
Time(value: Any)
A timestamp to look up by value, where a plain int would be a row position.
MarketData.index_of, between and split, and reset(options={"start": ...})
in the finance environments, read an int as a row position on every time axis.
Time(t) is always a timestamp: the first row at or after t is used. It is how
to address numeric timestamps that are integers, such as epoch seconds or the
timestamps of a split (which no longer start at 0). Since info["timestamp"]
reports an episode's decision times, options={"start": Time(info["timestamp"])}
replays an episode on any data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
A number on numeric timestamps; on datetime timestamps anything
|
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
Example
Sampling¶
sekai.finance.sampling. See Episode samplers.
EpisodeSampler
¶
Bases: ABC
Chooses the first row of each episode's data window.
sample
abstractmethod
¶
spawn
¶
spawn() -> EpisodeSampler
A sampler for one more independent environment (e.g. another sub-env of a VecEnv).
make_vec() and native vector envs call it once per sub-env. The default returns
this sampler itself, shared, so later changes to it (a curriculum raising a limit,
say) reach every environment. Override it when the sampler keeps per-environment
state, as SequentialStart does with its position. (ProcVecEnv workers always
hold pickled copies, which later changes in the parent cannot reach.)
RandomStart
¶
SequentialStart
¶
Bases: EpisodeSampler
Consecutive windows through the history, for deterministic evaluation.
The first episode starts at start; each later one stride rows on
(default: the episode length, so episodes tile the history without
overlap). Handing out the last window that fits increases epoch and
wraps around to start, so while sampler.epoch == 0: run_episode()
visits every window exactly once. Rows after the last full window are not
used.
spawn
¶
spawn() -> SequentialStart
A fresh copy (same start and stride) with its own position and epoch.
as_sampler
¶
as_sampler(sampler: str | int | EpisodeSampler) -> EpisodeSampler
Normalise a sampler argument: "random", "sequential", a fixed int, or a sampler.
sample_start
¶
sample_start(sampler: EpisodeSampler, rng: Generator, *, n_starts: int, episode_length: int, lookback: int, warmup: int = 0) -> int
A window start from sampler whose decisions all fall after the data's warm-up rows.
The sampler chooses among the valid starts only: its position k is the window
starting at row first_start(lookback, warmup) + k. Without warm-up rows (or
with lookback >= warmup) that is exactly the sampler's own choice.
Raises:
| Type | Description |
|---|---|
ValueError
|
If no window fits after the warm-up rows, or the sampler cannot place an episode (with warm-up rows, the message gives the positions in terms of the windows after them). |
first_start
¶
The first window start whose first decision (row start + lookback) is not a warm-up row.
resolve_start
¶
resolve_start(option: Any, *, timestamps: Any, lookback: int, n_starts: int, warmup: int = 0) -> int
The window start for reset(options={"start": option}).
option places the episode's first decision, read as MarketData.index_of
reads it: an int is a row position on every time axis, and a timestamp puts
the decision on the first row at or after it (on datetime timestamps anything
numpy.datetime64 accepts, on numeric ones a float, on either Time(t)). The
window begins lookback rows earlier. info["timestamp"] reports the decision
time, so start=Time(info["timestamp"]) replays an episode on any data,
including a split whose numeric timestamps no longer start at 0. A first
decision on one of the data's warmup rows (lookback-only history of a split)
is refused.
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ValueError
|
If |
Simulators¶
sekai.finance.simulators. See Market simulators.
MarketModel
¶
Bases: ABC
A generator of synthetic price paths for a fixed universe of n_assets assets.
Subclasses implement simulate, which must be vectorised over paths and assets, return
strictly positive prices wherever an asset is listed and honour the shapes documented on
Simulation.
n_assets
abstractmethod
property
¶
n_assets: int
Number of assets (the size of the last axis of Simulation.prices).
state_spec
¶
Keys of Simulation.state mapped to their per-step trailing shape.
For example {"regime": (), "variance": (n_assets,)}. Empty by default.
simulate
abstractmethod
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Simulate price paths.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rng
|
Generator
|
Source of randomness. |
required |
n_steps
|
int
|
Number of steps (>= 1); the time axis has n_steps + 1 entries. |
required |
n_paths
|
int | None
|
Number of independent paths (>= 1). None gives a single path without a leading paths axis; an int (even 1) adds a leading axis of that size. |
None
|
Returns:
| Type | Description |
|---|---|
Simulation
|
A |
Simulation
|
(n_paths, n_steps + 1, n_assets). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If n_steps or n_paths is smaller than 1. |
TypeError
|
If n_steps or n_paths is not an integer. |
Simulation
dataclass
¶
Simulation(prices: NDArray[float64], mask: NDArray[bool_] | None = None, state: Mapping[str, NDArray[float64]] = dict())
Simulated market paths returned by MarketModel.simulate.
Attributes:
| Name | Type | Description |
|---|---|---|
prices |
NDArray[float64]
|
Prices of shape (n_steps + 1, n_assets), or (n_paths, n_steps + 1, n_assets)
when simulated with |
mask |
NDArray[bool_] | None
|
Boolean array shaped like |
state |
Mapping[str, NDArray[float64]]
|
Latent or auxiliary series keyed by name (see |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the shapes of |
GBM
¶
GBM(mu: ArrayLike = 0.0, sigma: ArrayLike = 0.2, *, s0: ArrayLike = 100.0, corr: ArrayLike | None = None, dt: float = _DEFAULT_DT, n_assets: int | None = None)
Bases: _Model
Geometric Brownian motion with the exact log-normal transition.
log S_{t+1} = log S_t + (mu - sigma^2 / 2) dt + sigma sqrt(dt) z, with z correlated across
assets by corr. Without n_paths it draws random numbers in the same order as
sekai.envs.finance.market.simulate_gbm, so both give identical paths for the same seed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mu
|
ArrayLike
|
Annualised drift, scalar or shape (n_assets,). |
0.0
|
sigma
|
ArrayLike
|
Annualised volatility (>= 0), scalar or shape (n_assets,). |
0.2
|
s0
|
ArrayLike
|
Initial price (> 0), scalar or shape (n_assets,). |
100.0
|
corr
|
ArrayLike | None
|
Optional (n_assets, n_assets) correlation matrix of the assets' shocks. |
None
|
dt
|
float
|
Step length in years. |
_DEFAULT_DT
|
n_assets
|
int | None
|
Number of assets; needed only to broadcast all-scalar parameters to more
than one asset (otherwise inferred from the parameters or |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
On inconsistent shapes or out-of-range parameters. |
simulate
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Simulate GBM paths; see MarketModel.simulate. The state is empty.
Heston
¶
Heston(mu: ArrayLike = 0.05, kappa: ArrayLike = 2.0, theta: ArrayLike = 0.04, xi: ArrayLike = 0.3, rho: ArrayLike = -0.7, *, v0: ArrayLike | None = None, s0: ArrayLike = 100.0, corr: ArrayLike | None = None, dt: float = _DEFAULT_DT, n_assets: int | None = None)
Bases: _Model
Heston stochastic-volatility model, simulated with full-truncation Euler.
With v+ = max(v, 0) at each step:
log S += (mu - v+ / 2) dt + sqrt(v+ dt) z1 and
v += kappa (theta - v+) dt + xi sqrt(v+ dt) z2, where corr(z1, z2) = rho per asset and z1
is correlated across assets by corr.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mu
|
ArrayLike
|
Annualised drift, scalar or shape (n_assets,). |
0.05
|
kappa
|
ArrayLike
|
Mean-reversion speed of the variance (> 0), per year. |
2.0
|
theta
|
ArrayLike
|
Long-run variance (> 0), annualised. |
0.04
|
xi
|
ArrayLike
|
Volatility of variance (> 0). |
0.3
|
rho
|
ArrayLike
|
Correlation between price and variance shocks, in [-1, 1]. |
-0.7
|
v0
|
ArrayLike | None
|
Initial variance (>= 0); defaults to theta. |
None
|
s0
|
ArrayLike
|
Initial price (> 0). |
100.0
|
corr
|
ArrayLike | None
|
Optional (n_assets, n_assets) correlation matrix of the price shocks. |
None
|
dt
|
float
|
Step length in years. |
_DEFAULT_DT
|
n_assets
|
int | None
|
Number of assets when every parameter is a scalar. |
None
|
State
"variance": per-step shape (n_assets,), the truncated variance v+ at each time.
Raises:
| Type | Description |
|---|---|
ValueError
|
On inconsistent shapes or out-of-range parameters. |
simulate
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Simulate Heston paths; see MarketModel.simulate.
MertonJumpDiffusion
¶
MertonJumpDiffusion(mu: ArrayLike = 0.05, sigma: ArrayLike = 0.2, jump_intensity: ArrayLike = 1.0, jump_mean: ArrayLike = -0.05, jump_std: ArrayLike = 0.1, *, s0: ArrayLike = 100.0, corr: ArrayLike | None = None, dt: float = _DEFAULT_DT, n_assets: int | None = None)
Bases: _Model
Merton jump-diffusion: GBM plus compound-Poisson log-normal jumps.
Each step's log increment is (mu - sigma^2 / 2 - lambda k) dt + sigma sqrt(dt) z plus the
sum of N ~ Poisson(lambda dt) iid Normal(jump_mean, jump_std^2) log jumps, where
k = exp(jump_mean + jump_std^2 / 2) - 1 compensates the jumps so that
E[S_t] = s0 exp(mu t). Diffusive shocks are correlated across assets by corr; jumps are
independent across assets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mu
|
ArrayLike
|
Annualised drift (including the jump compensator). |
0.05
|
sigma
|
ArrayLike
|
Annualised diffusive volatility (>= 0). |
0.2
|
jump_intensity
|
ArrayLike
|
Expected number of jumps per year (>= 0). |
1.0
|
jump_mean
|
ArrayLike
|
Mean of a single log jump. |
-0.05
|
jump_std
|
ArrayLike
|
Standard deviation of a single log jump (>= 0). |
0.1
|
s0
|
ArrayLike
|
Initial price (> 0). |
100.0
|
corr
|
ArrayLike | None
|
Optional (n_assets, n_assets) correlation matrix of the diffusive shocks. |
None
|
dt
|
float
|
Step length in years. |
_DEFAULT_DT
|
n_assets
|
int | None
|
Number of assets when every parameter is a scalar. |
None
|
State
"jumps": per-step shape (n_assets,), the number of jumps in the step ending at t (0 at t = 0), as float64.
Raises:
| Type | Description |
|---|---|
ValueError
|
On inconsistent shapes or out-of-range parameters. |
simulate
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Simulate jump-diffusion paths; see MarketModel.simulate.
RegimeSwitching
¶
Bases: _Model
GBM whose drift, volatility and correlation follow a hidden Markov chain of regimes.
The regime at time t governs the increment from t to t + 1. The chain starts from
initial at t = 0 and moves according to transition after every step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
regimes
|
Sequence[GBM]
|
K >= 1 |
required |
transition
|
ArrayLike
|
(K, K) row-stochastic matrix; entry (i, j) is the per-step probability of moving from regime i to regime j. |
required |
initial
|
ArrayLike | None
|
Distribution of the regime at t = 0, shape (K,). Defaults to the stationary
distribution of |
None
|
State
"regime": per-step shape (), the regime index at each time as float64.
Raises:
| Type | Description |
|---|---|
TypeError
|
If a regime is not a |
ValueError
|
On inconsistent regimes or an invalid transition matrix or distribution. |
GARCH
¶
GARCH(omega: ArrayLike = 1e-06, alpha: ArrayLike = 0.08, beta: ArrayLike = 0.9, *, mu: ArrayLike = 0.0, s0: ArrayLike = 100.0, corr: ArrayLike | None = None, dt: float = _DEFAULT_DT, n_assets: int | None = None)
Bases: _Model
GARCH(1,1) volatility clustering on per-step log returns.
eps_t = sqrt(h_t) z_t, log return_t = mu dt + eps_t and
h_{t+1} = omega + alpha eps_t^2 + beta h_t, starting from the unconditional variance
h_0 = omega / (1 - alpha - beta). The z_t are correlated across assets by corr.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
omega
|
ArrayLike
|
Per-step (not annualised) variance intercept (> 0). |
1e-06
|
alpha
|
ArrayLike
|
ARCH coefficient (>= 0). |
0.08
|
beta
|
ArrayLike
|
GARCH coefficient (>= 0); alpha + beta must be < 1. |
0.9
|
mu
|
ArrayLike
|
Annualised drift of the log price. |
0.0
|
s0
|
ArrayLike
|
Initial price (> 0). |
100.0
|
corr
|
ArrayLike | None
|
Optional (n_assets, n_assets) correlation matrix of the shocks z. |
None
|
dt
|
float
|
Step length in years. |
_DEFAULT_DT
|
n_assets
|
int | None
|
Number of assets when every parameter is a scalar. |
None
|
State
"variance": per-step shape (n_assets,), the conditional variance h_t of the increment starting at t.
Raises:
| Type | Description |
|---|---|
ValueError
|
On inconsistent shapes or out-of-range parameters. |
MeanReverting
¶
MeanReverting(theta: ArrayLike = 5.0, mean: ArrayLike = 100.0, sigma: ArrayLike = 0.2, *, s0: ArrayLike = 100.0, corr: ArrayLike | None = None, dt: float = _DEFAULT_DT, n_assets: int | None = None)
Bases: _Model
Exponential Ornstein-Uhlenbeck prices: the log price reverts to log(mean).
With x = log S and m = log(mean), the exact discretisation is
x_{t+1} = m + (x_t - m) e^{-theta dt} + sigma sqrt((1 - e^{-2 theta dt}) / (2 theta)) z,
with z correlated across assets by corr.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
theta
|
ArrayLike
|
Mean-reversion speed (> 0), per year. |
5.0
|
mean
|
ArrayLike
|
Price level the log price reverts to (> 0). |
100.0
|
sigma
|
ArrayLike
|
Annualised volatility of the log price (>= 0). |
0.2
|
s0
|
ArrayLike
|
Initial price (> 0). |
100.0
|
corr
|
ArrayLike | None
|
Optional (n_assets, n_assets) correlation matrix of the shocks. |
None
|
dt
|
float
|
Step length in years. |
_DEFAULT_DT
|
n_assets
|
int | None
|
Number of assets when every parameter is a scalar. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
On inconsistent shapes or out-of-range parameters. |
simulate
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Simulate exponential OU paths; see MarketModel.simulate. The state is empty.
CointegratedPair
¶
CointegratedPair(mu: float = 0.05, sigma: float = 0.2, theta: float = 5.0, spread_sigma: float = 0.1, *, s0: ArrayLike = (100.0, 100.0), dt: float = _DEFAULT_DT)
Bases: _Model
Two cointegrated assets: a shared GBM trend plus a stationary OU spread.
The common log trend x (x_0 = 0) is a Brownian motion with drift (mu - sigma^2 / 2) and volatility sigma; the spread s (s_0 = 0) is a zero-mean OU process discretised exactly. log P1 = log s0[0] + x_t + s_t / 2 and log P2 = log s0[1] + x_t - s_t / 2, so each price wanders while log(P1 / P2) - log(s0[0] / s0[1]) = s_t mean-reverts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mu
|
float
|
Annualised drift of the common trend (scalar). |
0.05
|
sigma
|
float
|
Annualised volatility of the common trend (scalar, >= 0). |
0.2
|
theta
|
float
|
Mean-reversion speed of the spread (scalar, > 0), per year. |
5.0
|
spread_sigma
|
float
|
Annualised volatility of the spread (scalar, >= 0). |
0.1
|
s0
|
ArrayLike
|
Initial prices, a scalar or a length-2 sequence (> 0). |
(100.0, 100.0)
|
dt
|
float
|
Step length in years. |
_DEFAULT_DT
|
State
"spread": per-step shape (), the spread s_t.
Raises:
| Type | Description |
|---|---|
ValueError
|
On non-scalar or out-of-range parameters. |
simulate
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Simulate the pair; see MarketModel.simulate.
BlockBootstrap
¶
BlockBootstrap(returns: ArrayLike, *, block_size: int = 20, s0: ArrayLike = 100.0, dt: float = _DEFAULT_DT)
Bases: _Model
Circular block bootstrap of historical log returns.
Each path concatenates blocks of block_size consecutive rows of returns, each starting
at a uniformly random row and wrapping around circularly, truncated to n_steps rows. Whole
rows are resampled, so cross-asset correlation and short-range dependence are preserved.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Historical per-step log returns, shape (T, n_assets) or (T,) for one asset. |
required |
block_size
|
int
|
Rows per block, 1 <= block_size <= T. |
20
|
s0
|
ArrayLike
|
Initial price (> 0), scalar or shape (n_assets,). |
100.0
|
dt
|
float
|
Step length in years of the historical data. |
_DEFAULT_DT
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If returns are empty or non-finite, or block_size is out of range. |
simulate
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Resample paths; see MarketModel.simulate. The state is empty.
ListingProcess
¶
ListingProcess(model: MarketModel, *, initial_listed: ArrayLike = 0.8, listing_rate: ArrayLike = 1.0, delisting_rate: ArrayLike = 0.25, min_listed: int = 1)
Bases: _Model
A dynamic universe: assets of an inner model list and delist over time.
Each asset follows an independent two-state Markov chain. At t = 0 it is listed with
probability initial_listed; after every step an unlisted asset lists with probability
1 - exp(-listing_rate dt) and a listed asset delists with probability
1 - exp(-delisting_rate dt). Whenever fewer than min_listed assets are listed (also at
t = 0), the lowest-index unlisted assets are listed until min_listed are. In the long run
an asset is listed a fraction p_list / (p_list + p_delist) of the steps, where p_list and
p_delist are the two step probabilities above; this tends to
listing_rate / (listing_rate + delisting_rate) as dt -> 0.
Prices come from the inner model's path; where unlisted they are NaN and mask is False.
If the inner simulation has its own mask, the two are combined with a logical AND
(min_listed applies only to this process's own listing flags). The inner model's state
passes through unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
MarketModel
|
The inner market model. |
required |
initial_listed
|
ArrayLike
|
Probability that an asset is listed at t = 0, in [0, 1] (scalar or shape (n_assets,)). |
0.8
|
listing_rate
|
ArrayLike
|
Listing intensity per year for an unlisted asset (>= 0). |
1.0
|
delisting_rate
|
ArrayLike
|
Delisting intensity per year for a listed asset (>= 0). |
0.25
|
min_listed
|
int
|
Minimum number of listed assets at every time, 0 <= min_listed <= n_assets. |
1
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If model is not a |
ValueError
|
On out-of-range parameters. |
simulate
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Simulate the inner model, then the listing flags; see MarketModel.simulate.
Randomized
¶
Randomized(factory: Callable[[Generator], MarketModel])
Bases: _Model
Domain randomisation: a freshly parameterised model for every simulated path.
factory(rng) builds a model with randomly drawn parameters. The model returned for
np.random.default_rng(0) is kept as reference and fixes n_assets, dt and state_spec;
every later model must match them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factory
|
Callable[[Generator], MarketModel]
|
Callable mapping a generator to a |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
If factory is not callable or does not return a |
ValueError
|
(from |
simulate
¶
simulate(rng: Generator, n_steps: int, *, n_paths: int | None = None) -> Simulation
Simulate one freshly built model per path; see MarketModel.simulate.
Features¶
sekai.finance.features. See Point-in-time features.
Causal (point-in-time) feature transforms for market data, plus a look-ahead detector.
Every transform works along axis 0 (time) of an array shaped (T,) or (T, N) for N assets, treats NaN as missing data (an asset not yet listed, a halted day, ...) and is causal: the output at time t depends only on inputs at times <= t. Features can therefore be computed once over a whole history and sliced inside an environment without leaking the future. Results are float64 arrays of the input's shape unless stated otherwise.
check_causal verifies the causality property empirically for any transform, and
asof_join aligns irregularly timed data (macro releases, earnings) to bar timestamps
without look-ahead.
log_returns
¶
One-period log returns log(P_t / P_{t-1}).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prices
|
ArrayLike
|
Prices shaped (T,) or (T, N). |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Log returns of the same shape. Row 0 is NaN, as is any entry where either price |
NDArray[float64]
|
is missing (non-finite) or not strictly positive. |
simple_returns
¶
momentum
¶
Trailing log return over window periods, log(P_t / P_{t-window}).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prices
|
ArrayLike
|
Prices shaped (T,) or (T, N). |
required |
window
|
int
|
Look-back in periods (>= 1); window=1 equals |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Momentum of the same shape; NaN for t < window or where either price is missing |
NDArray[float64]
|
or not strictly positive. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If window < 1. |
lag
¶
Shift a series down (later in time) by periods rows.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T,) or (T, N). |
required |
periods
|
int
|
Number of rows to shift by (>= 0). |
1
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Array of the same shape whose row t is row t - periods of x; the first |
NDArray[float64]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If periods < 0. |
forward_fill
¶
Carry the last valid (non-NaN) value forward along time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T,) or (T, N). |
required |
limit
|
int | None
|
Maximum number of consecutive NaNs to fill after a valid value (None = unlimited, 0 = no filling). |
None
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Filled array of the same shape. Leading NaNs (before the first valid value) |
NDArray[float64]
|
stay NaN, as do NaNs more than |
Raises:
| Type | Description |
|---|---|
ValueError
|
If limit < 0. |
rolling_mean
¶
Trailing rolling mean over rows t-window+1..t, ignoring NaNs.
Matches pandas rolling(window, min_periods).mean().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T,) or (T, N). |
required |
window
|
int
|
Window length in rows (>= 1). |
required |
min_periods
|
int | None
|
Minimum number of valid values required in the window (1 <= min_periods <= window; default: window). |
None
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Rolling mean of the same shape; NaN where the window holds fewer than |
NDArray[float64]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If window or min_periods is out of range. |
rolling_std
¶
rolling_std(x: ArrayLike, window: int, *, min_periods: int | None = None, ddof: int = 1) -> NDArray[float64]
Trailing rolling standard deviation over rows t-window+1..t, ignoring NaNs.
Matches pandas rolling(window, min_periods).std(ddof).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T,) or (T, N). |
required |
window
|
int
|
Window length in rows (>= 1). |
required |
min_periods
|
int | None
|
Minimum number of valid values required in the window (1 <= min_periods <= window; default: window). |
None
|
ddof
|
int
|
Delta degrees of freedom (>= 0); the divisor is n_valid - ddof. |
1
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Rolling standard deviation of the same shape; NaN where the window holds fewer |
NDArray[float64]
|
than max(min_periods, ddof + 1) valid values. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If window, min_periods or ddof is out of range. |
rolling_zscore
¶
Trailing rolling z-score (x_t - mean) / std over rows t-window+1..t.
The mean and the (ddof=1) standard deviation are those of rolling_mean and
rolling_std over the same window, which includes x_t itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T,) or (T, N). |
required |
window
|
int
|
Window length in rows (>= 1). |
required |
min_periods
|
int | None
|
Minimum number of valid values required in the window (1 <= min_periods <= window; default: window). At least 2 are always needed. |
None
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Z-scores of the same shape: NaN where x_t is NaN or the window holds too few |
NDArray[float64]
|
valid values, and 0.0 where the window's standard deviation is 0. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If window or min_periods is out of range. |
ewm_mean
¶
Exponentially weighted moving average m_t = (1 - a) m_{t-1} + a x_t.
a = 1 - exp(log(0.5) / halflife) and the recursion starts at the first valid value.
Without NaNs this matches pandas ewm(halflife=halflife, adjust=False).mean().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T,) or (T, N). |
required |
halflife
|
float
|
Half-life in rows (> 0). |
required |
min_periods
|
int
|
Number of valid values that must have been seen before a value is emitted (>= 1). |
1
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
EWMA of the same shape. A NaN input leaves the state unchanged and gives NaN at |
NDArray[float64]
|
that t; the output is also NaN until |
Raises:
| Type | Description |
|---|---|
ValueError
|
If halflife <= 0 or min_periods < 1. |
ewm_std
¶
Exponentially weighted moving standard deviation.
On each valid x_t, with d = x_t - m_{t-1}: m_t = m_{t-1} + a d and
v_t = (1 - a) (v_{t-1} + a d^2), starting from m = x, v = 0 at the first valid value;
the output is sqrt(v_t). a is as in ewm_mean.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T,) or (T, N). |
required |
halflife
|
float
|
Half-life in rows (> 0). |
required |
min_periods
|
int
|
Number of valid values that must have been seen before a value is emitted (>= 1). |
2
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
EW standard deviation of the same shape, with the NaN rules of |
Raises:
| Type | Description |
|---|---|
ValueError
|
If halflife <= 0 or min_periods < 1. |
realized_volatility
¶
realized_volatility(returns: ArrayLike, window: int, *, periods_per_year: float | None = None) -> NDArray[float64]
Trailing realised volatility: rolling_std(returns, window) (ddof=1).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Per-period returns shaped (T,) or (T, N). |
required |
window
|
int
|
Window length in rows (>= 1); a full window of valid returns is required. |
required |
periods_per_year
|
float | None
|
If given (> 0), annualise by multiplying by sqrt(periods_per_year), e.g. 252 for daily returns. |
None
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Volatility of the same shape, per period or annualised. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If window < 1 or periods_per_year <= 0. |
cross_sectional_zscore
¶
Z-score each row across assets: (x - mean) / std over the row's valid entries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T, N). |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
(T, N) z-scores using the population (ddof=0) standard deviation. NaN entries |
NDArray[float64]
|
stay NaN; rows with fewer than 2 valid entries are all NaN; rows whose valid |
NDArray[float64]
|
entries are all equal give 0.0. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If x is not 2-D. |
cross_sectional_rank
¶
Rank each row across assets, scaled to [0, 1].
Valid entries get (rank - 1) / (n_valid - 1), where rank is the 1-based average rank (ties share the mean of their ranks).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ArrayLike
|
Data shaped (T, N). |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
(T, N) scaled ranks. NaN entries stay NaN; a row with a single valid entry gives |
NDArray[float64]
|
0.5 for it. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If x is not 2-D. |
asof_join
¶
asof_join(target_times: ArrayLike, event_times: ArrayLike, values: ArrayLike, *, lag: timedelta64 | timedelta | float | None = None) -> NDArray[float64]
Align irregularly timed data to target timestamps without look-ahead.
For each target time t the result holds the value of the last event with
event_time + lag <= t, i.e. the latest information that was public at t. Typical
uses are macro releases or earnings (with lag modelling the publication delay)
aligned to bar timestamps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target_times
|
ArrayLike
|
(T,) target timestamps, sorted ascending. |
required |
event_times
|
ArrayLike
|
(E,) event timestamps, sorted ascending; among equal times the last event wins. Either both time arrays are np.datetime64 or both numeric. |
required |
values
|
ArrayLike
|
(E,) or (E, k) event values. |
required |
lag
|
timedelta64 | timedelta | float | None
|
Non-negative delay before an event becomes known: a np.timedelta64 (or datetime.timedelta) for datetime64 times, a number for numeric times, or None for no delay. |
None
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
float64 array shaped (T,) or (T, k); NaN where no event is known yet. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the time arrays are of mixed or unsupported kinds, or |
ValueError
|
If a time array is not 1-D, contains NaN/NaT or is not sorted, if
|
check_causal
¶
check_causal(fn: Callable[[NDArray[float64]], ArrayLike], x: ArrayLike, *, n_checks: int = 5, rng: Generator | None = None, rtol: float = 0.0, atol: float = 0.0) -> None
Empirically check that a transform has no look-ahead bias.
For cut point 0 and n_checks random cut points c in [1, T-2] (every such point
when n_checks >= T - 2), x is copied with the rows after c perturbed in several ways,
and a causal fn must give the same output, of the same shape, for rows 0..c on
every copy. Cut point 0 is always tested: a leak into the first row only (a
backward fill of the leading NaN of returns, a normalisation by row 1) shows
nowhere else. The perturbations are:
- rescaled: valid entries multiplied by exp(Normal(0, 0.1));
- reordered: the rows after c permuted;
- values changed so that signs and zeros move, within the data's domain: for data with negative values, signs flipped at random plus additive noise, and some entries set to 0; for non-negative data with zeros, |x + noise| with some entries set to 0 (strictly positive data, such as prices, stay positive);
- for data with NaNs, the NaN pattern changed: some valid entries become NaN and the NaNs are filled with values drawn from x (this catches survivorship bias, e.g. dropping assets that delist later).
Perturbed inputs can be outside what fn expects downstream of the cut, so numpy
floating-point warnings are silenced while fn runs on them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn
|
Callable[[NDArray[float64]], ArrayLike]
|
Transform mapping an array shaped like x to an array whose axis 0 is aligned with x's time axis. It must be deterministic. |
required |
x
|
ArrayLike
|
Representative input data shaped (T, ...) with T >= 3. |
required |
n_checks
|
int
|
Number of random cut points to test besides 0 (>= 1). |
5
|
rng
|
Generator | None
|
Source of randomness for the cut points and perturbations (default: np.random.default_rng(0)). |
None
|
rtol
|
float
|
Relative tolerance for the comparison (as in np.allclose). |
0.0
|
atol
|
float
|
Absolute tolerance for the comparison (as in np.allclose). |
0.0
|
Raises:
| Type | Description |
|---|---|
LookAheadError
|
If an output at or before a cut point changed, naming the first time index that differs and the cut point, or if the output's shape changed (e.g. a column per asset that is still listed at the end). |
ValueError
|
If T < 3, n_checks < 1, a tolerance is negative, or fn's output is not aligned with x's time axis. |
Costs¶
sekai.finance.costs. See Cost models.
CostModel
¶
SpreadCost
¶
Bases: CostModel
Crossing half the bid-ask spread on every trade.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
half_spread
|
ArrayLike | None
|
Half-spread as a fraction of the price (scalar or per asset;
finite, >= 0). If None, the env's quoted |
None
|
fallback_spread
|
float | None
|
Full spread (fraction of the price) charged when no asset
has a valid quoted spread. Without it, trading on such a row raises
|
None
|
FixedCost
¶
Bases: CostModel
A fixed fee in currency for every asset traded (a ticket charge).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
float
|
Fee per traded asset, in the same currency as the env's capital (finite, >= 0). |
required |
threshold
|
float
|
Weight changes at or below this size are not counted as trades (finite, >= 0; the default is above float32 rounding, so echoing back observed weights is free). |
1e-06
|
SquareRootImpact
¶
Bases: CostModel
Square-root market impact: coefficient * vol * sqrt(traded / volume) per unit traded.
The empirical "square-root law" of impact (e.g. Almgren et al. 2005; Tóth
et al. 2011): trading a fraction q / V of an asset's volume moves its
price by about coefficient * sigma * sqrt(q / V), and the trade pays
that on its whole size, so the cost grows as |q|^1.5. Large rebalances in
illiquid names become expensive, which a proportional cost cannot express.
Needs equity (currency), volatility (per-step) and volume (traded
value per step, currency) from the environment. The impact per unit traded
is capped at 1 (the whole traded value), which is also what trading an asset
with zero or missing volume costs: there is no liquidity to trade against. A
missing (NaN) volatility, e.g. a name with no return history yet, is replaced
by the cross-sectional median of the other assets; a zero volatility (a flat
window) is a valid estimate and gives zero impact. When no asset has a
volatility, trading raises ValueError unless fallback_volatility is given.
Environments refuse this model with lookback=1, which gives no estimate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coefficient
|
float
|
Impact coefficient (finite, >= 0; order 0.1-1 in empirical studies). |
0.5
|
fallback_volatility
|
float | None
|
Per-step volatility used when no asset has a valid volatility estimate. Without it such trades raise instead of being free. |
None
|
CompositeCost
¶
as_cost_model
¶
A cost model from a CostModel or a proportional rate.
Account¶
sekai.finance.account. See Account rules.
AccountConfig
dataclass
¶
AccountConfig(allow_short: bool = False, max_leverage: float = 1.0, cash_rate: float = 0.0, margin_rate: float | None = None, borrow_rate: float = 0.0)
Constraints and financing terms of a trading account.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allow_short
|
bool
|
Allow negative weights. |
False
|
max_leverage
|
float
|
Cap on gross exposure |
1.0
|
cash_rate
|
float
|
Annual interest earned on positive cash; finite (negative rates are allowed). |
0.0
|
margin_rate
|
float | None
|
Annual interest paid on borrowed cash (default: cash_rate); finite. |
None
|
borrow_rate
|
float
|
Annual fee on the value of short positions; finite and non-negative. |
0.0
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a numeric field is NaN, infinite or out of its range. |
project_weights
¶
project_weights(scores: ArrayLike, tradable: ArrayLike, config: AccountConfig, *, cash_score: ArrayLike | None = None) -> Array
Map raw action values to target risky-asset weights that satisfy the account's rules.
Long-only: scores (and an optional cash_score) are clipped at zero and
normalised into weights summing to at most max_leverage (to exactly
max_leverage when there is no cash score and some score is positive);
all-zero scores mean all cash. Long/short: values are clipped to
[-max_leverage, max_leverage] and scaled down if gross exposure exceeds
max_leverage. Untradable assets get weight 0 in both cases.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scores
|
ArrayLike
|
|
required |
tradable
|
ArrayLike
|
|
required |
config
|
AccountConfig
|
The account rules. |
required |
cash_score
|
ArrayLike | None
|
|
None
|
Returns:
| Type | Description |
|---|---|
Array
|
|
Settlement
dataclass
¶
The outcome of holding weights over one period (arrays broadcast over batch dims).
settle
¶
settle(weights: ArrayLike, returns: ArrayLike, *, cost: ArrayLike, dt: float, config: AccountConfig) -> Settlement
Hold weights (set after paying cost) over a period with asset returns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
ArrayLike
|
|
required |
returns
|
ArrayLike
|
|
required |
cost
|
ArrayLike
|
|
required |
dt
|
float
|
Period length in years (for financing). |
required |
config
|
AccountConfig
|
Account financing terms. |
required |
turnover
¶
sum(|target - current|) over the last axis (cash excluded).
Rewards¶
sekai.finance.rewards. See Reward functions.
StepOutcome
dataclass
¶
StepOutcome(log_return: Any, simple_return: Any, equity: Any, turnover: Any, cost: Any, pnl: Any = None)
What happened to the account over one step.
Fields are floats for a single env, or arrays of shape (num_envs,).
Attributes:
| Name | Type | Description |
|---|---|---|
log_return |
Any
|
Log growth of equity over the step, net of all costs. |
simple_return |
Any
|
|
equity |
Any
|
Equity after the step, relative to the start of the episode. |
turnover |
Any
|
Sum of absolute weight changes traded at the start of the step. |
cost |
Any
|
Trading cost paid, as a fraction of equity. |
pnl |
Any
|
Change in equity over the step, in units of the initial equity (exact, also on a wipe-out), or None if the environment did not supply the equity before the step. |
from_growth
classmethod
¶
from_growth(growth: ArrayLike, *, equity: ArrayLike, turnover: ArrayLike, cost: ArrayLike, previous_equity: ArrayLike | None = None) -> StepOutcome
Build from the equity multiplier of the step (floored, so a wipe-out is finite).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
growth
|
ArrayLike
|
Equity multiplier of the step (0 or below on a wipe-out). |
required |
equity
|
ArrayLike
|
Equity after the step, relative to the start of the episode. |
required |
turnover
|
ArrayLike
|
Sum of absolute weight changes traded. |
required |
cost
|
ArrayLike
|
Trading cost paid, as a fraction of equity. |
required |
previous_equity
|
ArrayLike | None
|
Equity before the step. When given, |
None
|
RewardFunction
¶
LogReturn
¶
SimpleReturn
¶
ProfitAndLoss
¶
Bases: RewardFunction
Change in equity, in units of the initial equity (summed: final equity - 1).
Uses StepOutcome.pnl, which every built-in environment supplies, so the step that
wipes the account out is rewarded with the whole equity it lost. For an outcome
without pnl the change is recovered from the equity after the step, which is only
possible while that equity is positive; a wipe-out then raises ValueError.
MeanVariance
¶
MeanVariance(risk_aversion: float = 1.0)
Bases: RewardFunction
r - (risk_aversion / 2) * r^2 on the log return: a per-step mean-variance utility.
TurnoverPenalty
¶
Bases: RewardFunction
The step's turnover; subtract it to discourage over-trading beyond explicit costs.
DrawdownPenalty
¶
Bases: _Stateful
How much the drawdown deepened this step (0 when equity is at or recovering to a peak).
The drawdown is 1 - equity / running_peak; summed over an episode the
penalty is the total amount by which drawdowns deepened.
DifferentialSharpe
¶
DifferentialSharpe(eta: float = 0.01)
Bases: _Stateful
The differential Sharpe ratio of Moody & Saffell (2001).
An online, per-step reward whose sum approximately maximises the Sharpe
ratio of the step returns: with exponential moving estimates A (mean)
and B (second moment) of the returns,
D_t = (B dA - A dB / 2) / (B - A^2)^(3/2), dA = R_t - A, dB = R_t^2 - B.
It is 0 until the variance estimate becomes positive.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
eta
|
float
|
Adaptation rate of the moving estimates (about 1 / window length). |
0.01
|
Metrics¶
sekai.finance.metrics. See Performance metrics.
Trading performance metrics, and a wrapper that reports them per episode.
The metric functions take a 1-D series of simple per-period returns (0.01
is +1 % over the period), check that it is non-empty and finite (raising
ValueError otherwise) and return plain Python floats. Annualisation uses
periods_per_year: 252 for daily bars, 52 for weekly, 12 for monthly,
252 * 390 for one-minute bars of a US equity session.
Wipe-outs follow a limited-liability convention, as the finance envs do:
equity cannot fall below zero. A return of -100 % or worse wipes the account
out and equity stays at zero from then on, so total_return is at least -1,
drawdowns lie in [0, 1] and annualized_return is -1. Dispersion and tail
statistics (volatility, Sharpe, Sortino, VaR, CVaR, hit rate) use the returns
exactly as given.
Returns are undefined for P&L processes that start from zero wealth (e.g. a
market maker's mark-to-market P&L); summarise those with pnl_summary, which
works on per-period P&L increments in absolute units.
RecordPerformance wraps an env whose info reports account equity (or
cumulative P&L) and attaches a PerformanceSummary (or PnLSummary) to the
info of each episode's final step.
PerformanceSummary
dataclass
¶
PerformanceSummary(n_periods: int, total_return: float, annualized_return: float, annualized_volatility: float, sharpe_ratio: float, sortino_ratio: float, max_drawdown: float, calmar_ratio: float, value_at_risk: float, conditional_value_at_risk: float, hit_rate: float, mean_turnover: float | None = None, total_cost: float | None = None)
Performance metrics of one return series (e.g. one episode).
Return, volatility, drawdown and VaR fields are fractions (0.05 is 5 %); ratios are annualised. See the module functions of the same names for the exact definitions.
Attributes:
| Name | Type | Description |
|---|---|---|
n_periods |
int
|
Number of return periods. |
total_return |
float
|
Compounded simple return over the series. |
annualized_return |
float
|
Geometric annualised return. |
annualized_volatility |
float
|
Annualised sample standard deviation of returns. |
sharpe_ratio |
float
|
Annualised Sharpe ratio. |
sortino_ratio |
float
|
Annualised Sortino ratio (may be |
max_drawdown |
float
|
Maximum drawdown, in [0, 1]. |
calmar_ratio |
float
|
Annualised return over maximum drawdown (may be |
value_at_risk |
float
|
Historical per-period VaR as a positive loss. |
conditional_value_at_risk |
float
|
Historical per-period expected shortfall. |
hit_rate |
float
|
Fraction of non-zero periods with a positive return. |
mean_turnover |
float | None
|
Mean per-period turnover, if turnover was supplied. |
total_cost |
float | None
|
Sum of per-period trading costs, if costs were supplied. |
PnLSummary
dataclass
¶
PnLSummary(n_periods: int, total_pnl: float, mean_pnl: float, pnl_volatility: float, sharpe_ratio: float, max_drawdown: float, hit_rate: float)
Performance of a P&L process measured in absolute units (no returns).
Attributes:
| Name | Type | Description |
|---|---|---|
n_periods |
int
|
Number of periods. |
total_pnl |
float
|
Sum of per-period P&L. |
mean_pnl |
float
|
Mean per-period P&L. |
pnl_volatility |
float
|
Sample standard deviation of per-period P&L (ddof=1); 0.0 when n < 2. |
sharpe_ratio |
float
|
|
max_drawdown |
float
|
Largest fall of cumulative P&L from its running peak, in absolute units (>= 0); the running peak starts at 0. |
hit_rate |
float
|
Fraction of non-zero periods with positive P&L. |
RecordPerformance
¶
RecordPerformance(env: Env[ObsType, ActType], *, periods_per_year: float = 252, equity_key: str = 'equity', pnl_key: str | None = None, turnover_key: str | None = 'turnover', cost_key: str | None = 'cost', risk_free: float = 0.0, deque_size: int = 100)
Bases: Wrapper[ObsType, ActType, ObsType, ActType]
Reports trading performance metrics at the end of every episode.
Equity mode (default, pnl_key None) reads account equity from
info[equity_key] on every reset and step. Each step's simple return is
equity_t / equity_{t-1} - 1, where the previous equity is the last
step's or, on the first step, the reset info's. If the reset info has no
equity_key, the starting equity is assumed to be 1.0. A step that takes
equity to zero or below is a wipe-out: its return is -1 (-100 %) and the
series ends there, i.e. every later return in the episode is 0.
P&L mode (pnl_key given) reads cumulative wealth or P&L in absolute
units from info[pnl_key]; it may start at zero or be negative. Each
step's P&L is the change since the previous value (from the reset info,
else 0.0), and episodes are summarised with pnl_summary, with the
episode's largest absolute value as the rounding scale (a P&L that is
constant up to the rounding of the wealth level has zero volatility).
In equity mode, info[turnover_key] and info[cost_key] are collected
from the steps that report them and summarised as the mean turnover and the
total cost (None if no step reported them). P&L mode ignores them.
On the final step of an episode, the summary is attached to that step's
info as info["performance"] (in a new dict; the inner info is never
modified), appended to summaries and exposed as last_summary, and a new
episode starts. Around an inner AutoReset, the terminal value is read
from info["final_info"] and the next episode's starting value from
info["reset_info"], so back-to-back episodes are summarised correctly
without reset() reaching this wrapper. A reset() mid-episode discards
the unfinished episode.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
env
|
Env[ObsType, ActType]
|
Environment whose info reports equity (or cumulative P&L). |
required |
periods_per_year
|
float
|
Steps per year, for annualisation. |
252
|
equity_key
|
str
|
Info key holding account equity (equity mode). |
'equity'
|
pnl_key
|
str | None
|
Info key holding cumulative P&L; selects P&L mode when given. |
None
|
turnover_key
|
str | None
|
Info key holding per-step turnover, or None to ignore. |
'turnover'
|
cost_key
|
str | None
|
Info key holding per-step trading cost, or None to ignore. |
'cost'
|
risk_free
|
float
|
Annual simple risk-free rate for the Sharpe and Sortino ratios. |
0.0
|
deque_size
|
int
|
Number of recent episode summaries kept in |
100
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a numeric argument is out of range. |
TypeError
|
If a key argument is not a string (or None where allowed). |
total_return
¶
Compounded return over the whole series, prod(1 + r) - 1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
Returns:
| Type | Description |
|---|---|
float
|
Total simple return; -1.0 after a wipe-out (never lower). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
annualized_return
¶
Geometric annualised return, prod(1 + r) ** (periods_per_year / n) - 1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
periods_per_year
|
float
|
Number of return periods in a year. |
252
|
Returns:
| Type | Description |
|---|---|
float
|
Compound annual growth rate; -1.0 if equity ever reaches zero or below. |
float
|
May be |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
annualized_volatility
¶
Annualised volatility, std(r, ddof=1) * sqrt(periods_per_year).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
periods_per_year
|
float
|
Number of return periods in a year. |
252
|
Returns:
| Type | Description |
|---|---|
float
|
Annualised standard deviation of returns; 0.0 when n < 2 or the returns are |
float
|
constant up to floating-point rounding. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
sharpe_ratio
¶
Annualised Sharpe ratio of returns in excess of a risk-free rate.
mean(e) / std(e, ddof=1) * sqrt(periods_per_year) with
e = r - risk_free / periods_per_year.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
periods_per_year
|
float
|
Number of return periods in a year. |
252
|
risk_free
|
float
|
Annual simple risk-free rate (e.g. 0.04 for 4 %). |
0.0
|
Returns:
| Type | Description |
|---|---|
float
|
The Sharpe ratio; 0.0 when n < 2 or the excess returns are constant |
float
|
(zero standard deviation, up to floating-point rounding). Excess returns |
float
|
within rounding of zero count as exactly zero. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
sortino_ratio
¶
Annualised Sortino ratio: mean excess return over downside deviation.
With e = r - target / periods_per_year, the downside deviation is
sqrt(mean(min(e, 0) ** 2)) over all periods and the ratio is
mean(e) / dd * sqrt(periods_per_year).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
periods_per_year
|
float
|
Number of return periods in a year. |
252
|
target
|
float
|
Annual minimum acceptable return (simple rate). |
0.0
|
Returns:
| Type | Description |
|---|---|
float
|
The Sortino ratio. With no period below target, |
float
|
excess return is positive, else 0.0. Excess returns within floating-point |
float
|
rounding of zero count as exactly zero, so a series that earns exactly the |
float
|
target (e.g. cash at the risk-free rate) gives 0.0. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
drawdown_series
¶
Drawdown from the running peak after each period.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
|
NDArray[float64]
|
shape (n + 1,), values in [0, 1] (1 means wiped out). The first value |
NDArray[float64]
|
is always 0. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
max_drawdown
¶
Maximum drawdown as a positive fraction of the running peak.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
Returns:
| Type | Description |
|---|---|
float
|
The largest value of |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
calmar_ratio
¶
Calmar ratio: annualised return over maximum drawdown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
periods_per_year
|
float
|
Number of return periods in a year. |
252
|
Returns:
| Type | Description |
|---|---|
float
|
|
float
|
the annualised return is positive, else 0.0. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
value_at_risk
¶
Historical value at risk, reported as a positive loss.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
level
|
float
|
Confidence level, strictly between 0 and 1. |
0.95
|
Returns:
| Type | Description |
|---|---|
float
|
|
float
|
statistics): the per-period loss not exceeded with probability |
float
|
Negative if even the tail quantile is a gain. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
conditional_value_at_risk
¶
Historical expected shortfall (CVaR), reported as a positive loss.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
level
|
float
|
Confidence level, strictly between 0 and 1. |
0.95
|
Returns:
| Type | Description |
|---|---|
float
|
Minus the mean of the returns at or below |
float
|
Always at least |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
hit_rate
¶
Fraction of active (non-zero) periods with a positive return.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns (or P&L increments), shape (n,). |
required |
Returns:
| Type | Description |
|---|---|
float
|
Winning periods over non-zero periods, in [0, 1]; 0.0 if every period |
float
|
is zero. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
equity_curve
¶
Equity path implied by compounding simple returns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
initial
|
float
|
Starting equity (positive, any currency unit). |
1.0
|
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Equity, shape (n + 1,): |
NDArray[float64]
|
Once equity reaches zero or below (a return of -100 % or worse) it stays |
NDArray[float64]
|
at zero. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
returns_from_equity
¶
Simple returns between consecutive equity values (the inverse of equity_curve).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
equity
|
ArrayLike
|
Equity path, shape (n + 1,) with n >= 1, starting positive. The
first value at or below zero is a wipe-out, and every value after it
must be 0 (equity stays at zero, as |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Simple returns |
NDArray[float64]
|
gives a return of exactly -1 (-100 %) and the periods after it 0, as |
NDArray[float64]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
performance_summary
¶
performance_summary(returns: ArrayLike, periods_per_year: float = 252, *, risk_free: float = 0.0, level: float = 0.95, turnover: ArrayLike | None = None, costs: ArrayLike | None = None) -> PerformanceSummary
Compute every return-series metric at once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
ArrayLike
|
Simple per-period returns, shape (n,). |
required |
periods_per_year
|
float
|
Number of return periods in a year. |
252
|
risk_free
|
float
|
Annual simple risk-free rate; the hurdle for both the Sharpe and the Sortino ratio. |
0.0
|
level
|
float
|
Confidence level for VaR and CVaR, strictly between 0 and 1. |
0.95
|
turnover
|
ArrayLike | None
|
Optional per-period turnover (e.g. traded notional as a fraction of equity), shape (m,). It need not cover every period. |
None
|
costs
|
ArrayLike | None
|
Optional per-period trading costs, shape (k,), in the units the env reports them (typically a fraction of equity). |
None
|
Returns:
| Type | Description |
|---|---|
PerformanceSummary
|
A |
PerformanceSummary
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If any series is empty, not 1-D or not finite, or a parameter is invalid. |
pnl_summary
¶
pnl_summary(pnl: ArrayLike, periods_per_year: float = 252, *, scale: float = 0.0) -> PnLSummary
Summarise a series of per-period P&L increments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pnl
|
ArrayLike
|
Per-period P&L increments in absolute units, shape (n,). |
required |
periods_per_year
|
float
|
Number of periods in a year (annualises the Sharpe ratio). |
252
|
scale
|
float
|
Size of the cumulative wealth or P&L that the increments are
differences of, such as its largest absolute value. A difference of
values near |
0.0
|
Returns:
| Type | Description |
|---|---|
PnLSummary
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Universe¶
sekai.finance.universe. See Slots and dynamic universes.
SlotMap
¶
SlotMap(max_slots: int)
Assigns up to max_slots instruments to stable slot indices.
Example
update
¶
Set the current universe; return each present instrument's slot, in order.
Instruments that are no longer present free their slots; new ones take
the lowest free slots. changed marks slots whose owner differs from
before the call (freed or newly assigned), e.g. to reset per-slot state.
Raises:
| Type | Description |
|---|---|
ValueError
|
If more instruments are present than there are slots. |
Order book¶
sekai.finance.lob. See Order books.
OrderBook
¶
A price-time priority limit order book for one instrument, in integer price ticks.
Limit orders match against the opposite side while the prices cross and rest any
remainder; market orders walk the opposite side and drop any unfilled remainder.
Executions always happen at the resting order's price. Self-trades are allowed. Every
accepted order, including one that fills completely on arrival, is assigned a new
order id, increasing in arrival order (ids restart at 1 after clear).
Complexity: inserting or removing a price level is O(log L) search on a sorted list of L prices; cancelling or reducing an order is O(1); matching is O(1) per fill.
Attributes:
| Name | Type | Description |
|---|---|---|
time |
float
|
Current book time. A plain attribute: the caller (or the background flow) advances it, and it stamps accepted orders and fills. |
last_price |
int | None
|
Price of the most recent fill, or a reference price set by the
caller ( |
limit
¶
limit(side: Side, price: int, quantity: int, owner: int = BACKGROUND) -> tuple[int | None, list[Fill]]
Submit a limit order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
side
|
Side
|
|
required |
price
|
int
|
Limit price in ticks, an integer >= 1. |
required |
quantity
|
int
|
Quantity, an integer >= 1. |
required |
owner
|
int
|
Owner id; defaults to |
BACKGROUND
|
Returns:
| Type | Description |
|---|---|
int | None
|
|
list[Fill]
|
filled completely on arrival (its id still appears in |
tuple[int | None, list[Fill]]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
market
¶
Submit a market order: walk the opposite side and drop any unfilled remainder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
side
|
Side
|
|
required |
quantity
|
int
|
Quantity, an integer >= 1. |
required |
owner
|
int
|
Owner id; defaults to |
BACKGROUND
|
Returns:
| Type | Description |
|---|---|
int
|
|
list[Fill]
|
(empty if the opposite side is empty). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
cancel
¶
reduce
¶
Reduce a resting order's remaining quantity, keeping its time priority.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
order_id
|
int
|
Id returned by |
required |
quantity
|
int
|
New remaining quantity, an integer smaller than the current one; 0 cancels the order. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the order was resting and has been reduced (or cancelled); False if |
bool
|
the id is unknown or the order has already left the book. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
clear
¶
Remove every resting order and return the book to its freshly constructed state.
Resets time to 0, last_price to None and the order-id counter to 1.
get
¶
The resting order with this id (a live record: do not mutate it), or None.
best_bid
¶
best_bid() -> int | None
Highest resting bid price in ticks, or None if the bid side is empty.
best_ask
¶
best_ask() -> int | None
Lowest resting ask price in ticks, or None if the ask side is empty.
mid
¶
mid() -> float | None
(best_bid + best_ask) / 2 in ticks, or None unless both sides are quoted.
volume_at
¶
Total resting quantity on side at price (0 if there is no such level).
depth
¶
Aggregated depth of the best levels price levels on each side.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
levels
|
int
|
Number of levels per side, an integer >= 0. |
required |
Returns:
| Type | Description |
|---|---|
NDArray[int64]
|
|
NDArray[int64]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
orders_of
¶
Resting orders of owner, oldest first (live records: do not mutate them).
queue_ahead
¶
Total resting quantity ahead of an order in its price level's queue.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
order_id
|
int
|
Id of a resting order. |
required |
Returns:
| Type | Description |
|---|---|
int
|
The quantity that must trade at the order's price before it starts to fill. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If the order is not resting in the book. |
Side
¶
Order
dataclass
¶
A resting limit order.
The objects returned by OrderBook.get and OrderBook.orders_of are the book's live
internal records: read them, but never mutate them (use OrderBook.cancel and
OrderBook.reduce). Once an order leaves the book, by a complete fill, a cancellation
or OrderBook.clear, its quantity is 0.
Attributes:
| Name | Type | Description |
|---|---|---|
order_id |
int
|
Unique identifier assigned by the book, increasing in arrival order. |
side |
Side
|
|
price |
int
|
Limit price in integer ticks, >= 1. |
quantity |
int
|
Remaining quantity; > 0 while the order rests. |
owner |
int
|
Owner id: |
time |
float
|
Book time at which the order was accepted. |
Fill
dataclass
¶
Fill(price: int, quantity: int, maker_order_id: int, taker_order_id: int, maker_owner: int, taker_owner: int, taker_side: Side, time: float)
One execution between a resting (maker) order and an incoming (taker) order.
Attributes:
| Name | Type | Description |
|---|---|---|
price |
int
|
Execution price in ticks: the maker order's limit price. |
quantity |
int
|
Executed quantity, >= 1. |
maker_order_id |
int
|
Id of the resting order. |
taker_order_id |
int
|
Id of the incoming order. |
maker_owner |
int
|
Owner of the resting order. |
taker_owner |
int
|
Owner of the incoming order. |
taker_side |
Side
|
Side of the incoming order ( |
time |
float
|
Book time of the execution. |
BACKGROUND
module-attribute
¶
BACKGROUND: int = -1
Owner id of orders submitted by background flow (e.g. ZeroIntelligenceFlow).
ZeroIntelligenceFlow
dataclass
¶
ZeroIntelligenceFlow(limit_rate: float = 10.0, market_rate: float = 2.0, cancel_rate: float = 0.5, max_offset: int = 10, offset_decay: float = 0.5, mean_size: float = 3.0)
Poisson background order flow for an OrderBook.
In the spirit of Smith, Farmer, Gillemot & Krishnamurthy (2003) and Cont, Stoikov &
Talreja (2010): limit orders at random distances from the opposite best quote, market
orders, and cancellations of resting background orders, each arriving as an
independent Poisson process. All orders are submitted with owner BACKGROUND.
- Limit orders arrive at
limit_rateper side. A buy is placedkticks below the best ask and a sellkticks above the best bid, withkin1..max_offsetandP(k)proportional toexp(-offset_decay * (k - 1)), so a limit order never crosses on arrival (except where prices are clipped at 1 tick). If the opposite side is empty the reference is one tick beyond the same side's best quote, orbook.last_priceif the book is empty. - Market orders arrive at
market_rateper side and take the opposite side; an order that finds the opposite side empty is skipped. - Cancellations remove a uniformly random resting background order, at
cancel_rateper resting background order. Orders of other owners (agents) are never cancelled. - Sizes are
1 + Poisson(mean_size - 1), so their mean ismean_size.
If an event leaves one side of the book empty, a background limit order is placed on that side at once, so the book stays two-sided.
Volatility is governed mostly by cancel_rate relative to limit_rate. With the
defaults the book holds about 30 resting orders, the spread is about one tick and
the mid diffuses by roughly 0.5 ticks per unit time; cancel_rate=1.0 gives a
thinner book and about 1.3 ticks, while a low rate such as 0.1 lets the queues at
the best quotes grow so long that the mid barely moves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
limit_rate
|
float
|
Limit orders per unit time, per side, > 0. |
10.0
|
market_rate
|
float
|
Market orders per unit time, per side, > 0. |
2.0
|
cancel_rate
|
float
|
Cancellations per resting background order per unit time, >= 0. |
0.5
|
max_offset
|
int
|
Largest limit-order distance from the opposite best quote in ticks, >= 1. |
10
|
offset_decay
|
float
|
Decay rate of the offset distribution per tick, >= 0 (0 is uniform). |
0.5
|
mean_size
|
float
|
Mean order size, >= 1. |
3.0
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a parameter is out of range. |
initialise
¶
initialise(book: OrderBook, rng: Generator, *, mid: int, levels: int = 10, orders_per_level: int = 3) -> None
Clear book and seed it with a symmetric two-sided background book.
Bids rest at mid - 1, ..., mid - levels and asks at mid + 1, ..., mid + levels
(prices clipped to >= 1 tick), each level holding orders_per_level background
orders of random size. The book's time is reset to 0 and book.last_price is set
to mid as the reference price.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
book
|
OrderBook
|
The book to (re)initialise. |
required |
rng
|
Generator
|
Source of randomness. |
required |
mid
|
int
|
Initial mid price in ticks, an integer >= 1. |
required |
levels
|
int
|
Price levels per side, an integer >= 1. |
10
|
orders_per_level
|
int
|
Orders per price level, an integer >= 1. |
3
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
advance
¶
Simulate background events from book.time up to time until.
Events arrive as competing Poisson clocks with total rate
2 * limit_rate + 2 * market_rate + cancel_rate * n, where n is the number of
resting background orders, recomputed after each event. book.time is set to
each event's time as it happens and to until at the end.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
book
|
OrderBook
|
The book to drive; it may also hold other owners' (agents') orders. |
required |
rng
|
Generator
|
Source of randomness. |
required |
until
|
float
|
End time, finite and >= |
required |
Returns:
| Type | Description |
|---|---|
list[Fill]
|
Every fill that occurred, in order, including fills against non-background |
list[Fill]
|
orders. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Rendering¶
sekai.finance.rendering: charts for dashboards
of market environments. The classes are also exported from sekai.finance.
PriceChart
¶
PriceChart(price: Source, *, position: Source | None = None, quotes: tuple[Source, Source] | None = None, spread: tuple[Source, Source] | None = None, buys: Source | None = None, sells: Source | None = None, context: Source | None = None, reference: float | Source | None = None, reference_label: str | None = None, title: str | None = 'Price', tag: bool = True, min_trade: float = 1e-06, width: float = 1.0, height: float = 1.0)
Bases: Panel
A price over time, with the agent's position, trades and quotes.
Every argument after price is optional:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
price
|
Source
|
The price per step (a mid price, for market makers). |
required |
position
|
Source | None
|
The position held over the step that just ended, signed (long > 0,
short < 0): the background is shaded in the |
None
|
quotes
|
tuple[Source, Source] | None
|
|
None
|
spread
|
tuple[Source, Source] | None
|
|
None
|
buys
|
Source | None
|
Prices at which the agent bought during the step that just ended (a number, a sequence of numbers, or None). |
None
|
sells
|
Source | None
|
Likewise for sales. |
None
|
context
|
Source | None
|
The prices before the episode, ending with the price at its start (e.g. a lookback window), read once per episode and drawn muted. |
None
|
reference
|
float | Source | None
|
A price level drawn as a dashed line (an arrival or entry price, a strike): a number or a source. |
None
|
reference_label
|
str | None
|
Legend label for the reference level. |
None
|
title
|
str | None
|
Panel title. |
'Price'
|
tag
|
bool
|
Show the latest price in a tag on the y-axis. |
True
|
min_trade
|
float
|
The smallest change in |
1e-06
|
width
|
float
|
Relative width in its row. |
1.0
|
height
|
float
|
Relative height in its column. |
1.0
|
OrderBookChart
¶
OrderBookChart(book: Source, *, owners: Mapping[int, tuple[str, ColorSpec]] | Source | None = None, levels: int = 8, title: str | None = 'Order book', width: float = 1.0, height: float = 1.0)
Bases: Panel
A limit order book as a depth ladder around the mid price.
Asks are above the mid and bids below, one row per price tick, each with a bar for the resting volume. The orders of highlighted owners are drawn inside the bars at their place in the queue (the volume ahead of them on the left), so you see how close an order is to being filled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
book
|
Source
|
A source of the |
required |
owners
|
Mapping[int, tuple[str, ColorSpec]] | Source | None
|
Owners whose orders to highlight: |
None
|
levels
|
int
|
Price ticks shown on each side of the mid. |
8
|
title
|
str | None
|
Panel title. |
'Order book'
|
width
|
float
|
Relative width in its row. |
1.0
|
height
|
float
|
Relative height in its column. |
1.0
|
UniverseChart
¶
UniverseChart(weights: Source, *, available: Source | None = None, labels: Sequence[str] | Source | None = None, color: ColorSpec = 'accent', negative_color: ColorSpec = 'down', title: str | None = 'Universe', width: float = 1.0, height: float = 1.0)
Bases: Panel
A changing universe over time: one row per slot, one column per step.
A cell is filled with the slot's colour while its asset is held (deeper for a larger weight), drawn in the grid colour while the asset is tradable but not held, and left empty while the slot has no tradable asset, so listings, delistings and rotations show as the rows fill and empty.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
Source
|
A source of the weight of each slot. |
required |
available
|
Source | None
|
A source of whether each slot is tradable now. |
None
|
labels
|
Sequence[str] | Source | None
|
Slot labels (asset names), a sequence or a source; shown in the gutter. |
None
|
color
|
ColorSpec
|
The colour of held cells (theme role, hex, RGB or slot). |
'accent'
|
negative_color
|
ColorSpec
|
The colour of cells held short. |
'down'
|
title
|
str | None
|
Panel title. |
'Universe'
|
width
|
float
|
Relative width in its row. |
1.0
|
height
|
float
|
Relative height in its column. |
1.0
|