Files
QuantumTerminal/backend/data_manager/cli.py
T

135 lines
5.2 KiB
Python
Raw Normal View History

"""
Data Manager CLI — command-line interface for data library management.
Usage:
python -m data_manager.cli --status
python -m data_manager.cli --prefetch --symbols EURUSD XAUUSD --tf D1 M15
python -m data_manager.cli --history --symbol EURUSD --limit 20
python -m data_manager.cli --purge --symbol EURUSD --tf D1
python -m data_manager.cli --validate
"""
import argparse
import sys
import logging
from datetime import datetime, timedelta, timezone
from pathlib import Path
# Ensure parent dir is on path for relative imports
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from data_manager import DataManager
def cmd_status(dm: DataManager):
"""Print catalog summary."""
summary = dm.get_catalog_summary()
if not summary:
print("\n [DATA LIBRARY] Empty — no datasets cached yet.\n")
return
print(f"\n [DATA LIBRARY] {dm.library_root}")
print(f" {'Symbol':<10} {'TF':<6} {'Type':<12} {'From':<12} {'To':<12} {'Rows':>8} {'Source':<6}")
print(" " + "─" * 72)
for r in summary:
d_from = r.get("date_from", "")[:10] if r.get("date_from") else "—"
d_to = r.get("date_to", "")[:10] if r.get("date_to") else "—"
print(f" {r['symbol']:<10} {r['timeframe']:<6} {r['data_type']:<12} "
f"{d_from:<12} {d_to:<12} {r.get('row_count',0):>8} {r.get('source','?'):<6}")
print()
def cmd_prefetch(dm: DataManager, symbols: list, timeframes: list, days: int):
"""Batch warm-up cache for given symbols/timeframes."""
date_from = datetime.now(timezone.utc) - timedelta(days=days)
date_to = datetime.now(timezone.utc)
print(f"\n Prefetching {len(symbols)} symbols × {len(timeframes)} timeframes "
f"({days} days back)...\n")
dm.prefetch(symbols, timeframes, date_from, date_to)
print("\n Done.\n")
def cmd_history(dm: DataManager, symbol: str, limit: int):
"""Show fetch history."""
history = dm.get_fetch_history(symbol, limit)
if not history:
print(f"\n No fetch history{' for '+symbol if symbol else ''}.\n")
return
print(f"\n {'Time':<22} {'Symbol':<10} {'TF':<6} {'Rows':>8} {'ms':>8} {'Status':<10}")
print(" " + "─" * 68)
for r in history:
ts = r.get("timestamp", "")[:19]
print(f" {ts:<22} {r['symbol']:<10} {r['timeframe']:<6} "
f"{r.get('rows_returned',0):>8} {r.get('duration_ms',0):>8} {r.get('status','?'):<10}")
print()
def cmd_validate(dm: DataManager):
"""Validate all cached Parquet files."""
summary = dm.get_catalog_summary()
if not summary:
print("\n Nothing to validate — library is empty.\n")
return
print(f"\n Validating {len(summary)} datasets...")
all_ok = True
for r in summary:
result = dm.store.validate(r["symbol"], r["timeframe"], r.get("data_type", "ohlcv"))
tag = "✓" if result.valid else "✗"
print(f" {tag} {r['symbol']:<10} {r['timeframe']:<6} rows={result.row_count}", end="")
if not result.valid:
all_ok = False
print(f" ISSUES: {'; '.join(result.issues)}")
else:
print()
print(f"\n {'All datasets valid.' if all_ok else 'Some datasets have issues — see above.'}\n")
def cmd_purge(dm: DataManager, symbol: str, timeframe: str, data_type: str):
"""Remove a specific dataset from cache."""
dm.purge(symbol, timeframe, data_type)
print(f"\n Purged {symbol} {timeframe} {data_type}\n")
def main():
parser = argparse.ArgumentParser(description="Data Manager CLI")
parser.add_argument("--status", action="store_true", help="Show catalog summary")
parser.add_argument("--prefetch", action="store_true", help="Batch prefetch data")
parser.add_argument("--history", action="store_true", help="Show fetch history")
parser.add_argument("--validate", action="store_true", help="Validate all cached files")
parser.add_argument("--purge", action="store_true", help="Purge a dataset")
parser.add_argument("--symbols", nargs="+", default=[])
parser.add_argument("--symbol", type=str, default=None)
parser.add_argument("--tf", nargs="+", default=["D1"])
parser.add_argument("--days", type=int, default=1500, help="Days back for prefetch")
parser.add_argument("--limit", type=int, default=50)
parser.add_argument("--data-type", type=str, default="ohlcv")
parser.add_argument("--mt5-path", type=str, default=None)
args = parser.parse_args()
logging.basicConfig(level=logging.INFO, format="%(message)s")
dm = DataManager(mt5_terminal_path=args.mt5_path, auto_init_mt5=True)
if args.status:
cmd_status(dm)
elif args.prefetch:
if not args.symbols:
print(" --prefetch requires --symbols")
sys.exit(1)
cmd_prefetch(dm, args.symbols, args.tf, args.days)
elif args.history:
cmd_history(dm, args.symbol, args.limit)
elif args.validate:
cmd_validate(dm)
elif args.purge:
if not args.symbol or not args.tf:
print(" --purge requires --symbol and --tf")
sys.exit(1)
cmd_purge(dm, args.symbol, args.tf[0], args.data_type)
else:
parser.print_help()
if __name__ == "__main__":
main()