Add earnings calendar feature with command and scheduled delivery
Implement comprehensive earnings calendar functionality that displays upcoming earnings for major companies (market cap > $10B). Feature includes both manual command access and automated weekly delivery. Key additions: - Finnhub API integration for earnings calendar data with market cap filtering - Discord embed formatting grouped by day with EPS/revenue estimates - !earnings command for manual queries (current or next week) - Weekly scheduled task (Sunday 6PM ET) for automatic delivery - Configuration options for market cap threshold and schedule timing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -90,3 +90,83 @@ class FinnhubAPI(StockAPIBase):
|
||||
except Exception as e:
|
||||
logger.error(f"Finnhub API unavailable: {e}")
|
||||
return False
|
||||
|
||||
def get_earnings_calendar(self, from_date: str, to_date: str, min_market_cap: float = 10_000_000_000) -> Optional[list]:
|
||||
"""
|
||||
Retrieve earnings calendar for date range, filtered by market cap.
|
||||
|
||||
Args:
|
||||
from_date: Start date (YYYY-MM-DD)
|
||||
to_date: End date (YYYY-MM-DD)
|
||||
min_market_cap: Minimum market cap threshold in dollars (default 10B)
|
||||
|
||||
Returns:
|
||||
List of enriched earnings dictionaries, or None if unavailable
|
||||
"""
|
||||
try:
|
||||
# Fetch earnings calendar from Finnhub
|
||||
earnings_data = self.client.earnings_calendar(_from=from_date, to=to_date, symbol='', international=False)
|
||||
|
||||
if not earnings_data or 'earningsCalendar' not in earnings_data:
|
||||
logger.warning(f"No earnings data available for {from_date} to {to_date}")
|
||||
return []
|
||||
|
||||
earnings_list = earnings_data['earningsCalendar']
|
||||
|
||||
if not earnings_list:
|
||||
logger.info(f"No earnings found for {from_date} to {to_date}")
|
||||
return []
|
||||
|
||||
# Enrich each earning with company profile data and filter by market cap
|
||||
enriched_earnings = []
|
||||
|
||||
for earning in earnings_list:
|
||||
symbol = earning.get('symbol')
|
||||
if not symbol:
|
||||
continue
|
||||
|
||||
try:
|
||||
# Fetch company profile for market cap and name
|
||||
profile = self.client.company_profile2(symbol=symbol)
|
||||
|
||||
if not profile:
|
||||
logger.debug(f"No profile data for {symbol}")
|
||||
continue
|
||||
|
||||
# Market cap in Finnhub is in millions, convert to dollars
|
||||
market_cap = profile.get('marketCapitalization', 0) * 1_000_000
|
||||
|
||||
# Filter by minimum market cap
|
||||
if market_cap < min_market_cap:
|
||||
continue
|
||||
|
||||
# Enrich earnings data
|
||||
enriched_earning = {
|
||||
'symbol': symbol,
|
||||
'company_name': profile.get('name', symbol),
|
||||
'market_cap': market_cap,
|
||||
'date': earning.get('date'),
|
||||
'eps_estimate': earning.get('epsEstimate'),
|
||||
'eps_actual': earning.get('epsActual'),
|
||||
'revenue_estimate': earning.get('revenueEstimate'),
|
||||
'revenue_actual': earning.get('revenueActual'),
|
||||
'hour': earning.get('hour', 'TBD'),
|
||||
'quarter': earning.get('quarter'),
|
||||
'year': earning.get('year')
|
||||
}
|
||||
|
||||
enriched_earnings.append(enriched_earning)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not fetch profile for {symbol}: {e}")
|
||||
continue
|
||||
|
||||
# Sort by date, then by market cap descending
|
||||
enriched_earnings.sort(key=lambda x: (x['date'], -x['market_cap']))
|
||||
|
||||
logger.info(f"Found {len(enriched_earnings)} earnings (market cap >= ${min_market_cap/1_000_000_000:.1f}B)")
|
||||
return enriched_earnings
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching earnings calendar: {e}")
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user