Source code for wickly._utils
"""Data validation and preparation utilities."""
from __future__ import annotations
from typing import Any, Tuple
import numpy as np
import pandas as pd
[docs]
def check_and_prepare_data(
data: pd.DataFrame,
columns: tuple[str, ...] = ("Open", "High", "Low", "Close", "Volume"),
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray | None, pd.DatetimeIndex]:
"""Validate an OHLC(V) DataFrame and return arrays.
Returns
-------
opens, highs, lows, closes, volumes (or None), dates
"""
if not isinstance(data, pd.DataFrame):
raise TypeError("data must be a Pandas DataFrame with a DatetimeIndex.")
col_open, col_high, col_low, col_close, col_volume = columns
# --- accept case-insensitive column lookup ---------------------------------
col_map = {c.lower(): c for c in data.columns}
def _resolve(name: str) -> str:
if name in data.columns:
return name
low = name.lower()
if low in col_map:
return col_map[low]
raise ValueError(
f"Column '{name}' not found in DataFrame. "
f"Available columns: {list(data.columns)}"
)
col_open = _resolve(col_open)
col_high = _resolve(col_high)
col_low = _resolve(col_low)
col_close = _resolve(col_close)
opens = data[col_open].values.astype(float)
highs = data[col_high].values.astype(float)
lows = data[col_low].values.astype(float)
closes = data[col_close].values.astype(float)
volumes: np.ndarray | None = None
try:
col_vol = _resolve(col_volume)
volumes = data[col_vol].values.astype(float)
except ValueError:
pass
# Dates
if isinstance(data.index, pd.DatetimeIndex):
dates = data.index
else:
try:
dates = pd.DatetimeIndex(data.index)
except Exception:
dates = pd.date_range("2000-01-01", periods=len(data), freq="B")
return opens, highs, lows, closes, volumes, dates