Помощник ребалансировки портфеля для частных инвесторов
Подсказывает, какие бумаги докупить на свободный кэш, чтобы текущий портфель приближался к целевому распределению весов.
Targetfolio решает одну боль регулярного инвестора: пополнил счёт — и хочется потратить кэш так, чтобы портфель приблизился к целевой стратегии по весам, а не сломал её. В Тинькове такого инструмента нет, и считать руками или в Excel — медленно и легко ошибиться.
Приложение работает целиком в браузере, без бэкенда. Никакие данные не отправляются наружу, токены и портфели хранятся только локально.
- 📊 Текущий портфель. Загрузка через демо-фикстуру, ручной ввод или импорт из T‑Invest по read‑only токену.
- 🎯 Целевой портфель. Задание весов в процентах с цветовой подсказкой по сумме (зелёный = 100%, янтарный = 95–105%, красный — иначе) и набор готовых пресетов.
- 🤖 Рекомендации. Greedy‑алгоритм считает, какие лоты докупить на введённый кэш, чтобы сократить отклонение от таргета. Учитывает целочисленность лотов и
lotSize. - 💾 Persistence. Целевой портфель, пользовательский реестр инструментов, источник, опционально — токен T‑Invest, сохраняются в
localStorage. - 🔗 Sharable URL. Состояние таргета, ручного портфеля и суммы кэша синхронизируются в query‑строку — ссылку можно скинуть себе или сохранить.
- 🌗 Темы. Светлая и тёмная, переключается в шапке.
| Слой | Выбор |
|---|---|
| Framework | Vue 3 (Composition API, <script setup>) |
| Build | Vite |
| Language | TypeScript (strict) |
| State | Pinia + pinia-plugin-persistedstate |
| Routing | vue-router (для query‑sync) |
| UI | shadcn-vue + Tailwind CSS v4 |
| Иконки | lucide-vue-next |
| Тесты | Vitest (jsdom) |
| Lint/Format | oxlint + oxfmt |
| Менеджер пакетов | pnpm |
| Деплой | Docker + Caddy на Railway |
pnpm install
pnpm devДальше открой http://localhost:5173 — встретит демо‑портфель и пустой таргет.
pnpm dev # dev‑сервер с HMR
pnpm build # типчек + продакшн‑сборка в dist/
pnpm preview # локальный preview собранного билда
pnpm test # vitest в watch‑режиме
pnpm test:run # vitest однократно
pnpm test:coverage # покрытие
pnpm lint # oxlint
pnpm format # oxfmt
pnpm typecheck # vue-tsc --noEmitsrc/
domain/ чистая логика (calculateBuys, валидация). Без Vue/Pinia
stores/ Pinia: portfolio, target, rebalance
components/ секции UI + shadcn-vue в components/ui/
composables/ URL‑sync, пагинация, breakpoints
fixtures/ демо‑портфель
lib/ утилиты (cn, кодеки query‑строки и т.п.)
public/ favicon
scripts/ вспомогательные node‑скрипты (каталог инструментов, индексы)
В корне есть Dockerfile и Caddyfile под рекомендованный Railway‑рецепт:
- multi‑stage сборка:
node:lts-alpineставит pnpm через corepack и собирает Vite‑бандл, - финальный stage на
caddy:alpineотдаётdist/с gzip и SPA‑fallback наindex.html, - Caddy слушает
:{$PORT:3000}— Railway сам подставит порт.
Локальная проверка:
docker build -t targetfolio .
docker run --rm -p 3000:3000 targetfolio