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
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)
|