(
df: pl.DataFrame,
*,
interval: str = "1d",
)
| 247 | |
| 248 | |
| 249 | def align_calendar( |
| 250 | df: pl.DataFrame, |
| 251 | *, |
| 252 | interval: str = "1d", |
| 253 | ) -> pl.DataFrame: |
| 254 | interval_seconds = _interval_to_seconds(interval) |
| 255 | if interval_seconds <= 0: |
| 256 | raise ValueError("interval_seconds must be > 0") |
| 257 | |
| 258 | clean = clean_ohlcv(df).lazy() |
| 259 | bounds = clean.group_by("symbol").agg( |
| 260 | pl.col("ts").min().alias("ts_min"), |
| 261 | pl.col("ts").max().alias("ts_max"), |
| 262 | ) |
| 263 | calendar = ( |
| 264 | bounds.with_columns( |
| 265 | pl.datetime_ranges( |
| 266 | "ts_min", |
| 267 | "ts_max", |
| 268 | interval=f"{interval_seconds}s", |
| 269 | closed="both", |
| 270 | ).alias("ts") |
| 271 | ) |
| 272 | .explode("ts") |
| 273 | .select(["symbol", "ts"]) |
| 274 | ) |
| 275 | |
| 276 | out = ( |
| 277 | calendar.join(clean, on=["symbol", "ts"], how="left") |
| 278 | .with_columns(pl.col("open").is_null().alias("is_missing_bar")) |
| 279 | .select(CANONICAL_OHLCV_COLUMNS + ["is_missing_bar"]) |
| 280 | .sort(["symbol", "ts"]) |
| 281 | .collect() |
| 282 | ) |
| 283 | return out |
nothing calls this directly
no test coverage detected