intraday-btc-model-11yr / core /data_loader.py
VenuMuvva's picture
Upload folder using huggingface_hub
8346b41 verified
Raw History Blame Contribute Delete
6.21 kB
"""
Data loader module for BTC 1-minute OHLCV data.
This module handles loading, validation, and preprocessing of historical
Bitcoin price data from CSV files.
"""
import pandas as pd
import os
from typing import Optional
def load_data(
filepath: str,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
validate: bool = True
) -> pd.DataFrame:
"""
Load BTC 1-minute OHLCV data from CSV file.
Parameters
----------
filepath : str
Path to the CSV file containing OHLCV data
start_date : str, optional
Start date for filtering (format: 'YYYY-MM-DD')
end_date : str, optional
End date for filtering (format: 'YYYY-MM-DD')
validate : bool, default True
Whether to validate the data integrity
Returns
-------
pd.DataFrame
DataFrame with columns: timestamp, open, high, low, close, volume
Indexed by timestamp
Raises
------
FileNotFoundError
If the file doesn't exist
ValueError
If required columns are missing or data is invalid
"""
if not os.path.exists(filepath):
raise FileNotFoundError(f"Data file not found: {filepath}")
# Load CSV
print(f"Loading data from {filepath}...")
df = pd.read_csv(filepath)
# Validate required columns
required_cols = ['timestamp', 'open', 'high', 'low', 'close', 'volume']
missing_cols = [col for col in required_cols if col not in df.columns]
if missing_cols:
raise ValueError(f"Missing required columns: {missing_cols}")
# Convert timestamp to datetime
df['timestamp'] = pd.to_datetime(df['timestamp'])
# Sort by timestamp
df = df.sort_values('timestamp').reset_index(drop=True)
# Filter by date range if specified
if start_date:
df = df[df['timestamp'] >= pd.to_datetime(start_date)]
if end_date:
df = df[df['timestamp'] <= pd.to_datetime(end_date)]
# Set timestamp as index
df = df.set_index('timestamp')
if validate:
_validate_data(df)
print(f"✓ Loaded {len(df)} bars from {df.index[0]} to {df.index[-1]}")
return df
def _validate_data(df: pd.DataFrame) -> None:
"""
Validate data integrity.
Parameters
----------
df : pd.DataFrame
DataFrame to validate
Raises
------
ValueError
If data validation fails
"""
# Check for missing values
if df.isnull().any().any():
null_counts = df.isnull().sum()
print(f"⚠ Warning: Found missing values:\n{null_counts[null_counts > 0]}")
# Fill forward missing values
df.fillna(method='ffill', inplace=True)
print(" → Filled missing values using forward fill")
# Validate OHLC relationships (with small tolerance for rounding)
tolerance = 0.01 # Allow 1 cent of tolerance
invalid_high = (df['high'] < df['low'] - tolerance).sum()
invalid_open = ((df['open'] > df['high'] + tolerance) | (df['open'] < df['low'] - tolerance)).sum()
invalid_close = ((df['close'] > df['high'] + tolerance) | (df['close'] < df['low'] - tolerance)).sum()
if invalid_high > 0:
print(f"⚠ Warning: Found {invalid_high} bars where high < low (fixing automatically)")
# Fix by swapping
mask = df['high'] < df['low']
df.loc[mask, ['high', 'low']] = df.loc[mask, ['low', 'high']].values
if invalid_open > 0:
print(f"⚠ Warning: Found {invalid_open} bars where open is outside [low, high] (fixing automatically)")
# Clamp to range
df['open'] = df['open'].clip(lower=df['low'], upper=df['high'])
if invalid_close > 0:
print(f"⚠ Warning: Found {invalid_close} bars where close is outside [low, high] (fixing automatically)")
# Clamp to range
df['close'] = df['close'].clip(lower=df['low'], upper=df['high'])
# Check for negative prices or volume
if (df[['open', 'high', 'low', 'close', 'volume']] < 0).any().any():
raise ValueError("Found negative prices or volume")
# Check for zero prices (volume can be zero)
if (df[['open', 'high', 'low', 'close']] == 0).any().any():
raise ValueError("Found zero prices")
print("✓ Data validation passed")
def get_data_summary(df: pd.DataFrame) -> dict:
"""
Get summary statistics for the dataset.
Parameters
----------
df : pd.DataFrame
OHLCV DataFrame
Returns
-------
dict
Dictionary containing summary statistics
"""
summary = {
'num_bars': len(df),
'start_date': df.index[0],
'end_date': df.index[-1],
'duration_days': (df.index[-1] - df.index[0]).days,
'price_range': {
'min': df['low'].min(),
'max': df['high'].max(),
'mean': df['close'].mean(),
'std': df['close'].std()
},
'volume': {
'total': df['volume'].sum(),
'mean': df['volume'].mean(),
'median': df['volume'].median()
}
}
return summary
if __name__ == "__main__":
# Test the data loader
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import config
try:
df = load_data(config.BTC_DATA_FILE)
summary = get_data_summary(df)
print("\nData Summary:")
print(f" Bars: {summary['num_bars']:,}")
print(f" Period: {summary['start_date']} to {summary['end_date']}")
print(f" Duration: {summary['duration_days']} days")
print(f" Price range: ${summary['price_range']['min']:.2f} - ${summary['price_range']['max']:.2f}")
print(f" Mean price: ${summary['price_range']['mean']:.2f}")
except FileNotFoundError:
print("⚠ Data file not found. Please add btc_1m.csv to the data/ directory.")
except Exception as e:
print(f"✗ Error: {e}")