Finaim
Finaim Умные инвестиции
Документация

Методика расчётов

Полное описание математических алгоритмов, используемых на платформе Finaim для оптимизации портфелей, оценки риска, профилирования инвестора и скоринга непубличных компаний.

Оптимизация портфеля по Марковицу

Алгоритм CLA + EfficientFrontier (PyPortfolioOpt)

Mean-Variance оптимизация

Основа платформы — классическая теория Марковица (1952). Для заданного набора активов строится портфель, максимизирующий ожидаемую доходность при фиксированном уровне риска (волатильности), либо минимизирующий риск при заданной доходности. Математически задача решается квадратичным программированием:

Целевая функция (максимизация коэффициента Шарпа):

max [ (wᵀ μ - r_f) / sqrt(wᵀ Σ w) ]

где: w — вектор весов активов (сумма = 1)

μ — вектор ожидаемой годовой доходности (mean_historical_return)

Σ — ковариационная матрица (sample_cov из исторических цен)

r_f — безрисковая ставка (по умолчанию 2% годовых)

Ожидаемая доходность и ковариация

Ожидаемая доходность актива μ_i вычисляется как среднее арифметическое дневных логарифмических доходностей, аннуализированное умножением на 252 (торговых дня в году). Ковариационная матрица Σ строится методом выборочной ковариации по историческим ценам закрытия (скорректированным на дивиденды и сплиты), получаемым через yfinance или MOEX ISS API.

Critical Line Algorithm (CLA)

Для построения эффективной границы используется алгоритм Critical Line Algorithm (Wolfe, 1959) — точный аналитический метод, итерирующий по угловым портфелям (corner portfolios), что обеспечивает точную эффективную границу без численных артефактов. CLA возвращает массив пар (volatility, expected_return) для визуализации в d3.js.

Ограничения на веса

Система поддерживает три типа ограничений на веса активов:

  • Фиксированный вес (fixed): актив принудительно включается с заданной долей, ограничения вверх и вниз одновременно равны заданному значению.
  • Минимальный вес (min_weight): нижняя граница доли актива в портфеле.
  • Максимальный вес (max_weight): верхняя граница доли актива в портфеле.

Случайные портфели (Dirichlet-выборка)

Для фонового облака «возможных портфелей» на графике генерируется 300 случайных наборов весов из симметричного распределения Дирихле: w ~ Dirichlet(1_N), что равномерно покрывает стандартный симплекс. Для каждого случайного портфеля вычисляются доходность и волатильность.

Расчёт метрик риска и доходности

Sharpe, Sortino, Max Drawdown, корреляции

Коэффициент Шарпа

Sharpe = (R_p - r_f) / σ_p
где R_p — ожидаемая годовая доходность портфеля
r_f — безрисковая ставка
σ_p = sqrt(wᵀ Σ w) — годовая волатильность портфеля

Вычисляется на основе оптимальных весов через PyPortfolioOpt.

Коэффициент Сортино

Модификация Шарпа, учитывающая только нисходящий риск (downside deviation):

Sortino = (R_p - r_f) / σ_d
где σ_d = sqrt(252) * std( min(r_t - r_f/252, 0) )
r_t — дневная доходность портфеля
Усредняется по дням, когда r_t - r_f/252 < 0

Максимальная просадка (Max Drawdown)

cum_t = ∏(1 + r_τ) для τ = 1..t
running_max_t = max(cum_1, ..., cum_t)
drawdown_t = cum_t / running_max_t - 1
Max DD = min(drawdown_t)

Накопленная стоимость портфеля строится как произведение (1 + дневная доходность). Просадка — процентное отклонение от текущего исторического максимума. Max DD — минимальное (наихудшее) значение просадки за весь период.

Корреляционная матрица

Матрица попарных коэффициентов корреляции Пирсона строится по дневным доходностям активов. Визуализируется в виде тепловой карты (heatmap) в d3.js с диапазоном цветов от –1 (красный) до +1 (синий).

Периодическая доходность (30d / YTD / 1y)

Для каждого периода берётся цена закрытия на начало периода и текущая цена. Взвешенная доходность портфеля:

P(t) = ∑_i w_i * (price_i(t) / price_i(t_0))
return = P(T) / P(t_cutoff) - 1

Результаты кешируются в памяти на 30 минут (TTL cache с ключом MD5 по тикерам и весам).

Профилирование инвестора

5 вопросов → риск-балл 1–10 → тип портфеля

Анкета

