Initial hello world IBKR API connection.

This commit is contained in:
2026-07-25 22:19:31 +03:00
parent 470e243526
commit 8d3e663e71
11 changed files with 456 additions and 3 deletions
+1
View File
@@ -0,0 +1 @@
"""Trading bot package."""
+1
View File
@@ -0,0 +1 @@
"""Training data collection tools."""
+120
View File
@@ -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()