DRRK/app/ui/pages/market_data.py

104 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from datetime import date
import streamlit as st
from app.services import fx_rates as fx_rates_service
from app.services import market_data as market_data_service
from app.services.dates import previous_business_day
from app.services.fx_rates import FxRatesUpdateResult
from app.services.market_data import MarketDataUpdateResult
from app.ui.common import as_table, call_db, current_user
_QUOTE_COLUMNS = {
"isin": "ISIN",
"name": "Наименование",
"board": "Режим",
"clean_price": "Чистая цена, %",
"clean_price_source": "Источник цены",
"yield_value": "Доходность, %",
"yield_source": "Источник доходности",
"duration_days": "Дюрация, дн.",
"accrued_interest": "НКД",
"face_value": "Номинал (тек.)",
"coupon_rate": "Купон, %",
"num_trades": "Сделок",
"volume": "Объём, шт.",
}
_RATE_COLUMNS = {
"rate_date": "Дата",
"nominal": "Номинал",
"rate": "Курс ЦБ",
"rate_per_unit": "За 1 CNY",
}
def render() -> None:
st.header("Рыночные данные")
on_date: date = st.date_input(
"Дата",
value=previous_business_day(),
max_value=date.today(),
format="DD.MM.YYYY",
)
# Внешние API — только по кнопке; ниже экран читает только БД.
quotes_col, fx_col = st.columns(2)
if quotes_col.button("Обновить котировки", use_container_width=True):
with st.spinner("Запрос котировок MOEX…"):
result = call_db(
market_data_service.update(on_date, current_user()),
"Не удалось обновить котировки",
)
if result is not None:
_show_market_result(result)
if fx_col.button("Обновить курс CNY", use_container_width=True):
with st.spinner("Запрос курса ЦБ…"):
fx_result = call_db(
fx_rates_service.update(on_date, current_user()),
"Не удалось обновить курс CNY",
)
if fx_result is not None:
_show_fx_result(fx_result)
st.subheader(f"Котировки на {on_date:%d.%m.%Y}")
quotes = call_db(
market_data_service.list_for_date(on_date), "Не удалось загрузить котировки"
)
if quotes:
st.dataframe(as_table(quotes, _QUOTE_COLUMNS), hide_index=True)
elif quotes is not None:
st.info("За эту дату котировок в базе нет.")
st.subheader("Курс CNY (последние)")
rates = call_db(fx_rates_service.list_recent(10), "Не удалось загрузить курсы")
if rates:
st.dataframe(as_table(rates, _RATE_COLUMNS), hide_index=True)
elif rates is not None:
st.info("Курсов CNY в базе пока нет.")
def _show_market_result(result: MarketDataUpdateResult) -> None:
summary = (
f"Обновлено: {result.updated}, без торгов: {result.no_trades}, "
f"ошибок: {result.errors}."
)
if result.errors:
st.error(summary)
elif result.no_trades:
st.warning(summary)
else:
st.success(summary)
with st.expander("Подробности по бумагам", expanded=bool(result.errors)):
for message in result.messages:
st.write(f"- {message}")
def _show_fx_result(result: FxRatesUpdateResult) -> None:
show = st.error if not result.ok else st.success
for message in result.messages:
show(message)