#!/usr/bin/env python3 """Fetch OHLCV bars from HF Market Data into CSV or Parquet. Examples: fetch_bars.py --asset stock --ticker AAPL --start 2020-01-01 --out aapl.csv fetch_bars.py --asset stock --ticker AAPL MSFT --timeframe 1hour --start 2025-08-01 --out both.csv fetch_bars.py --asset futures --ticker CL --adjustment contin_adj_ratio --out cl.parquet """ from __future__ import annotations import argparse import sys from pathlib import Path import pandas as pd sys.path.insert(0, str(Path(__file__).parent)) import hfmd # noqa: E402 def main() -> int: ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("--asset", required=True, choices=["stock", "etf", "crypto", "index", "fx", "futures"]) ap.add_argument("--ticker", required=True, nargs="+", help="one or more symbols") ap.add_argument("--timeframe", default="1day", help="1min 5min 30min 1hour 1day (aliases 1m 5m 30m 1h 1d)") ap.add_argument("--start") ap.add_argument("--end") ap.add_argument("--adjustment", help="stock/etf: UNADJUSTED adj_split adj_splitdiv ยท futures: contin_UNadj contin_adj_ratio contin_adj_absolute") ap.add_argument("--out", required=True, help=".csv or .parquet") a = ap.parse_args() frames = [] for t in a.ticker: df = hfmd.bars(a.asset, t.upper(), a.timeframe, a.start, a.end, a.adjustment) if df.empty: hfmd.log(f"{t}: no rows returned") continue hfmd.log(f"{t}: {len(df):,} bars from {df['datetime'].iloc[0]} to {df['datetime'].iloc[-1]}") frames.append(df) if not frames: return 1 out = pd.concat(frames, ignore_index=True) if a.out.endswith(".parquet"): out.to_parquet(a.out, index=False) else: out.to_csv(a.out, index=False) print(f"wrote {a.out}: {len(out):,} rows, {out['ticker'].nunique()} ticker(s), columns={list(out.columns)}") return 0 if __name__ == "__main__": sys.exit(main())