58 lines
1.8 KiB
Python
58 lines
1.8 KiB
Python
import os
|
|
import threading
|
|
from typing import List, Optional
|
|
|
|
import pandas as pd
|
|
|
|
|
|
_lock = threading.Lock()
|
|
|
|
|
|
def ensure_storage(base_dir: str):
|
|
os.makedirs(base_dir, exist_ok=True)
|
|
|
|
|
|
def _path(base_dir: str, symbol: str, timeframe: str) -> str:
|
|
safe_symbol = symbol.replace("/", "_").replace(":", "_")
|
|
d = os.path.join(base_dir, timeframe)
|
|
os.makedirs(d, exist_ok=True)
|
|
return os.path.join(d, f"{safe_symbol}.parquet")
|
|
|
|
|
|
def read_candles(base_dir: str, symbol: str, timeframe: str, start: Optional[int], end: Optional[int]) -> pd.DataFrame:
|
|
p = _path(base_dir, symbol, timeframe)
|
|
if not os.path.exists(p):
|
|
return pd.DataFrame(columns=["timestamp", "open", "high", "low", "close", "volume"]) # empty
|
|
df = pd.read_parquet(p)
|
|
if start is not None:
|
|
df = df[df["timestamp"] >= int(start)]
|
|
if end is not None:
|
|
df = df[df["timestamp"] <= int(end)]
|
|
df = df.sort_values("timestamp")
|
|
return df
|
|
|
|
|
|
def upsert_candles(base_dir: str, symbol: str, timeframe: str, candles: List[List[float]]):
|
|
p = _path(base_dir, symbol, timeframe)
|
|
new_df = pd.DataFrame(candles, columns=["timestamp", "open", "high", "low", "close", "volume"])
|
|
with _lock:
|
|
if os.path.exists(p):
|
|
old = pd.read_parquet(p)
|
|
merged = pd.concat([old, new_df], ignore_index=True)
|
|
merged = merged.drop_duplicates(subset=["timestamp"], keep="last").sort_values("timestamp")
|
|
else:
|
|
merged = new_df.sort_values("timestamp")
|
|
merged.to_parquet(p, index=False)
|
|
|
|
|
|
def get_last_timestamp(base_dir: str, symbol: str, timeframe: str) -> Optional[int]:
|
|
p = _path(base_dir, symbol, timeframe)
|
|
if not os.path.exists(p):
|
|
return None
|
|
df = pd.read_parquet(p)
|
|
if df.empty:
|
|
return None
|
|
return int(df["timestamp"].iloc[-1])
|
|
|
|
|