WLM1ke / poptimizer

Оптимизация долгосрочного портфеля акций
The Unlicense
151 stars 28 forks source link

Как принудительно переобучить все имеющиеся модели для обновленного набора тикеров? #70

Closed RomaKoks closed 2 years ago

RomaKoks commented 2 years ago

Запуск эволюции не совсем выход, так как основная цель - переобучить имеющиеся модели (а не искать параметры для новых) и обновить их показатели "качества" на обновленном наборе. Грубо говоря, как сделать переинициализацию, но не случайным образом, а с текущими параметрами моделей.

WLM1ke commented 2 years ago

Если набор тикеров изменился, то на следующий торговый день начнется переобучение. Поэтому я обычно стараюсь вечером менять список тикеров. Какого-то простого способа форсировать переобучение нет.

RomaKoks commented 2 years ago

Прошло 2 торговых дня с момента изменения набора тикеров, старые модели так и не переобучились. Если простого способа нет, какой сложный?

WLM1ke commented 2 years ago

Не очень понятно, что у вас конкретно происходит.

У вас всего сколько моделей? Ни одна модель не переобучилась?

WLM1ke commented 2 years ago

Я видел, вы свой форк ведете - может проблема, что вы как-то не совсем правильно свои патчи налагаете.

RomaKoks commented 2 years ago

У вас всего сколько моделей?

Организмов - 198 / Максимум оценок - 15

Ни одна модель не переобучилась?

Точно сказать не могу, но есть модели с обновленным набором тикеров, а также есть со старым и они как-то существуют одновременно, эволюции это не мешает...

Основное отличие в том форке - оптимизация нескольких портфелей с различными ограничениями на используемые тикеры. Например, часть портфелей содержит только дивидендные акции / только иностранные, а другие все вместе взятые. Сначала я попробовал реализовать эти ограничения на этапе обучения моделей, но потом, когда вы сказали, что просто их не переобучить не получится - перенёс эти ограничения на этап формирования рекомендаций. Так что сейчас модели обучаются на всех тикерах из всех портфелей, но старые модели, обученные на ограниченном наборе, выдают ошибки типа:

Forecasts: 198it [00:00, 763.28it/s]
Traceback (most recent call last):
  File "PATH_TO/poptimizer/optimize.py", line 12, in opt
    optimize(ports_to_optimize, ports_wht_lst)
  File "PATH_TO/poptimizer/poptimizer/__main__.py", line 28, in optimize
    opt = Optimizer(port, white_list_portfolio=white_list_portfolio)
  File "PATH_TO/poptimizer/poptimizer/portfolio/optimizer.py", line 31, in __init__
    self._metrics = metrics.MetricsResample(portfolio)
  File "PATH_TO/poptimizer/poptimizer/portfolio/metrics.py", line 154, in __init__
    for forecast in evolve.get_forecasts(tickers, date):
  File "PATH_TO/poptimizer/poptimizer/evolve/forecaster.py", line 142, in get_forecasts
    return cache()
  File "PATH_TO/poptimizer/poptimizer/evolve/forecaster.py", line 98, in __call__
    return self._create_cache()
  File "PATH_TO/poptimizer/poptimizer/evolve/forecaster.py", line 116, in _create_cache
    forecasts = Forecasts(self._tickers, self._date)
  File "PATH_TO/poptimizer/poptimizer/evolve/forecaster.py", line 34, in __init__
    raise population.ForecastError(f"Отсутствуют прогнозы - необходимо обучить модели. SymDiff: {diff}")
