You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
"""
|
|
Earnings Surprise schemas
|
|
"""
|
|
|
|
from datetime import date, datetime
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
|
|
class EarningsSurpriseEntry(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
fiscal_date_ending: date
|
|
reported_date: Optional[date] = None
|
|
reported_eps: Optional[float] = None
|
|
estimated_eps: Optional[float] = None
|
|
surprise: Optional[float] = None
|
|
surprise_percentage: Optional[float] = None
|
|
beat: Optional[bool] = None
|
|
|
|
@classmethod
|
|
def from_orm_obj(cls, obj) -> "EarningsSurpriseEntry":
|
|
surprise = obj.surprise
|
|
return cls(
|
|
fiscal_date_ending=(
|
|
obj.fiscal_date_ending.date()
|
|
if hasattr(obj.fiscal_date_ending, "date")
|
|
else obj.fiscal_date_ending
|
|
),
|
|
reported_date=(
|
|
obj.reported_date.date()
|
|
if obj.reported_date and hasattr(obj.reported_date, "date")
|
|
else obj.reported_date
|
|
),
|
|
reported_eps=obj.reported_eps,
|
|
estimated_eps=obj.estimated_eps,
|
|
surprise=surprise,
|
|
surprise_percentage=obj.surprise_percentage,
|
|
beat=surprise > 0 if surprise is not None else None,
|
|
)
|
|
|
|
|
|
class EarningsSurpriseResponse(BaseModel):
|
|
symbol: str
|
|
quarters: List[EarningsSurpriseEntry]
|
|
streak: int = 0 # positive = consecutive beats, negative = consecutive misses
|
|
avg_surprise_pct: Optional[float] = None
|
|
metadata: Dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class EarningsCalendarEntry(BaseModel):
|
|
symbol: str
|
|
earnings_date: datetime
|
|
earnings_time: str # "pre_market" | "post_market" | "during_market" | "unknown"
|
|
estimated_eps: Optional[float] = None
|
|
reported_eps: Optional[float] = None # non-null when as_of_date is historical
|
|
source: str = "yfinance"
|
|
fetched_at: datetime
|
|
|
|
|
|
class EarningsCalendarResponse(BaseModel):
|
|
symbol: str
|
|
upcoming_earnings: List[EarningsCalendarEntry]
|
|
metadata: Dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class BulkEarningsCalendarRequest(BaseModel):
|
|
symbols: List[str] = Field(..., min_length=1, max_length=50)
|
|
days_ahead: int = Field(30, ge=1, le=365)
|
|
limit: int = Field(4, ge=1, le=20)
|
|
as_of_date: Optional[date] = Field(
|
|
None, description="PIT date for backtesting (YYYY-MM-DD). Defaults to today."
|
|
)
|
|
|
|
|
|
class BulkEarningsCalendarResponse(BaseModel):
|
|
entries: List[EarningsCalendarEntry]
|
|
metadata: Dict[str, Any] = Field(default_factory=dict)
|