Initial hello world IBKR API connection.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Trading bot package."""
|
||||
@@ -0,0 +1 @@
|
||||
"""Training data collection tools."""
|
||||
@@ -0,0 +1,120 @@
|
||||
"""Skeleton IBKR daily candle fetcher.
|
||||
|
||||
This intentionally uses hard-coded values while the project shape is still
|
||||
being designed. Parquet persistence and configurable date ranges come later.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import date
|
||||
|
||||
|
||||
TICKER = "SPY"
|
||||
START_DATE = date(2026, 6, 1)
|
||||
END_DATE = date(2026, 6, 5)
|
||||
|
||||
IBKR_HOST = "127.0.0.1"
|
||||
IBKR_PORT = 4002
|
||||
IBKR_CLIENT_ID = 101
|
||||
IBKR_CONNECT_TIMEOUT_SECONDS = 10
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DailyCandle:
|
||||
"""Daily OHLCV market data for one trading session."""
|
||||
|
||||
trading_day: date
|
||||
open: float
|
||||
high: float
|
||||
low: float
|
||||
close: float
|
||||
volume: int
|
||||
|
||||
|
||||
def fetch_hard_coded_daily_candles() -> list[DailyCandle]:
|
||||
"""Fetch one hard-coded week of SPY daily candles from IBKR."""
|
||||
|
||||
try:
|
||||
from ib_insync import IB, Stock # type: ignore[import-not-found]
|
||||
except ImportError as exc:
|
||||
raise SystemExit(
|
||||
"Missing dependency: ib_insync. Install it before running the "
|
||||
"IBKR fetcher skeleton."
|
||||
) from exc
|
||||
|
||||
ib = IB()
|
||||
try:
|
||||
print(
|
||||
f"Connecting to IBKR Gateway at {IBKR_HOST}:{IBKR_PORT} "
|
||||
f"with client id {IBKR_CLIENT_ID}"
|
||||
)
|
||||
ib.connect(
|
||||
IBKR_HOST,
|
||||
IBKR_PORT,
|
||||
clientId=IBKR_CLIENT_ID,
|
||||
timeout=IBKR_CONNECT_TIMEOUT_SECONDS,
|
||||
)
|
||||
|
||||
contract = Stock(TICKER, "SMART", "USD")
|
||||
ib.qualifyContracts(contract)
|
||||
bars = ib.reqHistoricalData(
|
||||
contract,
|
||||
endDateTime="20260605 23:59:59 US/Eastern",
|
||||
durationStr="1 W",
|
||||
barSizeSetting="1 day",
|
||||
whatToShow="TRADES",
|
||||
useRTH=True,
|
||||
formatDate=1,
|
||||
)
|
||||
|
||||
if not bars:
|
||||
print("IBKR returned no historical bars for the hard-coded request.")
|
||||
|
||||
candles: list[DailyCandle] = []
|
||||
for bar in bars:
|
||||
trading_day = bar.date if isinstance(bar.date, date) else bar.date.date()
|
||||
if START_DATE <= trading_day <= END_DATE:
|
||||
candles.append(
|
||||
DailyCandle(
|
||||
trading_day=trading_day,
|
||||
open=float(bar.open),
|
||||
high=float(bar.high),
|
||||
low=float(bar.low),
|
||||
close=float(bar.close),
|
||||
volume=int(bar.volume),
|
||||
)
|
||||
)
|
||||
|
||||
return candles
|
||||
finally:
|
||||
if ib.isConnected():
|
||||
ib.disconnect()
|
||||
|
||||
|
||||
def print_candles(candles: list[DailyCandle]) -> None:
|
||||
"""Print candles in a compact table."""
|
||||
|
||||
print("date,ticker,open,high,low,close,volume")
|
||||
for candle in candles:
|
||||
print(
|
||||
f"{candle.trading_day.isoformat()},"
|
||||
f"{TICKER},"
|
||||
f"{candle.open:.2f},"
|
||||
f"{candle.high:.2f},"
|
||||
f"{candle.low:.2f},"
|
||||
f"{candle.close:.2f},"
|
||||
f"{candle.volume}"
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Run the hard-coded fetcher skeleton."""
|
||||
|
||||
print(f"Fetching {TICKER} daily candles from {START_DATE} to {END_DATE}")
|
||||
candles = fetch_hard_coded_daily_candles()
|
||||
print_candles(candles)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user