Files
QuantumTerminal/backend/data_manager/cli.py
T

135 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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()