Приложение заменяет Google-таблицу для учёта портфеля: тикеры, живые цены, классы активов и подклассы с целевыми долями.
cd portfolio-tracker
pip install -r requirements.txt
streamlit run app/main.pyОткроется браузер с интерфейсом на русском.
- Сводка портфеля: класс, подкласс, тикер, цена (по API), количество и стоимость суммарно по тикеру (все места хранения сложены). Вкладка «По местам хранения» — одна строка на тикер, дальше столбец на каждое место из справочника (остаток или «—»), затем Всего и Цена в валюте отображения. Кнопка «Обновить цены сейчас» в сводке делает полный перезапуск страницы.
- Классы активов: в интерфейсе задаются только подклассы (% от всего портфеля). Доля класса в БД хранится как сумма подклассов и пересчитывается при сохранении подкласса и при старте (
reconcile_asset_class_targets), чтобы не было расхождений. Стартовая матрица на 100% — константыASSET_SUBCLASS_DEFAULT_ROWS(и ожидаемые суммы по классам) вapp/db.py; при первом запуске выполняется однократная миграцияapply_allocation_user_sheet_migration()(таблица_schema_migrations). Чтобы применить обновлённые константы к уже мигрированной БД, удалите строкуallocation_user_sheet_2025из_schema_migrationsи перезапустите приложение. - Тикеры и классы (опционально): переопределить подкласс для тикера; иначе при сделке используется автоопределение (
subclass_inference.py) и при необходимости дефолт (PORTFOLIO_DEFAULT_SUBCLASS). - Покупка / продажа: тикер (selectbox + «Новый тикер…» или ввод), место хранения так же — selectbox из локальной базы и «Новое место…». Продажа — с выбранной строки «тикер + место». Для акций и ETF количество целое; для криптовалют (BTC, ETH, SOL, … —
COINGECKO_IDSвapp/services/prices.py) допускаются дроби. - Ребалансировка (только покупки): вкладка в боковой панели — сумма новых средств в валюте отображения; расчёт долей по целевым % подклассов, затем разбивка внутри подкласса пропорционально текущей стоимости тикеров с котировкой. Продажи не учитываются. Логика в
app/services/rebalancing.py. - Доходность портфеля (MWR/XIRR + TWR): во вкладке «Доходность» главная метрика — MWR (XIRR, годовая); TWR отображается как дополнительная справочная метрика. История бэкофилится от первой сделки по историческим котировкам (Yahoo / MOEX / CoinGecko) и кэшируется в SQLite (
historical_quotes) для ускорения повторных запусков. - Источник цен подбирается автоматически (США/мир → Yahoo Finance, РФ → MOEX ISS, крипта → CoinGecko).
python -m unittest tests.test_rebalancing -v
python -m unittest tests.test_performance -vНужен Streamlit ≥ 1.35 (фрагменты с run_every).
- Курсы в сайдбаре обновляются в фоне примерно каждые 60 с (API open.er-api.com; при ошибке — запасные значения).
- Цены в сводке портфеля перезапрашиваются каждые ~30 с без кэша (осторожно с лимитами Yahoo/CoinGecko при большом числе тикеров). Кнопка «Обновить цены сейчас» делает полный перезапуск страницы.
- Котировки MOEX в ₽, Yahoo/CoinGecko в USD, затем пересчёт в выбранную валюту отображения.
По умолчанию SQLite: файл data/portfolio.db в корне проекта. Путь можно задать переменной окружения PORTFOLIO_DB. Справочник мест хранения — таблица storages; в каждой сделке (transactions) указывается storage_id. Новые названия мест добавляются в интерфейсе покупки («Новое место…») или вручную в БД. При старте в БД дописываются недостающие имена из списка по умолчанию (Interactive Brokers, Тинькофф, Bybit, кошельки и т.д. — см. DEFAULT_STORAGE_NAMES_ORDERED в app/db.py).
| Тикеры | API |
|---|---|
| США / мировые ETF (VOO, QQQ, VXUS, …) | Yahoo Finance (yfinance) |
| РФ / MOEX (TMOS, SBGB, SBRB, TGLD, …) | MOEX ISS |
| Крипта (BTC, ETH, SOL, …) | CoinGecko |
Цены кэшируются в сессии на 2 минуты. Для смены источника цен можно добавить запись в таблицу instruments (поле provider: yfinance, moex_iss, coingecko).