main
py 64 lines 2.75 KB
Raw
1 """Authenticated regional watchlist contracts and durable research projection."""
2 from __future__ import annotations
3
4 import asyncio
5 from decimal import Decimal
6 from typing import Any, Literal
7 from uuid import UUID
8
9 from pydantic import BaseModel, ConfigDict, Field
10
11
12 MarketRegion = Literal["INDIA", "EUROPE", "USA"]
13
14
15 class EnsureDefaultWatchlistRequest(BaseModel):
16 region: MarketRegion
17
18
19 class AddWatchlistInstrumentRequest(BaseModel):
20 model_config = ConfigDict(populate_by_name=True)
21
22 global_instrument_id: UUID = Field(alias="globalInstrumentId")
23 source_period: Literal["DAY", "WEEK", "MONTH", "YEAR"] | None = Field(
24 default=None, alias="sourcePeriod"
25 )
26 source_performance_pct: Decimal | None = Field(default=None, alias="sourcePerformancePct")
27
28 def portfolio_payload(self) -> dict[str, Any]:
29 return {
30 "globalInstrumentId": str(self.global_instrument_id),
31 "sourcePeriod": self.source_period,
32 "sourcePerformancePct": float(self.source_performance_pct) if self.source_performance_pct is not None else None,
33 }
34
35
36 async def watchlist_research_projection(orchestrator, payload: dict, **kwargs) -> dict:
37 """Compose membership with existing durable company research; never refresh."""
38 memberships = payload.get("instruments", [])
39
40 async def project(membership: dict) -> dict:
41 instrument_id = UUID(str(membership["globalInstrumentId"]))
42 metadata = membership.get("instrument")
43 company = await orchestrator.read_global_company_state(
44 instrument_id,
45 metadata=metadata if isinstance(metadata, dict) else None,
46 **kwargs,
47 )
48 return {
49 "globalInstrumentId": str(instrument_id),
50 "companyName": (metadata or {}).get("canonicalName") if isinstance(metadata, dict) else None,
51 "ticker": (metadata or {}).get("primarySymbol") if isinstance(metadata, dict) else None,
52 "exchange": (metadata or {}).get("primaryExchange") if isinstance(metadata, dict) else None,
53 "country": (metadata or {}).get("country") if isinstance(metadata, dict) else None,
54 "currency": (metadata or {}).get("currency") if isinstance(metadata, dict) else None,
55 "assetType": (metadata or {}).get("assetType") if isinstance(metadata, dict) else None,
56 "held": False,
57 "sourcePeriod": membership.get("sourcePeriod"),
58 "sourcePerformancePct": membership.get("sourcePerformancePct"),
59 "addedAt": membership.get("addedAt"),
60 "company": company.model_dump(mode="json", by_alias=True),
61 }
62
63 instruments = await asyncio.gather(*(project(value) for value in memberships))
64 return {"watchlist": payload.get("watchlist", {}), "instruments": instruments}