DRRK/app/repositories/market_data.py

62 lines
2.3 KiB
Python

from __future__ import annotations
from datetime import date
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.models import MarketData, Security
from app.integrations.moex import MarketQuote
from app.repositories._upsert import insert_for
class MarketDataRepository:
def __init__(self, session: AsyncSession) -> None:
self.session = session
async def upsert(self, security_id: int, quote: MarketQuote, user: str) -> None:
"""Повторная загрузка за ту же дату перезаписывает котировку
(created_* сохраняются, updated_*/loaded_at обновляются)."""
values = {
"board": quote.board,
"clean_price": quote.clean_price,
"clean_price_source": quote.clean_price_source,
"yield_value": quote.yield_value,
"yield_source": quote.yield_source,
"duration_days": quote.duration_days,
"accrued_interest": quote.accrued_interest,
"face_value": quote.face_value,
"coupon_rate": quote.coupon_percent,
"num_trades": quote.num_trades,
"volume": quote.volume,
"raw": quote.raw,
}
stmt = insert_for(self.session, MarketData.__table__).values(
security_id=security_id,
market_date=quote.trade_date,
created_by=user,
updated_by=user,
**values,
)
stmt = stmt.on_conflict_do_update(
index_elements=["security_id", "market_date"],
set_={
**{name: stmt.excluded[name] for name in values},
"loaded_at": func.now(),
"updated_at": func.now(),
"updated_by": user,
},
)
await self.session.execute(stmt)
async def list_for_date(
self, market_date: date
) -> list[tuple[MarketData, Security]]:
result = await self.session.execute(
select(MarketData, Security)
.join(Security, Security.id == MarketData.security_id)
.where(MarketData.market_date == market_date)
.order_by(Security.isin)
)
return [(row, security) for row, security in result.all()]