DRRK/app/services/dates.py
Raykov-MS c1c73e96f5 Add funding rates, positions, business calendar and xlsx export
- funding_rate table and "Фондирование" page: rate from date, history, rate on date (D27)
- positions by issue: BUY - SELL per portfolio, "Остатки" page (D29)
- quotes are loaded only for securities with an open position (D10)
- business calendar from xmlcalendar.ru: yearly file upload, report date
  and update job use previous working day (D30)
- xlsx download for positions, quotes and funding rate history
- manual operation type as radio buttons
- QUIK instruments with purchase marks ("МТС 2Р-18_1") match the issue,
  file name kept in operation.instrument (D17)
- migrations d3a6f8b1c254, e7b2c9d4a813, f1c4a7e9b352
- project.md: decisions and questions after customer meetings
2026-10-29 11:20:15 +03:00

31 lines
1.0 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from datetime import date, timedelta
@dataclass(frozen=True)
class BusinessCalendar:
"""Нерабочие дни загруженных лет (D30). Для года без календаря рабочими
считаются будни."""
years: frozenset[int] = frozenset()
non_working: frozenset[date] = frozenset()
def is_business_day(self, day: date) -> bool:
if day.year in self.years:
return day not in self.non_working
return day.weekday() < 5
def previous_business_day(
today: date | None = None, calendar: BusinessCalendar | None = None
) -> date:
"""Дата отчёта по умолчанию — предыдущий рабочий день (в Excel —
WORKDAY.INTL по списку праздников)."""
calendar = calendar or BusinessCalendar()
day = (today or date.today()) - timedelta(days=1)
while not calendar.is_business_day(day):
day -= timedelta(days=1)
return day