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.
95 lines
3.2 KiB
Python
95 lines
3.2 KiB
Python
"""Dividend calendar Oracle service methods."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import datetime as dt
|
|
from typing import Sequence
|
|
|
|
from libs.oracle_client.client import OracleClient
|
|
from libs.oracle_client.models import (
|
|
DividendCalendarEntry,
|
|
DividendHistoryResponse,
|
|
DividendIngestResponse,
|
|
DividendUpcomingResponse,
|
|
)
|
|
|
|
|
|
def _date_param(value: dt.date | str | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
if isinstance(value, dt.date):
|
|
return value.isoformat()
|
|
return str(value)
|
|
|
|
|
|
class DividendService:
|
|
def __init__(self, client: OracleClient) -> None:
|
|
self._client = client
|
|
|
|
async def get_upcoming(
|
|
self,
|
|
*,
|
|
as_of_date: dt.date | str | None = None,
|
|
from_ex_date: dt.date | str | None = None,
|
|
to_ex_date: dt.date | str | None = None,
|
|
symbols: Sequence[str] | None = None,
|
|
limit: int = 500,
|
|
force_refresh: bool = False,
|
|
) -> DividendUpcomingResponse:
|
|
params: dict[str, object] = {
|
|
"limit": int(limit),
|
|
"force_refresh": bool(force_refresh),
|
|
}
|
|
as_of = _date_param(as_of_date)
|
|
from_ex = _date_param(from_ex_date)
|
|
to_ex = _date_param(to_ex_date)
|
|
if as_of:
|
|
params["as_of_date"] = as_of
|
|
if from_ex:
|
|
params["from_ex_date"] = from_ex
|
|
if to_ex:
|
|
params["to_ex_date"] = to_ex
|
|
if symbols:
|
|
params["symbols"] = [str(symbol).strip().upper() for symbol in symbols if str(symbol).strip()]
|
|
data = await self._client.get("/api/v1/dividends/upcoming", params=params)
|
|
entries = [DividendCalendarEntry.model_validate(item) for item in data.get("dividends", [])]
|
|
return DividendUpcomingResponse(
|
|
dividends=entries,
|
|
total_count=int(data.get("total_count", len(entries))),
|
|
metadata=dict(data.get("metadata") or {}),
|
|
)
|
|
|
|
async def get_history(
|
|
self,
|
|
symbol: str,
|
|
*,
|
|
limit: int = 1000,
|
|
force_refresh: bool = False,
|
|
) -> DividendHistoryResponse:
|
|
data = await self._client.get(
|
|
f"/api/v1/dividends/history/{symbol}",
|
|
params={"limit": int(limit), "force_refresh": bool(force_refresh)},
|
|
)
|
|
entries = [DividendCalendarEntry.model_validate(item) for item in data.get("dividends", [])]
|
|
annual_yield_estimate = data.get("annual_yield_estimate")
|
|
return DividendHistoryResponse(
|
|
symbol=data.get("symbol", symbol),
|
|
dividends=entries,
|
|
total_count=int(data.get("total_count", len(entries))),
|
|
annual_yield_estimate=float(annual_yield_estimate) if annual_yield_estimate is not None else None,
|
|
metadata=dict(data.get("metadata") or {}),
|
|
)
|
|
|
|
async def ingest(
|
|
self,
|
|
symbols: Sequence[str],
|
|
*,
|
|
force_refresh: bool = False,
|
|
) -> DividendIngestResponse:
|
|
payload = {
|
|
"symbols": [str(symbol).strip().upper() for symbol in symbols if str(symbol).strip()],
|
|
"force_refresh": bool(force_refresh),
|
|
}
|
|
data = await self._client.post("/api/v1/dividends/admin/ingest", json=payload)
|
|
return DividendIngestResponse.model_validate(data)
|