Ledger

Defined in fynance.research

class Ledger(root)[source]

Bases: object

A persistent, append-only store of experiments under root.

Parameters:
rootstr or pathlib.Path

Directory the experiments live under (created on demand). Each experiment is stored at <root>/<name>/experiment.json.

Examples

>>> import tempfile
>>> from fynance.research import Experiment, Ledger
>>> d = tempfile.mkdtemp()
>>> led = Ledger(d)
>>> _ = led.append(Experiment(name="a", metrics={"sharpe": 1.0}))
>>> _ = led.append(Experiment(name="b", metrics={"sharpe": 2.0}))
>>> led.n_trials
2
>>> [r["name"] for r in led.leaderboard()]
['b', 'a']
append(experiment)[source]

Persist experiment under the ledger root; return its json path.

The store is append-only: appending an experiment whose name already exists raises FileExistsError rather than silently overwriting the prior run. Overwriting would undercount n_trials and so deflate the multiple-testing correction fed to the deflated Sharpe ratio. Pick a unique name (e.g. version-suffix a re-run) before appending.

Parameters:
experimentExperiment

The experiment to persist.

Returns:
pathlib.Path

Path to the written experiment.json.

Raises:
FileExistsError

If an experiment with the same name is already stored.

deflated_sharpe(experiment, metric='sharpe')[source]

Deflated Sharpe of experiment against the ledger’s trial count.

Uses the ledger’s n_trials as the number of trials and the dispersion of the stored Sharpe metrics as the trial variance, so a selected strategy is judged against the multiple testing it came from.

The stored sharpe metric is annualized (by the period used at run time, recorded in spec), whereas deflated_sharpe_ratio expects a per-observation Sharpe (it scales by sqrt(n_obs - 1) internally). This method therefore de-annualizes both the selected strategy’s Sharpe and the across-trial variance before the call: sr_obs = sr_annual / sqrt(period) and var_obs = var_annual / period. Skipping this de-annualization saturates the DSR to ~1 (a modest per-period edge looks certain), defeating the guard.

Parameters:
experimentExperiment

The selected experiment to deflate.

metricstr

Metric key holding the (annualized) Sharpe (default "sharpe").

Returns:
float

Deflated Sharpe ratio in [0, 1].

leaderboard(*, sort_by='sharpe', descending=True)[source]

Rank the stored experiments (see fynance.research.leaderboard).

load()[source]

Load every stored experiment (sorted by name for determinism).

property n_trials

Number of experiments in the ledger (the multiple-testing count).