Build a deterministic synthetic multi-asset futures dataset. The first asset is treated as the primary traded instrument (e.g., crude oil), while the other assets provide cross-asset context for allocation/risk.
(
n_bars: int = 192,
seed: int = 7,
asset_names: list[str] | None = None,
)
| 40 | |
| 41 | |
| 42 | def make_synthetic_futures_dataset( |
| 43 | n_bars: int = 192, |
| 44 | seed: int = 7, |
| 45 | asset_names: list[str] | None = None, |
| 46 | ) -> ResearchDataset: |
| 47 | """Build a deterministic synthetic multi-asset futures dataset. |
| 48 | |
| 49 | The first asset is treated as the primary traded instrument (e.g., crude oil), |
| 50 | while the other assets provide cross-asset context for allocation/risk. |
| 51 | """ |
| 52 | if n_bars < 32: |
| 53 | raise ValueError("n_bars must be >= 32") |
| 54 | rng = random.Random(seed) |
| 55 | asset_names = asset_names or ["CL", "NG", "RB", "GC"] |
| 56 | n_assets = len(asset_names) |
| 57 | if n_assets < 2: |
| 58 | raise ValueError("asset_names must contain at least 2 assets") |
| 59 | |
| 60 | start = datetime(2024, 1, 1, 9, 30, 0) |
| 61 | timestamps = [(start + timedelta(minutes=i)).strftime("%Y-%m-%d %H:%M:%S") for i in range(n_bars)] |
| 62 | |
| 63 | base = 80.0 |
| 64 | close: list[float] = [] |
| 65 | for i in range(n_bars): |
| 66 | seasonal = 0.45 * sin(i / 9.0) + 0.25 * sin(i / 17.0) |
| 67 | drift = 0.006 * i |
| 68 | noise = rng.uniform(-0.10, 0.10) |
| 69 | price = base + drift + seasonal + noise |
| 70 | close.append(max(price, 1.0)) |
| 71 | |
| 72 | model_probabilities: list[float] = [] |
| 73 | model_sides: list[float] = [] |
| 74 | for i in range(n_bars): |
| 75 | edge = 0.53 + 0.08 * sin(i / 13.0) + rng.uniform(-0.025, 0.025) |
| 76 | p = min(max(edge, 0.05), 0.95) |
| 77 | model_probabilities.append(p) |
| 78 | model_sides.append(1.0 if sin(i / 11.0) >= 0.0 else -1.0) |
| 79 | |
| 80 | asset_prices: list[list[float]] = [] |
| 81 | for i in range(n_bars): |
| 82 | row: list[float] = [] |
| 83 | for j in range(n_assets): |
| 84 | lag = max(i - (j + 1), 0) |
| 85 | spread = 0.45 + 0.07 * j |
| 86 | px = close[lag] * (1.0 + 0.0015 * j) + spread * sin((i + 3 * j) / (9.5 + j)) |
| 87 | px += rng.uniform(-0.08, 0.08) |
| 88 | row.append(max(px, 1.0)) |
| 89 | asset_prices.append(row) |
| 90 | |
| 91 | return ResearchDataset( |
| 92 | timestamps=timestamps, |
| 93 | close=close, |
| 94 | model_probabilities=model_probabilities, |
| 95 | model_sides=model_sides, |
| 96 | asset_prices=asset_prices, |
| 97 | asset_names=asset_names, |
| 98 | ) |
| 99 |
nothing calls this directly
no test coverage detected