Инвестор отвечает на 5 вопросов, каждый с 4 вариантами (балл 1–4):

  1. Горизонт инвестирования — от «менее 1 года» (1) до «более 7 лет» (4)
  2. Допустимая просадка — от «до −5%» (1) до «более −30%» (4)
  3. Цель инвестирования — от «сохранение капитала» (1) до «максимальный рост» (4)
  4. Опыт на финансовых рынках — от «нет опыта» (1) до «более 5 лет» (4)
  5. Аппетит к непубличным компаниям — от «только биржа» (1) до «свыше 20%» (4)

Формула скоринга

raw = h + d + g + e + pa (сумма баллов: 5..20)
scaled = round((raw - 5) * 10 / 15) + 1 (нормализация → 1..10)

Итоговый балл от 1 до 10 интерпретируется как уровень риск-толерантности.

Тип портфеля (Tier)

Балл Тип Ожидаемая доходность Волатильность
1–4 Консервативный 4–6% год. 5–8%
5–7 Сбалансированный 7–10% год. 10–14%
8–10 Агрессивный 12–18% год. 18–25%

На основе типа формируется рекомендованная корзина инструментов: для консервативного — облигации (IEF, TLT), золото (GLD) и защитные акции; для агрессивного — технологические мега-капиталы (NVDA, META, GOOGL) с возможной долей pre-IPO до 20%.

Snowflake-анализ публичных компаний

5 осей, оценка 0–6 по каждой (источник: yfinance)

Каждая американская компания оценивается по пяти осям в стиле Simply Wall St. По каждой оси алгоритм присваивает балл от 0 до 6. Финальный «снежинок» визуализируется как радарная диаграмма в d3.js.

Стоимость (Value)

P/E, P/B, P/S — чем ниже мультипликатор, тем выше балл. Используется функция bucket с порогами и флагом reverse=True.

P/E < 10 → 6, < 15 → 5, ..., > 50 → 0

Перспективы (Future)

earningsGrowth и revenueGrowth (YoY прогноз). Чем выше темп роста, тем выше балл.

EPS growth > 40% → 6, > 25% → 5...

Прошлое (Past)

ROE, ROA, profitMargins — историческое качество прибыльности.

ROE > 30% → 6, > 20% → 5...

Здоровье (Health)

Debt/Equity (reverse: ниже — лучше), currentRatio и quickRatio — устойчивость баланса.

D/E < 10 → 6, currentRatio > 3 → 6

Дивиденды (Dividends)

dividendYield, payoutRatio (оптимум ~40%), fiveYearAvgDividendYield. Коэффициент выплат оценивается через параболическую нормировку: пик при payout=40%.

pr_norm = max(0, 1 - |payout - 0.4| * 2)

Итоговый балл каждой оси — среднее арифметическое доступных компонентов (с округлением). Общий суммарный балл Snowflake — сумма пяти осей (максимум 30). Для MOEX-тикеров Snowflake не строится (данные фундаменталов через публичные API ненадёжны).

SHAP-скоринг непубличных компаний

CatBoost + SHAP values (11 признаков)

Модель

Для непубличных компаний (стартапов, pre-IPO) используется бинарный классификатор CatBoostClassifier, обученный на данных Crunchbase. Целевая переменная: 1 — компания успешно развивается / вышла на IPO / приобретена, 0 — ликвидирована или закрыта.

Признаки (11 features)

Числовые (8):

  • founded_year — год основания
  • age_years — возраст компании
  • funding_rounds — число раундов финансирования
  • funding_total_usd — суммарное финансирование ($)
  • milestones — число ключевых вех
  • relationships — число деловых связей
  • investment_rounds — участие компании в инвестициях
  • invested_companies — число проинвестированных компаний

Категориальные (3):

  • country_code — страна регистрации
  • category_code — отрасль
  • state_code — штат/регион (для США)

SHAP-объяснение

После получения предсказания success_probability = P(класс=1) (CatBoost predict_proba) для каждого признака вычисляется значение SHAP (SHapley Additive exPlanations) с помощью shap.TreeExplainer. SHAP-значение показывает вклад каждого признака в отклонение предсказания от базового значения (base_value = E[f(x)]).

f(x) = base_value + ∑_i SHAP_i(x)
SHAP_i > 0 — признак увеличивает вероятность успеха
SHAP_i < 0 — признак снижает вероятность успеха

В интерфейсе отображаются топ-8 признаков по |SHAP_i|, отсортированных по убыванию абсолютного вклада.

Семантический анализ описания компании

Sentence-transformers + центроиды Crunchbase

Алгоритм

Текстовое описание компании (минимум 30 символов) преобразуется в плотный вектор-эмбеддинг с помощью многоязычной модели paraphrase-multilingual-MiniLM-L12-v2 из библиотеки sentence-transformers. Размерность вектора — 384.

