Run an end-to-end AFML-style research pipeline. Returns nested dictionaries with stage outputs: events, signals, portfolio, risk, backtest, leakage_checks.
(
timestamps: Sequence[str],
close: Sequence[float],
model_probabilities: Sequence[float],
asset_prices: Sequence[Sequence[float]],
model_sides: Sequence[float] | None = None,
asset_names: Sequence[str] | None = None,
cusum_threshold: float = 0.001,
num_classes: int = 2,
step_size: float = 0.1,
risk_free_rate: float = 0.0,
confidence_level: float = 0.05,
)
| 9 | |
| 10 | #: Trading days (sessions) a year: the annualisation factor for daily bars. |
| 11 | TRADING_DAYS_PER_YEAR = 252.0 |
| 12 | #: Minutes in one trading session (a 6.5-hour US equity session, 09:30 to 16:00). |
| 13 | SESSION_MINUTES = 390.0 |
| 14 | #: One-minute bars a year, ``TRADING_DAYS_PER_YEAR * SESSION_MINUTES`` = 98,280. |
| 15 | MINUTE_BARS_PER_YEAR = TRADING_DAYS_PER_YEAR * SESSION_MINUTES |
| 16 | |
| 17 | |
| 18 | def infer_periods_per_year(timestamps: Sequence[str]) -> float | None: |
| 19 | """Bars a year implied by the spacing of ``timestamps``. |
| 20 | |
| 21 | Thin wrapper over ``openquant._core.pipeline.infer_periods_per_year``: the median gap |
| 22 | between consecutive strictly increasing timestamps is mapped with the convention of |
| 23 | 252 sessions of 390 minutes a year. Intraday gaps give ``252 * 390 / gap_minutes`` |
| 24 | (one-minute bars: 98,280); gaps from 20 hours to under 4 days give 252 (daily bars); |
| 25 | longer gaps give ``365.25 / gap_days``. |
| 26 | |
| 27 | Parameters |
| 28 | ---------- |
| 29 | timestamps : Sequence[str] |
| 30 | Bar timestamps as ``"%Y-%m-%d %H:%M:%S"`` strings, oldest first. |
| 31 | |
| 32 | Returns |
| 33 | ------- |
| 34 | float or None |
| 35 | Bars a year, or None when fewer than two timestamps strictly increase. |
| 36 | """ |
| 37 | return _core.pipeline.infer_periods_per_year(list(timestamps)) |
| 38 | |
| 39 | |
| 40 | def _resolve_periods_per_year(timestamps: Sequence[str], periods_per_year: float | None) -> float: |
| 41 | if periods_per_year is not None: |
| 42 | return float(periods_per_year) |
| 43 | inferred = infer_periods_per_year(timestamps) |
| 44 | return TRADING_DAYS_PER_YEAR if inferred is None else inferred |
no outgoing calls
no test coverage detected