poptimizer.evolve.population.ForecastError: Отсутствуют прогнозы - необходимо обучить модели. SymDiff: {'TCSG', 'AVGO-RM', 'TGKN', 'KMAZ', 'NEE-RM', 'SMLT', 'NEM-RM', 'NKNC', 'BANE', 'CHMK', 'SBRB', 'AMEZ', 'BA-RM', 'CSCO-RM', 'MDMG', 'PFE-RM', 'KZOS', 'MTLR', 'FB-RM', 'POGR', 'F-RM', 'LSNGP', 'NVTK', 'QIWI', 'FDX-RM', 'FIVE', 'LNZLP', 'MGTS', 'SNGS', 'NKNCP', 'NSVZ', 'T-RM', 'TATNP', 'RTKMP', 'ABRD', 'CHMF', 'CNTL', 'NKE-RM', 'TATN', 'ISKJ', 'YAKG', 'KAZT', 'KLSB', 'ATVI-RM', 'LNZL', 'RBCM', 'IBM-RM', 'LIFE', 'TGT-RM', 'SVAV', 'TGKBP', 'YNDX', 'TRNFP', 'BMY-RM', 'AMZN-RM', 'HPQ-RM', 'MSTT', 'ENPG', 'XOM-RM', 'MRSB', 'HIMCP', 'ZILL', 'RUGR', 'NVDA-RM', 'GOOG-RM', 'MU-RM', 'EA-RM', 'UNAC', 'BSPB', 'TSLA-RM', 'OGKB', 'GE-RM', 'LSNG', 'MRKC', 'APTK', 'CRM-RM', 'AFLT', 'BELU', 'EELT', 'GAZP', 'ALRS', 'QCOM-RM', 'WMT-RM', 'MAIL', 'RSTI', 'TGKB', 'BIDU-RM', 'RASP', 'SBER', 'OZON', 'INTC-RM', 'LNTA', 'SFIN', 'FESH', 'VTBB', 'SBERP', 'SELG', 'KHC-RM', 'LSRG', 'NFLX-RM', 'RSTIP', 'ORUP', 'NKHP', 'MTLRP', 'USBN', 'TWTR-RM', 'ABT-RM', 'UWGN', 'AMD-RM', 'MRKS', 'VTBM', 'FEES', 'BRZL', 'BIIB-RM', 'CNTLP', 'HHRU', 'PG-RM', 'VTBR', 'RUAL', 'IRAO', 'AFKS', 'MRKP', 'AKRN', 'KRSB', 'VTRS-RM', 'ENRU', 'AAPL-RM', 'TGKA', 'FXRU', 'ADBE-RM', 'MSRS', 'UNKL', 'UBER-RM', 'MSFT-RM', 'GTRK', 'CBOM', 'VSMO', 'JNJ-RM', 'MCD-RM', 'GMKN', 'PYPL-RM', 'DIS-RM', 'RTKM', 'KRKNP', 'PLZL', 'AQUA', 'RNFT', 'ROSN', 'ABBV-RM', 'RGSS', 'ROLO', 'INGR', 'NFAZ', 'LKOH', 'TGKD', 'FXRB', 'V-RM', 'SBUX-RM', 'AAL-RM', 'NLMK', 'FXMM'}

И по прошествии нескольких дней ситуация не исправилась. Таким образом, мне нужно один раз всё-таки пройти этот сложный процесс переинициализации, так как с холодного старта всё теперь работает нормально.

Каких-то функциональных изменений в этап обучения я не вносил, изменения есть лишь в процессе формирования рекомендаций, но и они не существенны. Могу попробовать оформить как PR, там будут видно различие.

WLM1ke commented 2 years ago

Точно сказать не могу, но точно есть модели с обновленным набором тикеров, а также очень много со старым и они как-то существуют одновременно, эволюции это не мешает...

Процесс переобучения достаточно долгий, особенно если есть много моделей. Он вполне может идти несколько дней, и в это время будут существовать стратегии со старым и новым набором. В это время должно в первую очередь идти переобучение и не должны создаваться новые модели. Прогноз будет делаться по уже переученным моделям - их достаточно буквально двух, чтобы оптимизация проработала без ошибок (другое дело, что им лучше не пользоваться). Если у вас падает с ошибками, то где-то вкралась ошибка в коде - думаю в вашем патче.

Можете прислать скрин одного выполненного шага эволюции? Это позволит понять, правильно ли все у вас идет обучение - переучиваются старые модели, а не создаются новые.

Каких-то функциональных изменений в этап обучения я не вносил, изменения есть лишь в процессе формирования рекомендаций, но и они не существенны. Могу попробовать оформить как PR, там будут видно различие.

Тут есть тонкости, которые вы могли не учесть. Прогноз должен делаться по тем же тикерам, которые использовались в обучении. Какая-то фильтрация отображения должна выполняться после этого.

WLM1ke commented 2 years ago

Из вашего PR мало чего понятно. Многое зависит от того, как вы все это запускаете.

Ключевой момент - эволюция должна запускаться ровно с тем же набором тикеров, что и MetricsResample. Постарайтесь как-то понять, какие у вас наборы туда приходят. Ниже ссылки на соотвествующие строки в моем коде.

https://github.com/WLM1ke/poptimizer/blob/5fcbd74f9102eaad8be7468ba99300f9319d5192/poptimizer/evolve/evolve.py#L81

https://github.com/WLM1ke/poptimizer/blob/5fcbd74f9102eaad8be7468ba99300f9319d5192/poptimizer/portfolio/optimizer.py#L24

Если это не так, то будет падать с ошибкой.

RomaKoks commented 2 years ago

Процесс переобучения достаточно долгий, особенно если есть много моделей.

Понял.

