- Docker: Delete 23 deprecated Dockerfiles, fix CI/CD to use Dockerfile.foxhunt-build - Config: Remove 36 .env files, keep 4 essential, delete config/environments/ - Docs: Archive 614 Wave D files to docs/archive/wave_d/, 95% reduction in root - Scripts: Delete 56 deprecated scripts, keep 58 production-critical (49% reduction) - Python: Organize 37 scripts into scripts/python/ subdirectories, delete ml/python/ - Build: Remove 1GB artifacts, delete old venvs, clean Python cache from git - Migrations: Delete deprecated directory (4,432 lines), remove duplicate database/migrations/ - Infrastructure: Delete deployment/ (61 files), docs/scripts/ (8 files) Total impact: ~2,500 files cleaned, 750MB+ space freed, zero production impact All deleted scripts backed up to archives. runpod/ and tests/runpod/ preserved. data_acquisition_service retained per user request.
168 lines
5.0 KiB
Python
168 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Download 180 days of NQ.FUT (E-mini Nasdaq-100) OHLCV-1m data from Databento.
|
|
|
|
Agent: W12-03
|
|
Symbol: NQ.FUT
|
|
Date range: 2025-04-23 to 2025-10-20 (180 days)
|
|
Schema: ohlcv-1m
|
|
Dataset: GLBX.MDP3
|
|
Expected: ~1.33M bars, ~95 MB
|
|
Cost: ~$1.00
|
|
|
|
Usage:
|
|
python3 download_nq_fut_180d.py
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
import databento as db
|
|
|
|
# Configuration
|
|
API_KEY = os.getenv("DATABENTO_API_KEY", "db-95LEt9gtDRPJfc55NVUB5KL3A3uf6")
|
|
OUTPUT_FILE = "test_data/NQ_FUT_180d.dbn"
|
|
SCHEMA = "ohlcv-1m"
|
|
DATASET = "GLBX.MDP3"
|
|
SYMBOL = "NQ.FUT"
|
|
START_DATE = "2024-04-23"
|
|
END_DATE = "2024-10-19" # Yesterday - today's data requires premium subscription
|
|
|
|
|
|
def main():
|
|
"""Download NQ.FUT 180-day OHLCV data."""
|
|
print("=" * 80)
|
|
print("NQ.FUT 180-Day Databento Download (Agent W12-03)")
|
|
print("=" * 80)
|
|
print()
|
|
|
|
# Check API key
|
|
if not API_KEY:
|
|
print("❌ ERROR: DATABENTO_API_KEY not found in environment!")
|
|
print("Set it with: export DATABENTO_API_KEY='your-key-here'")
|
|
sys.exit(1)
|
|
|
|
# Create output directory
|
|
os.makedirs(os.path.dirname(OUTPUT_FILE), exist_ok=True)
|
|
print(f"📁 Output file: {OUTPUT_FILE}")
|
|
print(f"📊 Schema: {SCHEMA}")
|
|
print(f"📦 Dataset: {DATASET}")
|
|
print(f"🎯 Symbol: {SYMBOL}")
|
|
print(f"📅 Date range: {START_DATE} to {END_DATE}")
|
|
print()
|
|
|
|
# Initialize Databento client
|
|
try:
|
|
client = db.Historical(API_KEY)
|
|
print("✅ Databento client initialized")
|
|
except Exception as e:
|
|
print(f"❌ Failed to initialize Databento client: {e}")
|
|
sys.exit(1)
|
|
|
|
# Download data
|
|
try:
|
|
print()
|
|
print("-" * 80)
|
|
print(f"📥 Downloading NQ.FUT data...")
|
|
print("-" * 80)
|
|
print()
|
|
|
|
# Parse dates
|
|
start_dt = datetime.strptime(START_DATE, "%Y-%m-%d").replace(tzinfo=timezone.utc)
|
|
# END_DATE includes time, so parse accordingly
|
|
if "T" in END_DATE:
|
|
end_dt = datetime.fromisoformat(END_DATE).replace(tzinfo=timezone.utc)
|
|
else:
|
|
end_dt = datetime.strptime(END_DATE, "%Y-%m-%d").replace(hour=23, minute=59, second=59, tzinfo=timezone.utc)
|
|
|
|
print(f" Start: {start_dt.isoformat()}")
|
|
print(f" End: {end_dt.isoformat()}")
|
|
print()
|
|
|
|
# Request data
|
|
print(" Requesting data from Databento...")
|
|
data = client.timeseries.get_range(
|
|
dataset=DATASET,
|
|
symbols=[SYMBOL],
|
|
schema=SCHEMA,
|
|
start=start_dt.isoformat(),
|
|
end=end_dt.isoformat(),
|
|
stype_in="parent", # Required for .FUT continuous symbols
|
|
)
|
|
|
|
# Write to file
|
|
print(" Writing to file...")
|
|
data.to_file(OUTPUT_FILE)
|
|
|
|
# Get file size
|
|
file_size = os.path.getsize(OUTPUT_FILE)
|
|
file_size_mb = file_size / (1024 * 1024)
|
|
|
|
print()
|
|
print(f"✅ Download complete!")
|
|
print(f" File size: {file_size:,} bytes ({file_size_mb:.2f} MB)")
|
|
|
|
# Read back to verify data count
|
|
try:
|
|
print(" Verifying data...")
|
|
store = db.DBNStore.from_file(OUTPUT_FILE)
|
|
df = store.to_df()
|
|
record_count = len(df)
|
|
|
|
print(f" Records: {record_count:,}")
|
|
|
|
# Show sample data
|
|
if record_count > 0:
|
|
print(f" Price range: ${df['close'].min():.2f} - ${df['close'].max():.2f}")
|
|
print(f" Volume: {df['volume'].sum():,.0f}")
|
|
|
|
# Show first and last timestamps
|
|
print(f" First timestamp: {df.index[0]}")
|
|
print(f" Last timestamp: {df.index[-1]}")
|
|
else:
|
|
print(" ⚠️ WARNING: No records in file!")
|
|
sys.exit(1)
|
|
|
|
except Exception as e:
|
|
print(f" ⚠️ Could not verify record count: {e}")
|
|
|
|
# Estimate cost (rough: ~$1.00 for 180 days of 1-minute OHLCV data)
|
|
estimated_cost = 1.00
|
|
|
|
print()
|
|
print(f"💰 Estimated cost: ${estimated_cost:.2f}")
|
|
|
|
# Success summary
|
|
print()
|
|
print("=" * 80)
|
|
print("✅ SUCCESS: NQ.FUT download complete!")
|
|
print("=" * 80)
|
|
print()
|
|
print(f"📁 File: {OUTPUT_FILE}")
|
|
print(f"📊 Size: {file_size_mb:.2f} MB")
|
|
print(f"📈 Records: {record_count:,} bars")
|
|
print(f"💰 Cost: ${estimated_cost:.2f}")
|
|
print()
|
|
print("📋 NEXT STEPS:")
|
|
print("1. Validate file:")
|
|
print(" cargo run -p backtesting_service --example validate_dbn_data")
|
|
print("2. Use for ML training with 225 features")
|
|
print("3. Proceed to W12-04 (6E.FUT download)")
|
|
print()
|
|
|
|
except Exception as e:
|
|
print()
|
|
print(f"❌ Download failed: {e}")
|
|
print()
|
|
print("Possible causes:")
|
|
print("• Invalid API key")
|
|
print("• Network connectivity issues")
|
|
print("• Databento service unavailable")
|
|
print("• Invalid date range or symbol")
|
|
print()
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|