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.

211 lines
5.4 KiB
Python

"""
Pydantic schemas for Overlay API responses
"""
from datetime import datetime
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field
class OverlayFeatures(BaseModel):
headline_burst_z: Optional[float] = None
youtube_influence_z: Optional[float] = None
wiki_attention_z: Optional[float] = None
theme_heat_z: Optional[float] = None
crowding_stress_z: Optional[float] = None
class OverlaySourcePresence(BaseModel):
yahoo: bool = False
youtube: bool = False
wikimedia: bool = False
google_trends: bool = False
finra: bool = False
class YahooSourceDetail(BaseModel):
headline_count_6h: int = 0
headline_count_24h: int = 0
publisher_breadth_24h: int = 0
class YouTubeSourceDetail(BaseModel):
mentions_24h: int = 0
weighted_views_24h: float = 0.0
class WikiSourceDetail(BaseModel):
page_views_1d: Optional[int] = None
page_views_7d_avg: Optional[float] = None
class FinraSourceDetail(BaseModel):
short_volume_ratio: Optional[float] = None
short_volume_spike_zscore: Optional[float] = None
class OverlaySourceDetails(BaseModel):
yahoo: Optional[YahooSourceDetail] = None
youtube: Optional[YouTubeSourceDetail] = None
wikimedia: Optional[WikiSourceDetail] = None
finra: Optional[FinraSourceDetail] = None
class OverlayMetadata(BaseModel):
feature_version: str = "v1"
data_freshness: Optional[datetime] = None
next_update_expected: Optional[datetime] = None
class OverlayScoreResponse(BaseModel):
symbol: str
as_of_ts: Optional[datetime] = None
overlay_score: float = 0.0
overlay_confidence: float = 0.0
overlay_band: Optional[str] = None
hold_extension_hint: Optional[str] = None
add_on_eligibility: Optional[bool] = None
features: OverlayFeatures = Field(default_factory=OverlayFeatures)
source_presence: OverlaySourcePresence = Field(default_factory=OverlaySourcePresence)
source_details: OverlaySourceDetails = Field(default_factory=OverlaySourceDetails)
metadata: OverlayMetadata = Field(default_factory=OverlayMetadata)
class BulkOverlayResponse(BaseModel):
results: List[OverlayScoreResponse]
total_count: int
metadata: Dict[str, Any] = Field(default_factory=dict)
class OverlayTopMover(BaseModel):
symbol: str
overlay_score: float
overlay_band: Optional[str] = None
as_of_ts: Optional[datetime] = None
class TopMoversResponse(BaseModel):
top_movers: List[OverlayTopMover]
total_count: int
metadata: Dict[str, Any] = Field(default_factory=dict)
class HeadlineItem(BaseModel):
title: str
publisher: Optional[str] = None
published_at: datetime
article_guid: str
class HeadlinesResponse(BaseModel):
symbol: str
headlines: List[HeadlineItem]
headline_count_6h: int = 0
headline_count_24h: int = 0
publisher_breadth_24h: int = 0
metadata: Dict[str, Any] = Field(default_factory=dict)
class VideoItem(BaseModel):
video_id: str
channel_id: str
title: str
view_count: int = 0
comment_count: int = 0
published_at: Optional[datetime] = None
channel_weight: float = 0.5
class YouTubeResponse(BaseModel):
symbol: str
videos: List[VideoItem]
mentions_24h: int = 0
weighted_views_24h: float = 0.0
metadata: Dict[str, Any] = Field(default_factory=dict)
class WikiPageviewPoint(BaseModel):
date: datetime
views: int
page_title: str
class WikiResponse(BaseModel):
symbol: str
pageviews: List[WikiPageviewPoint]
views_1d: Optional[int] = None
views_7d_avg: Optional[float] = None
metadata: Dict[str, Any] = Field(default_factory=dict)
class CrowdingResponse(BaseModel):
symbol: str
short_volume_ratio: Optional[float] = None
short_volume_spike_zscore: Optional[float] = None
crowding_stress_z: Optional[float] = None
metadata: Dict[str, Any] = Field(default_factory=dict)
class TrendPoint(BaseModel):
observed_at: datetime
interest_value: int
topic_id: str
topic_label: Optional[str] = None
class TrendsResponse(BaseModel):
symbol: str
trends: List[TrendPoint]
theme_heat_z: Optional[float] = None
metadata: Dict[str, Any] = Field(default_factory=dict)
class OverlayHistoryPoint(BaseModel):
as_of_ts: datetime
overlay_score: float
overlay_confidence: float
overlay_band: Optional[str] = None
class OverlayHistoryResponse(BaseModel):
symbol: str
history: List[OverlayHistoryPoint]
metadata: Dict[str, Any] = Field(default_factory=dict)
class SourceHealthItem(BaseModel):
source: str
last_collected_at: Optional[datetime] = None
status: str = "unknown"
success_rate_24h: Optional[float] = None
records_24h: int = 0
class AdminHealthResponse(BaseModel):
overlay_enabled: bool
sources: List[SourceHealthItem]
last_pipeline_run: Optional[datetime] = None
metadata: Dict[str, Any] = Field(default_factory=dict)
class TriggerPipelineResponse(BaseModel):
status: str
message: str
job_ids: List[str] = Field(default_factory=list)
class JobLogEntry(BaseModel):
id: str
job_type: str
status: str
started_at: datetime
completed_at: Optional[datetime] = None
records_processed: int = 0
error_message: Optional[str] = None
class JobLogResponse(BaseModel):
logs: List[JobLogEntry]
total_count: int
metadata: Dict[str, Any] = Field(default_factory=dict)