DevKX commited on
Commit
6711b85
Β·
verified Β·
1 Parent(s): 1f009b3

Upload data_fetcher.py

Browse files
Files changed (1) hide show
  1. src/data_fetcher.py +93 -15
src/data_fetcher.py CHANGED
@@ -4,6 +4,7 @@ import yfinance as yf
4
  import pandas as pd
5
  import finnhub
6
  import streamlit as st
 
7
  from dotenv import load_dotenv
8
  from datetime import datetime, timedelta
9
 
@@ -11,31 +12,108 @@ from datetime import datetime, timedelta
11
  load_dotenv()
12
 
13
  class DataFetcher:
14
- def __init__(self, ticker="^GSPC", vix_ticker="^VIX"):
15
  self.ticker = ticker
16
  self.vix_ticker = vix_ticker
17
 
18
- # Initialize Finnhub Client
19
- api_key = os.getenv("FINNHUB_API_KEY")
20
- if not api_key:
21
- raise ValueError("❌ FINNHUB_API_KEY not found in .env file!")
22
 
23
- self.finnhub_client = finnhub.Client(api_key=api_key)
 
 
 
 
24
 
25
- def fetch_market_data(self, days=50):
26
- """
27
- Exclusively loads market data from backup to ensure 100% uptime for demo.
28
- """
29
- print(f"πŸ“ System: API bypassed. Loading localized market data...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  backup_path = "data/market_data_backup.csv"
 
 
 
 
 
 
 
31
 
 
 
 
 
 
 
 
 
 
32
  if not os.path.exists(backup_path):
33
- print(f"🚨 FATAL: {backup_path} not found!")
34
  return pd.DataFrame()
35
-
36
  df = pd.read_csv(backup_path, index_col=0, parse_dates=True)
37
-
38
-
39
  return df.tail(days)
40
 
41
 
 
4
  import pandas as pd
5
  import finnhub
6
  import streamlit as st
7
+ import requests
8
  from dotenv import load_dotenv
9
  from datetime import datetime, timedelta
10
 
 
12
  load_dotenv()
13
 
14
  class DataFetcher:
15
+ def __init__(self, ticker="^GSPC", vix_ticker="%5EVIX"):
16
  self.ticker = ticker
17
  self.vix_ticker = vix_ticker
18
 
19
+ # Load API Keys
20
+ self.finnhub_key = os.getenv("FINNHUB_API_KEY")
21
+ self.fmp_key = os.getenv("FMP_API_KEY")
 
22
 
23
+ if not self.finnhub_key or not self.fmp_key:
24
+ print("⚠️ Warning: API Keys missing! Check your .env file or HF Secrets.")
25
+
26
+ # Initialize Finnhub Client for News
27
+ self.finnhub_client = finnhub.Client(api_key=self.finnhub_key)
28
 
29
+ def fetch_market_data(self, days=60):
30
+ """Fetches live SPY data from the NEW FMP Stable API and merges VIX."""
31
+ if not self.fmp_key:
32
+ return self._load_backup(days)
33
+
34
+ try:
35
+ print(f"πŸ“‘ Fetching live data for {self.ticker} from FMP Stable API...")
36
+
37
+ spy_url = f"https://financialmodelingprep.com/stable/historical-price-eod/full?symbol={self.ticker}&apikey={self.fmp_key}"
38
+ spy_res = requests.get(spy_url, timeout=10).json()
39
+
40
+ if isinstance(spy_res, dict) and "Error Message" in spy_res:
41
+ print(f"🚨 FMP Error: {spy_res['Error Message']}")
42
+ return self._load_backup(days)
43
+
44
+ if not isinstance(spy_res, list) or len(spy_res) == 0:
45
+ return self._load_backup(days)
46
+
47
+ # Format main DataFrame
48
+ df = pd.DataFrame(spy_res)
49
+
50
+ # πŸ›‘οΈ THE FIX: Convert to datetime, strip timezones, and set to midnight
51
+ df['date'] = pd.to_datetime(df['date'])
52
+ if df['date'].dt.tz is not None:
53
+ df['date'] = df['date'].dt.tz_localize(None)
54
+ df['date'] = df['date'].dt.normalize()
55
+
56
+ df.set_index('date', inplace=True)
57
+ df = df.sort_index()[['open', 'high', 'low', 'close', 'volume']]
58
+ df.columns = [c.capitalize() for c in df.columns]
59
+
60
+ # Add VIX
61
+ df['VIX'] = self._get_vix_data()
62
+ df['VIX'] = df['VIX'].ffill().bfill()
63
+
64
+ print("βœ… Live market data fetched and merged successfully!")
65
+ return df.tail(days)
66
+
67
+ except Exception as e:
68
+ print(f"🚨 Major Fetch Error: {e}")
69
+ return self._load_backup(days)
70
+
71
+ def _get_vix_data(self):
72
+ """Attempts to fetch VIX from Stable API, falls back to CSV if blocked."""
73
+ print("πŸ“‘ Attempting to fetch VIX from FMP Stable API...")
74
+ try:
75
+ vix_url = f"https://financialmodelingprep.com/stable/historical-price-eod/full?symbol={self.vix_ticker}&apikey={self.fmp_key}"
76
+ vix_res = requests.get(vix_url, timeout=5).json()
77
+
78
+ if isinstance(vix_res, list) and len(vix_res) > 0:
79
+ vix_df = pd.DataFrame(vix_res)
80
+
81
+ # πŸ›‘οΈ THE FIX: Strip timezones for VIX so it perfectly matches SPY
82
+ vix_df['date'] = pd.to_datetime(vix_df['date'])
83
+ if vix_df['date'].dt.tz is not None:
84
+ vix_df['date'] = vix_df['date'].dt.tz_localize(None)
85
+ vix_df['date'] = vix_df['date'].dt.normalize()
86
+
87
+ vix_df.set_index('date', inplace=True)
88
+ vix_df = vix_df.sort_index()
89
+ print("βœ… VIX fetched successfully from FMP!")
90
+ return vix_df['close']
91
+ except Exception as e:
92
+ print(f"⚠️ VIX API request failed: {e}")
93
+
94
+ print("⚠️ Pulling VIX from local backup...")
95
  backup_path = "data/market_data_backup.csv"
96
+
97
+ if os.path.exists(backup_path):
98
+ backup_df = pd.read_csv(backup_path, index_col=0, parse_dates=True)
99
+ # Strip timezones from the backup CSV index as well!
100
+ if backup_df.index.tz is not None:
101
+ backup_df.index = backup_df.index.tz_localize(None)
102
+ backup_df.index = backup_df.index.normalize()
103
 
104
+ if 'VIX' in backup_df.columns:
105
+ return backup_df['VIX']
106
+
107
+ return 18.0
108
+
109
+ def _load_backup(self, days):
110
+ """Failsafe method to load local CSV if API entirely blocks the request."""
111
+ print(f"πŸ“ System: Loading localized market data backup...")
112
+ backup_path = "data/market_data_backup.csv"
113
  if not os.path.exists(backup_path):
114
+ print("🚨 Market backup CSV not found!")
115
  return pd.DataFrame()
 
116
  df = pd.read_csv(backup_path, index_col=0, parse_dates=True)
 
 
117
  return df.tail(days)
118
 
119