"""Остатки выпусков в портфелях на дату (D29).""" from __future__ import annotations from datetime import date import streamlit as st from app.services import positions from app.ui.common import as_table, call_db, default_report_date, download_xlsx _ALL = "все" _COLUMNS = { "portfolio": "Портфель", "name": "Бумага", "isin": "ISIN", "currency": "Валюта", "bought": "Куплено, шт", "sold": "Продано, шт", "balance": "Остаток, шт", } def render() -> None: st.header("Остатки") st.caption( "Остаток на конец дня: куплено минус продано по сделкам с датой сделки " "не позже выбранной. Купоны, амортизация и корректировки количество не " "меняют." ) portfolios = call_db(positions.list_portfolios(), "Не удалось загрузить портфели") if portfolios is None: return date_col, portfolio_col = st.columns(2) on_date: date = date_col.date_input( "Дата", value=default_report_date(), format="DD.MM.YYYY" ) portfolio = portfolio_col.selectbox( "Портфель", [_ALL, *portfolios], format_func=lambda c: c if c == _ALL else f"{c} — {portfolios[c]}", ) include_closed = st.checkbox("Показывать закрытые (остаток 0)") rows = call_db( positions.positions_on( on_date, None if portfolio == _ALL else portfolio, include_closed=include_closed, ), "Не удалось посчитать остатки", ) if rows is None: return if not rows: st.caption("Открытых позиций на эту дату нет.") return st.dataframe(as_table(rows, _COLUMNS), hide_index=True) suffix = "" if portfolio == _ALL else f"_{portfolio}" download_xlsx(rows, _COLUMNS, "Остатки", f"остатки{suffix}_{on_date:%Y%m%d}.xlsx") negative = [row for row in rows if row.balance < 0] if negative: names = ", ".join(f"{row.name} ({row.portfolio})" for row in negative) st.warning( f"Продано больше, чем куплено: {names}. Возможно, не загружены " "покупки за прошлые даты." )