Центроиды классов

В процессе предобучения (offline) по корпусу Crunchbase вычисляются два центроида:

c_success = mean( embed(desc_i) ) для успешных компаний
c_failure = mean( embed(desc_j) ) для закрытых компаний
Оба центроида L2-нормализованы и сохранены в semantic_centroids.npz

Скоринг нового описания

v = embed(text) / ||embed(text)|| (L2-нормализация)
sim_success = dot(v, c_success) (косинусное сходство)
sim_failure = dot(v, c_failure)
success_lift = sim_success - sim_failure
verdict = "успех" если success_lift > 0 else "риск"

Результат включает числовые значения сходства с обоими центроидами и итоговый вердикт. Функция кешируется через lru_cache на уровне загрузки модели и центроидов.

Месячное ранжирование акций (прогноз модели)

Кросс-секционный ранжировщик LightGBM · своя модель на каждый рынок · по Zhang (ICIAAI 2025)

Это число стоит за строкой «Прогноз модели на месяц» в карточке актива. Модель кросс-секционная: она не предсказывает, куда пойдёт рынок, — она ранжирует бумаги одного рынка между собой на ближайший месяц. У рынка США, российского рынка (MOEX) и еврозоны свои модели, обученные и измеренные отдельно: z-оценка осмысленна только внутри одной валюты и одного торгового календаря.

Признаки

Одиннадцать месячных признаков строятся из дневных баров, и каждый использует данные не позже последнего торгового дня месяца t: импульс за 1 месяц и за 12-2 месяца, изменение полугодового импульса, реализованная волатильность внутри месяца и за 252 дня, максимальная дневная доходность месяца, расстояние до 52-недельного максимума, изменение объёма торгов, логарифм среднего дневного оборота, коэффициент неликвидности Амихуда и прокси размера (логарифм среднего оборота за 252 дня — не капитализация, для которой нужна история числа акций, которой у нас нет).

Нормализация

для каждого месяца t: z = (x - mean_t(x)) / sd_t(x)
винзоризация по 1-му / 99-му перцентилю этого месяца, затем отсечение до ±5

Нормализация — внутри месяца, никогда не по времени: модель сравнивает бумаги друг с другом, а не сегодняшний рынок с рынком 2016 года.

Отбор признаков

Каждый признак оценивается t-статистикой его месячного rank IC (корреляция Спирмена между признаком и доходностью следующего месяца), посчитанной только на обучающих месяцах; среднее |SHAP| разрешает ничьи. В финальную модель идут пять лучших. Отбор по одному SHAP награждает то, по чему модель случайно делила выборку, а на шумном месячном таргете это не то же самое, что предсказательная сила.

Обучение

Регрессия LightGBM (MSE) на доходность следующего месяца. Последняя пятая часть обучающих месяцев откладывается, чтобы ранней остановкой выбрать число деревьев, после чего модель переобучается на всём окне с этим числом (но не меньше 60): месячные доходности почти целиком шум, и иначе остановка срабатывает на одном-двух деревьях — модель, выдающая горстку разных значений на сотни бумаг, ничего не ранжирует.

Walk-forward проверка

для каждого месяца t после начального окна:
  обучение только на строках с месяцем < t
  ранжируем срез месяца t, берём топ-N равными долями, держим один месяц

Отсутствие заглядывания в будущее доказывается, а не декларируется: пайплайн пересчитывает признаки с обрезанным будущим и требует побитового совпадения, требует исчезновения таргета при удалении месяца t+1 и независимо пересчитывает каждый таргет.

Умение или везение?

Доходность сама по себе на это не отвечает, поэтому каждая модель сообщает ещё средний месячный rank IC с t-статистикой, спред между верхним и нижним децилями, оборот и ряд с учётом издержек (10 б.п. за сторону), а также рандомизационный тест: тот же размер портфеля, набранный случайно, тысячи раз — чтобы увидеть, где в этом распределении оказывается результат модели. Числа по модели, обслуживающей конкретный рынок, лежат в её метаданных и показаны в блоке «Как это считается» на скринере портфеля.

Ограничения

Вселенная — сегодняшний состав индекса, применённый к истории задним числом: survivorship bias, который завышает и стратегию, и бенчмарк. Заголовочные метрики не учитывают транзакционные издержки (ряд с их учётом приводится рядом). Sharpe считается при безрисковой ставке 0%. Прогноз — точечная оценка с широкой неопределённостью на горизонте одного месяца и не является инвестиционной рекомендацией.