RivaCube/utils/usmarkets/collector.py
2025-02-04 19:31:18 +01:00

104 lines
3.8 KiB
Python

import logging
import requests
from datetime import datetime, timedelta
import time
import json
class USMarketsClient:
def __init__(self, api_key, rate_limit_per_minute=300):
self.api_key = api_key
self.base_url = "https://financialmodelingprep.com/api"
self.rate_limit = rate_limit_per_minute
self.last_request_time = 0
self.session = requests.Session()
def _make_request(self, endpoint):
"""Make API request with rate limiting and retry logic"""
current_time = time.time()
time_passed = current_time - self.last_request_time
if time_passed < (60 / self.rate_limit):
time.sleep((60 / self.rate_limit) - time_passed)
max_retries = 3
retry_delay = 5 # seconds
for attempt in range(max_retries):
try:
# Ensure we're not appending apikey to an existing query string
separator = '&' if '?' in endpoint else '?'
url = f"{self.base_url}{endpoint}{separator}apikey={self.api_key}"
response = self.session.get(url, timeout=30)
self.last_request_time = time.time()
if response.status_code == 200:
data = response.json()
if self._validate_response(data):
return data
else:
logging.error(f"Invalid data received for endpoint {endpoint}")
return None
elif response.status_code == 429: # Rate limit exceeded
retry_after = int(response.headers.get('Retry-After', retry_delay))
time.sleep(retry_after)
continue
else:
logging.error(f"API request failed with status code {response.status_code}")
return None
except requests.exceptions.RequestException as e:
if attempt < max_retries - 1:
time.sleep(retry_delay)
continue
logging.error(f"API request error: {e}")
return None
return None
def _validate_response(self, data):
"""Validate API response data"""
if not data:
return False
if isinstance(data, list) and len(data) == 0:
return False
if isinstance(data, dict) and 'error' in data:
return False
return True
def get_market_indices(self):
"""Get market indices data"""
return self._make_request("/v3/quotes/index")
def get_sector_performance(self):
"""Get sector performance data"""
return self._make_request("/v3/sectors-performance")
def get_sector_historical(self, from_date, to_date):
"""Get historical sector performance data"""
endpoint = f"/v3/historical-sectors-performance?from={from_date}&to={to_date}"
return self._make_request(endpoint)
def get_sector_pe_ratios(self, date, exchange='NYSE'):
"""Get sector PE ratios"""
endpoint = f"/v4/sector_price_earning_ratio?date={date}&exchange={exchange}"
return self._make_request(endpoint)
def get_industry_pe_ratios(self, date, exchange='NYSE'):
"""Get industry PE ratios"""
endpoint = f"/v4/industry_price_earning_ratio?date={date}&exchange={exchange}"
return self._make_request(endpoint)
def get_market_movers(self, mover_type='gainers'):
"""Get market movers data"""
endpoint = f"/v3/stock_market/{mover_type}"
return self._make_request(endpoint)
def get_market_actives(self):
"""Get most active stocks"""
return self._make_request("/v3/stock_market/actives")
def __del__(self):
"""Cleanup session on deletion"""
if hasattr(self, 'session'):
self.session.close()