Можете прислать скрин одного выполненного шага эволюции? Это позволит понять, правильно ли все у вас идет обучение - переучиваются старые модели, а не создаются новые.

Небольшое видео, так как окно достаточно маленькое и много сообщений от mongodb https://yadi.sk/i/lf9h6i8BhGf5Hg

Постарайтесь как-то понять, какие у вас наборы туда приходят.

Посмотрел, да, ошибка была в том, что набор был неполным. Спасибо!

WLM1ke commented 2 years ago

Судя по ролику у вас идет именно переобучение - в этой части все окей.

RomaKoks commented 2 years ago
***2021-11-23: Шаг эволюции — 210***
LLH - (0.7452, 2.5894, 2.7491)
RET - (0.2295, 0.3055, 1.7552)
Организмов - 199 / Максимум оценок - 16
Доля принятых - 9.97%

Я правильно понимаю, что на данном этапе все модели должны были переобучиться?

WLM1ke commented 2 years ago

Вроде да, при обычном течении процесса. Если вы там как-то нестандартно вмешивались в процесс, то всякое может быть.

Понять это можно, посмотрев на вторую модель в шаге - претендента. У нового пустой заголовок и соответствующая пометка:

Претендент - новый организм: LLH — - RET — - Timer — 0:00:00

У переобучающегося организма, должны быть данные о прошлых тренировках без пометки, что он новый:

Претендент: LLH — 2.5586: 2.5785, 2.5983, 2.6087, 2.6236, 2.6274, 2.6250, 2.5815, 2.6052, 2.6697, 2.6943, 2.7326, 2.6525 RET — 1.0189: 0.6014, 0.7336, 0.8677, 1.1824, 0.8525, 0.8907, 1.2082, 0.9837, 0.6796, 0.6521, 0.7502, 0.8319 Timer — 0:03:15

RomaKoks commented 2 years ago

Да, теперь создаются новые, но при оптимизации получаются запредельные значения (3.42e+30) у матрицы ковариаций у части метрик (не у всех): https://yadi.sk/d/TRf27Do_gPvvwA https://github.com/WLM1ke/poptimizer/blob/5fcbd74f9102eaad8be7468ba99300f9319d5192/poptimizer/portfolio/metrics.py#L73 удаление forecasts не помогло.

WLM1ke commented 2 years ago

Возможно естественный отбор еще не убил заведомо дурацкие прогнозы - у вас достаточно не долго эволюция работала судя по максимальному количеству прогнозов.

По идее в оптимизации используется медиана именно для того, чтобы несколько совершенно неадекватных прогнозов не оказывало влияние на общую картину. Но у вас там как-то изменена логика - не знаю насколько хорошо она справляется с выбросами.

Удаление forecasts не поможет - если у вас есть неадекватные модели они снова выдадут неадекватные прогнозы. Нужно ждать их уничтожения.

RomaKoks commented 2 years ago

судя по максимальному количеству прогнозов

а сколько можно считать достаточным?

Но у вас там как-то изменена логика

она почти такая же, просто градиенты внутри прогноза одной модели преобразуются в квантили (что уже обеспечивает защиту от выбросов), после чего эти квантили усредняются по всем моделям.

WLM1ke commented 2 years ago

а сколько можно считать достаточным?

Не знаю, тут какого-то формального критерия нет. Если на глаз, то у вас популяция должна быть в пару раз больше целевой, а максимальное число проверок сопоставимо с длинной прогноза.

она почти такая же, просто градиенты внутри прогноза одной модели преобразуются в квантили (что уже обеспечивает защиту от выбросов), после чего эти квантили усредняются по всем моделям.

А как вы поняли, что у вас такие странные ковариационный матрицы?

RomaKoks commented 2 years ago

А как вы поняли, что у вас такие странные ковариационный матрицы?

По ворнингам при расчете, например, STD. NA получались, с которыми hmean из коробки работать не умеет.

PATH_TO/poptimizer/poptimizer/portfolio/metrics.py:90: RuntimeWarning: invalid value encountered in matmul
  beta = cov @ weight.reshape(-1, 1)
PATH_TO/poptimizer/poptimizer/portfolio/metrics.py:78: RuntimeWarning: invalid value encountered in matmul
  portfolio_var = weight.reshape(1, -1) @ cov @ weight.reshape(-1, 1)  # noqa: WPS221
PATH_TO/anaconda3/envs/finan/lib/python3.9/site-packages/numpy/lib/nanfunctions.py:1374: RuntimeWarning: All-NaN slice encountered
  r, k = function_base._ureduce(

И ворнингов было много, так как эти метрики рассчитываются каждый раз в оптимизационном цикле.