(
df: pl.DataFrame,
*,
dedupe_keep: str = "last",
return_report: bool = False,
)
| 168 | |
| 169 | |
| 170 | def clean_ohlcv( |
| 171 | df: pl.DataFrame, |
| 172 | *, |
| 173 | dedupe_keep: str = "last", |
| 174 | return_report: bool = False, |
| 175 | ) -> pl.DataFrame | tuple[pl.DataFrame, dict[str, Any]]: |
| 176 | if dedupe_keep not in {"first", "last"}: |
| 177 | raise ValueError("dedupe_keep must be 'first' or 'last'") |
| 178 | |
| 179 | base_lf = _prepare_ohlcv_lf(df).with_columns(pl.col("ts").dt.timestamp(time_unit="us").alias("ts_us")) |
| 180 | sorted_lf = base_lf.sort(["symbol", "ts_us"]) |
| 181 | |
| 182 | duplicate_key_count = int( |
| 183 | sorted_lf |
| 184 | .select( |
| 185 | ( |
| 186 | ((pl.col("symbol") == pl.col("symbol").shift(1)) & (pl.col("ts_us") == pl.col("ts_us").shift(1))) |
| 187 | .cast(pl.UInt32) |
| 188 | .sum() |
| 189 | ).alias("duplicate_key_count") |
| 190 | ) |
| 191 | .collect() |
| 192 | .item(0, 0) |
| 193 | ) |
| 194 | |
| 195 | cleaned = ( |
| 196 | sorted_lf.unique( |
| 197 | subset=["symbol", "ts_us"], |
| 198 | keep=dedupe_keep, |
| 199 | maintain_order=True, |
| 200 | ) |
| 201 | .sort(["symbol", "ts"]) |
| 202 | .collect() |
| 203 | ) |
| 204 | |
| 205 | frame = cleaned.select(CANONICAL_OHLCV_COLUMNS) |
| 206 | if not return_report: |
| 207 | return frame |
| 208 | |
| 209 | report = _build_quality_report(cleaned, rows_removed_by_deduplication=duplicate_key_count) |
| 210 | report["duplicate_key_count"] = 0 |
| 211 | return frame, report |
| 212 | |
| 213 | |
| 214 | def data_quality_report(df: pl.DataFrame) -> dict[str, Any]: |
no test coverage detected