bit-forecast-arena / tests /fixture.py
Bit-Trading-Company's picture
CI deploy local
8028640 verified
Raw
History Blame Contribute Delete
1.41 kB
"""Synthetic market data with known statistics.
A geometric random walk is used rather than a recorded price series because
the coverage test needs a distribution whose true quantiles are known in
closed form. Real prices would make that test a measurement of the market
rather than of the arithmetic.
"""
from __future__ import annotations
import numpy as np
import pandas as pd
def synth(n: int = 600, tf: str = "1h", seed: int = 7, s0: float = 50000.0,
sigma: float = 0.01, mu: float = 0.0) -> pd.DataFrame:
rng = np.random.default_rng(seed)
r = rng.normal(mu, sigma, n)
close = s0 * np.exp(np.cumsum(r))
openp = np.concatenate([[s0], close[:-1]])
hi = np.maximum(openp, close) * (1 + np.abs(rng.normal(0, sigma / 3, n)))
lo = np.minimum(openp, close) * (1 - np.abs(rng.normal(0, sigma / 3, n)))
vol = np.abs(rng.normal(1000, 200, n)) + 1.0
step = pd.Timedelta("1h") if tf == "1h" else pd.Timedelta("1d")
ts = pd.date_range("2025-01-01", periods=n, freq=step, tz="UTC")
return pd.DataFrame({"ts": ts, "open": openp, "high": hi, "low": lo,
"close": close, "volume": vol})
def future_ts(context: pd.DataFrame, horizon: int) -> pd.DatetimeIndex:
ts = pd.to_datetime(context["ts"], utc=True)
step = ts.diff().dropna().mode().iloc[0]
return pd.DatetimeIndex([ts.iloc[-1] + step * (i + 1) for i in range(horizon)])