Skip to content

Modelling assumptions

What a backtest takes as given about markets and data, and the process-wide default. See Backtest.

assumptions

What a backtest takes as given about markets and data, in one object.

from beacon import ModellingAssumptions, use_modelling_assumptions

use_modelling_assumptions(ModellingAssumptions(fx_policy="EXACT_DAY"))

Backtest(initial_capital=1e6,
         modelling_assumptions=ModellingAssumptions(cash_rate=0.02))

Two kinds of assumption

Data treatment decides how data is read: the FX policy on a day a pair printed no rate, how long a name may go without trading before it is stale, and how far a free float carries over blank cells. The index calculation reads data too, so these reach it as well, and an index and the backtest tracking it never assume different things.

Simulation conventions decide how a backtest is valued and measured: what cash earns, the risk-free rate the Sharpe ratio is measured against, how many periods make a year when returns are annualised, the share of each dividend withheld, and how far a day's traded volume carries over blank cells when an execution limit needs it. They do not affect an index.

Unset fields, and where their values come from

Every field defaults to None, meaning "not set here". A backtest's own assumptions are laid over the process-wide default field by field, so passing only cash_rate keeps the default's FX policy. A data-treatment field still unset after that takes the data source's own setting, and a simulation field takes the library default. resolved produces the fully specified result, and that is what a run records.

ModellingAssumptions dataclass

ModellingAssumptions(
    fx_policy: str | None = None,
    max_price_staleness_days: int | None = None,
    free_float_backfill_days: int | None = None,
    cash_rate: float | None = None,
    risk_free_rate: float | None = None,
    periods_per_year: int | None = None,
    withholding_tax_rate: float | None = None,
    volume_backfill_days: int | None = None,
)

A backtest's modelling assumptions. Every field is optional.

Parameters:

Name Type Description Default
fx_policy str | None

How an FX rate is read on a day the pair printed none: "CARRY_FORWARD" uses the last rate published, "EXACT_DAY" only that day's. Unset takes the data source's.

None
max_price_staleness_days int | None

How many calendar days a name may go without trading before it is dropped as stale. 0 keeps every name however long ago it traded. Unset takes the data source's.

None
free_float_backfill_days int | None

How many calendar days a reported free float carries forward over blank cells. 0 turns carrying off. Unset takes the data source's.

None
cash_rate float | None

The annual rate cash earns, accrued daily over calendar days (ACT/365). Unset is 0.

None
risk_free_rate float | None

The annual rate the Sharpe ratio is measured against. Unset is 0.

None
periods_per_year int | None

How many periods make a year when returns are annualised. Unset is 252.

None
withholding_tax_rate float | None

The share of each dividend withheld before the book receives it, as a decimal. Unset is 0.

None
volume_backfill_days int | None

How many calendar days a name's last reported volume stands in for a blank one when an execution limit reads the day's volume. Past that, its average daily volume is used. A volume reported as 0 is never replaced. Unset is 5.

None

Raises:

Type Description
ValueError

If a field is set to a value it cannot take.

over

over(base: ModellingAssumptions) -> ModellingAssumptions

These assumptions, with base's filling every field unset here.

resolved

resolved(fetcher: DataFetcher) -> ModellingAssumptions

Every field set: unset data treatment from fetcher, the rest from the library defaults.

with_defaults

with_defaults() -> ModellingAssumptions

The simulation conventions filled from the library defaults where unset; the data treatment left as it is.

effective

effective() -> ModellingAssumptions

These assumptions laid over the process-wide default.

applied_to

applied_to(fetcher: DataFetcher) -> DataFetcher

fetcher, reading data under these assumptions' data treatment.

The same fetcher when nothing set here differs from its own settings, so a run with no assumptions shares its data source's caches.

data_treatment

data_treatment() -> dict[str, Any]

The fields that reach an index calculation, by name.

as_dict

as_dict() -> dict[str, Any]

Every field, by name: what a result records.

data_treatment_of

data_treatment_of(
    fetcher: Any,
) -> ModellingAssumptions | None

The data treatment fetcher reads under, as assumptions with only those fields set. None for a data source that is not a DataFetcher.

apply

apply(
    assumptions: ModellingAssumptions, fetcher: Any
) -> Any

fetcher under assumptions' data treatment, when it is a DataFetcher; any other data source (a test double) unchanged.

use_modelling_assumptions

use_modelling_assumptions(
    assumptions: ModellingAssumptions | None,
) -> None

Set the process-wide modelling assumptions, or reset them with None.

Every backtest and index calculation that is not given its own reads these. A backtest's own assumptions are laid over them field by field.

current_modelling_assumptions

current_modelling_assumptions() -> ModellingAssumptions

The process-wide modelling assumptions.