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

В этой статье мы воспользуемся библиотекой FinRL для построения торгового агента на базе технического и фундаментального анализа. Мы объединим данные движения рынка и квартальной отчетности компаний, построим на их базе систему индикаторов и на ее основе поспробуем построить прогноз цены.

Для тех, кто захочет повторить представленный материал - исходный код и данные можно найти у меня на github'e.

Итак, продолжим наше знакомство с FinRL.

Постановка задачи

Мы будем обучать агента (Deep Reinforcement Learning - DRL) торговле акциями. Задача описывается как Марковский процесс принятия решений (MDP), и целевая функция состоит в максимизации (ожидаемой) накопленной доходности.

Определяем состояние-действие-награду следующим образом:

Состояние s: Пространство состояний представляет собой восприятие агентом среды рынка. Как трейдер-человек анализирует различную информацию, так и наш агент пассивно наблюдает множество признаков и учится взаимодействуя с рыночной средой (обычно путем воспроизведения исторических данных).

Действие a: Пространство действий включает разрешенные действия, которые агент может совершать в каждом состоянии. Например, a \in {-1, 0, 1}, где {-1, 0, 1}представляют собой {продажу, удержание, покупку} какой-либо позиции в портфеле. Когда действие касается нескольких акций, то a \in {-k, ...,-1, 0, 1, ..., k}, где например, "Покупка 10 акций AAPL" или "Продажа 10 акций AAPL" - это 10 или −10 соответственно.

Функция вознагражденияr(s, a, s') : Вознаграждение является стимулом для агента для изучения лучшей стратегии. Например, это может быть изменение стоимости портфеля при выполнении действия a в состоянии sи перехода в новое состояние s', т.е r(s, a, s')=v-v', где v и v' представляют собой значения портфеля в состояниях sи s' соответственно.

Рыночная среда: 30 акций, составляющих индекс Dow Jones Industrial Average (DJIA).

Данные по отдельной акции, которые мы будем использовать для этого примера, получены из API Yahoo Finance. Данные содержат цены открытия, максимальные, минимальные и закрытия, а также объем торгов.

Необходимые инструменты

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

Нам понадобятся загрузчик данных с Yahoo finance, служебные папки для сохранения результатов и перечень бумаг, входящих в индекс DOW30.

from finrl.meta.preprocessor.yahoodownloader import YahooDownloader
from finrl.main import check_and_make_directories
from finrl.config import (
  DATA_SAVE_DIR,
  TRAINED_MODEL_DIR,
  TENSORBOARD_LOG_DIR,
  RESULTS_DIR,
  INDICATORS,
  TRAIN_START_DATE,
  TRAIN_END_DATE,
  TEST_START_DATE,
  TEST_END_DATE,
  TRADE_START_DATE,
  TRADE_END_DATE)
from finrl.config_tickers import DOW_30_TICKER

Создадим необходимые директории и загрузим данные с yahoo fifnance:

check_and_make_directories([DATA_SAVE_DIR, TRAINED_MODEL_DIR, TENSORBOARD_LOG_DIR, RESULTS_DIR])
TRAIN_START_DATE = '2009-01-01'
TRAIN_END_DATE = '2019-01-01'
TEST_START_DATE = '2019-01-01'
TEST_END_DATE = '2021-01-01'

# загружаем данные
df = YahooDownloader(start_date = TRAIN_START_DATE,
                     end_date = TEST_END_DATE,
                     ticker_list = DOW_30_TICKER).fetch_data()

Преобразуем даты и отсортируем наш датафрейм по дате и коду бумаг:

df['date'] = pd.to_datetime(df['date'],format='%Y-%m-%d')
df.sort_values(['date','tic'],ignore_index=True).head()

Предобработка и обогащение данных

Для построения модели давайте обогатим наш датасет данными из квартальной отчетности компаний. Данные для составляющих индекса Dow Jones загружаем с WRDS (Wharton Research Data Services). Доступ к отчетности на этом ресурсе платный, но мы воспользуемся фрагментом в демонстрационных целях.

Данные, для этого примера вы можете найти в репозитории проекта в папке data. Они содержат информацию с 2009 по 2020 год.

fund = pd.read_csv('data/dow_30_fundamental_wrds.csv')

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

items = [
    'datadate',  # Дата
    'tic',       # Тикер
    'oiadpq',    # Квартальная операционная прибыль
    'revtq',     # Квартальные доходы
    'niq',       # Квартальная чистая прибыль
    'atq',       # Всего активов
    'teqq',      # Собственный капитал
    'epspiy',    # Прибыль на акцию (базовая), включая внештатные элементы
    'ceqq',      # Общий капитал
    'cshoq',     # Общее количество обыкновенных акций
    'dvpspq',    # Дивиденды на акцию
    'actq',      # Оборотные активы
    'lctq',      # Оборотные пассивы
    'cheq',      # Денежные средства и их эквиваленты
    'rectq',     # Дебиторская задолженность
    'cogsq',     # Себестоимость проданных товаров
    'invtq',     # Инвентарь
    'apq',       # Кредиторская задолженность
    'dlttq',     # Долгосрочные обязательства
    'dlcq',      # Задолженность по текущим обязательствам
    'ltq'        # Пассивы
  ]

Используя имеющиеся показатели, мы рассчитываем 15 дополнительных финансовых коэффициентов для отражения финансового состояния компаний. Список коэффициентов приведен ниже:

  • Коэффициенты прибыльности: Операционная маржа, Чистая маржа, Рентабельность собственного капитала, Рентабельность активов;

  • Коэффициенты ликвидности: Текущая ликвидность, Коэффициент наличности, Быстрая ликвидность;

  • Коэффициенты эффективности: Коэффициент оборачиваемости запасов, Коэффициент оборачиваемости кредиторской задолженности, Коэффициент оборачиваемости дебиторской задолженности;

  • Финансовые коэффициенты кредитного плеча: Коэффициент долга, Коэффициент долга к собственному капиталу;

  • Коэффициенты оценки рынка: P/E, P/B, Дивидендная доходность.

Нам необходимо рассчитать LTM (Последние двенадцать месяцев) для показателей из отчетов о прибылях и убытках, так как мы работаем с квартальными данными. Мы используем значения показателей из балансов, так как они представляют собой числа акций.

Например, мы хотим рассчитать ROE к концу третьего квартала в финансовом году 2018 года. В числителе мы суммируем данные о чистой прибыли за четыре квартала:

  • (Числитель ROE) = Чистая прибыль Q4 2017 года + Q1 2018 года + Q2 2018 года + Q3 2018 года

  • Мы используем количество собственного капитала в качестве знаменателя на конец Q3 2018 года. То есть, (Знаменатель ROE) = Собственный капитал на конец Q3 2018 года

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

Операционная маржа рассчитывается как отношение операционной прибыли к выручке и выражается в процентах.

Формула для расчета операционной маржи:

 \text{Operating Margin} = \frac{\text{Операционная прибыль}}{\text{Выручка}} \times 100\%

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

Чистая операционная маржа рассчитывается как отношение чистой прибыли к выручке и выражается в процентах.

Формула для расчета чистой операционной маржи:

 \text{Net Profit Margin} = \frac{\text{Чистая прибыль}}{\text{Выручка}} \times 100\%

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

Рентабельность активов (ROA) рассчитывается как отношение чистой прибыли к общей сумме активов и выражается в процентах.

Формула для расчета ROA:

 \text{Return On Assets (ROA)} = \frac{\text{Чистая прибыль}}{\text{Общая сумма активов}} \times 100\%

ROA показывает, сколько прибыли компания генерирует на каждый доллар активов. Этот показатель помогает инвесторам и аналитикам оценить эффективность использования активов компанией для генерации прибыли. Более высокие значения ROA указывают на более эффективное использование активов и, как следствие, на более высокую прибыльность компании.

Рентабельность собственного капитала (ROE) рассчитывается как отношение чистой прибыли к собственному капиталу и выражается в процентах.

Формула для расчета ROE:

 \text{Return On Equity (ROE)} = \frac{\text{Чистая прибыль}}{\text{Собственный капитал}} \times 100\%

ROE показывает, какую чистую прибыль компания генерирует на каждый доллар собственного капитала. Этот показатель помогает инвесторам и аналитикам оценить эффективность использования собственного капитала компанией для генерации прибыли. Более высокие значения ROE обычно указывают на более эффективное использование собственного капитала и, как следствие, на более высокую прибыльность компании.

Прибыль на акцию (EPS) рассчитывается как отношение чистой прибыли к общему количеству обыкновенных акций компании.

Формула для расчета EPS:

 \text{Earnings Per Share (EPS)} = \frac{\text{Чистая прибыль}}{\text{Общее количество обыкновенных акций}}

EPS показывает, сколько долларов чистой прибыли приходится на одну акцию компании. Этот показатель является важным для инвесторов и аналитиков при оценке прибыльности и стоимости акций компании.

Собственный капитал на акцию (Book Value Per Share) рассчитывается как отношение общего собственного капитала компании к общему количеству обыкновенных акций.

Формула для расчета Book Value Per Share:

 \text{Book Value Per Share} = \frac{\text{Собственный капитал}}{\text{Общее количество обыкновенных акций}}

Book Value Per Share показывает, сколько долларов собственного капитала приходится на одну акцию компании. Этот показатель используется для оценки стоимости акций и может служить важным индикатором при принятии инвестиционных решений.

Дивиденды на акцию (Dividends Per Share) рассчитываются как отношение общей суммы выплаченных дивидендов к общему количеству обыкновенных акций.

Формула для расчета Dividends Per Share:

 \text{Dividends Per Share} = \frac{\text{Общая сумма выплаченных дивидендов}}{\text{Общее количество обыкновенных акций}}

Dividends Per Share показывает, сколько долларов дивидендов выплачено на одну акцию компании. Этот показатель является важным для инвесторов, которые оценивают потенциальную доходность от дивидендов в связи с инвестициями в акции компании.

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

Наиболее распространенными коэффициентами ликвидности являются:

Коэффициент текущей ликвидности (Current Ratio):

 \text{Current Ratio} = \frac{\text{Оборотные активы}}{\text{Оборотные пассивы}}

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

Быстрый коэффициент ликвидности (Quick Ratio):

 \text{Quick Ratio} = \frac{\text{Оборотные активы} - \text{Запасы}}{\text{Оборотные пассивы}}

Этот коэффициент исключает запасы из оборотных активов, поскольку запасы могут быть менее ликвидными и могут быть труднее реализовать. Таким образом, Quick Ratio предоставляет оценку ликвидности компании без учета запасов.

Коэффициент абсолютной ликвидности (Absolute Liquidity Ratio):

 \text{Absolute Liquidity Ratio} = \frac{\text{Денежные средства и эквиваленты}}{\text{Оборотные пассивы}}

Этот коэффициент показывает, какая доля оборотных пассивов компании покрывается ее денежными средствами и эквивалентами. Он оценивает способность компании к немедленному погашению текущих обязательств.

Коэффициент денежной ликвидности (Cash Ratio):

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

 \text{Cash Ratio} = \frac{\text{Денежные средства и их эквиваленты}}{\text{Оборотные пассивы}}

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

Коэффициенты эффективности капитала

Коэффициент оборачиваемости запасов (Inventory Turnover Ratio) измеряет, сколько раз за определенный период времени компания обновляет свой инвентарь. Этот показатель помогает оценить эффективность управления запасами компании и их оборачиваемость.

Формула для расчета Inventory Turnover Ratio:

 \text{Inventory Turnover Ratio} = \frac{\text{Себестоимость проданных товаров}}{\text{Средний объем запасов}}

Где:

  • Себестоимость проданных товаров представляет собой затраты, связанные с производством или приобретением товаров, которые были реализованы за рассматриваемый период времени.

  • Средний объем запасов можно рассчитать как среднее арифметическое между начальным и конечным объемом запасов за период.

Высокий коэффициент оборачиваемости запасов обычно указывает на то, что компания эффективно управляет своим инвентарем, что может свидетельствовать о более здоровой финансовой позиции. Однако низкий коэффициент оборачиваемости запасов может указывать на проблемы с управлением запасами или на недостаточный спрос на товары компании.

Коэффициент оборачиваемости дебиторской задолженности (Receivables Turnover Ratio) измеряет, сколько раз за определенный период времени компания обновляет свою дебиторскую задолженность. Этот показатель помогает оценить эффективность управления кредитными отношениями компании и скорость взыскания долгов.

Формула для расчета Receivables Turnover Ratio:

 \text{Receivables Turnover Ratio} = \frac{\text{Выручка}}{\text{Средний объем дебиторской задолженности}}

Где:

  • Выручка представляет собой общий объем продаж компании за рассматриваемый период времени.

  • Средний объем дебиторской задолженности можно рассчитать как среднее арифметическое между начальным и конечным объемом дебиторской задолженности за период.

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

Коэффициент оборачиваемости кредиторской задолженности (Payable Turnover Ratio) измеряет, сколько раз за определенный период времени компания обновляет свою кредиторскую задолженность. Этот показатель помогает оценить эффективность управления кредиторскими отношениями компании и ее скорость выплаты долгов.

Формула для расчета Payable Turnover Ratio:

 \text{Payable Turnover Ratio} = \frac{\text{Себестоимость проданных товаров}}{\text{Средний объем кредиторской задолженности}}

Где:

  • Себестоимость проданных товаров представляет собой затраты, связанные с производством или приобретением товаров, которые были реализованы за рассматриваемый период времени.

  • Средний объем кредиторской задолженности можно рассчитать как среднее арифметическое между начальным и конечным объемом кредиторской задолженности за период.

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

Финансовые коэффициенты кредитного плеча используются для оценки уровня финансового долга компании и ее способности управлять им. Эти показатели позволяют инвесторам и кредиторам оценить финансовую устойчивость компании и ее риск в отношении обязательств.

Наиболее распространенные финансовые коэффициенты кредитного плеча включают:

Коэффициент финансового плеча (Debt-to-Equity Ratio):

\text{Debt-to-Equity Ratio} = \frac{\text{Общий долг}}{\text{Собственный капитал}}

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

Коэффициент финансовой нагрузки (Financial Leverage Ratio):

 \text{Financial Leverage Ratio} = \frac{\text{Общий долг}}{\text{Общие активы}}

Этот коэффициент показывает, какая часть активов компании финансируется за счет долга. Он помогает определить степень риска, связанного с использованием долгового финансирования.

Коэффициент краткосрочной ликвидности (Short-term Debt Ratio):

\text{Short-term Debt Ratio} = \frac{\text{Краткосрочный долг}}{\text{Общий долг}}

Этот коэффициент показывает, какая доля долга компании является краткосрочным. Он помогает оценить финансовую стабильность компании в краткосрочной перспективе.

Коэффициент капитализации долга (Debt Capitalization Ratio):

 \text{Debt Capitalization Ratio} = \frac{\text{Общий долг}}{\text{Общий долг} + \text{Собственный капитал}}

Этот коэффициент показывает, какая часть капитализации компании приходится на долг. Он помогает оценить, в какой степени компания зависит от долга для финансирования своей деятельности.

Эти коэффициенты обогатят наш анализ и внесут в него показатели финансовой отчетности компаний. Такой подход называется Фундаментальным анализом.

Ввиду того, что наши показатели рассчитываются по ряду значений часть из них в начале и в конце датафрейма оказалось не запоненными. Для корреткной работы модели эти значения необходимо или удалить или заполнить 0.

# Replace NAs infinite values with zero
final_ratios = ratios.copy()
final_ratios = final_ratios.fillna(0)
final_ratios = final_ratios.replace(np.inf,0)

Объединим DataFrame с ценами, предварительно обработанный в части 3, и DataFrame с коэффициентами, созданный в этой части. Поскольку цены представлены ежедневно, а коэффициенты - квартально, после объединения двух DataFrame в столбцах с коэффициентами будут пропущенные значения. Мы решаем эту проблему, заполняя пропущенные значения последним известным значением коэффициента.

list_ticker = df["tic"].unique().tolist()
list_date = list(pd.date_range(df['date'].min(),df['date'].max()))
combination = list(itertools.product(list_date,list_ticker))

# Merge stock price data and ratios into one dataframe
processed_full = pd.DataFrame(combination,columns=["date","tic"]).merge(df,on=["date","tic"],how="left")
processed_full = processed_full.merge(final_ratios,how='left',on=['date','tic'])
processed_full = processed_full.sort_values(['tic','date'])

# Backfill the ratio data to make them daily
processed_full = processed_full.bfill(axis='rows')

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

# Рассчитайте коэффициенты P/E (цена/прибыль), P/B (цена/балансовая стоимость) и дивидендную доходность с использованием ежедневной цены закрытия.
processed_full['PE'] = processed_full['close']/processed_full['EPS']
processed_full['PB'] = processed_full['close']/processed_full['BPS']
processed_full['Div_yield'] = processed_full['DPS']/processed_full['close']

# Удалим показатели на одну акцию, использованные для расчета коэффициентов.
processed_full = processed_full.drop(columns=['day','EPS','BPS','DPS'])

Моделирование

Данные готовы, пора обернуть их в модель рынка и обучить нашу модель.

Для построения модели рынка, как и ранее воспользуемся интерфейсами, предоставляемыми библиотекой Gymnasium :

class StockTradingEnv(gym.Env):
    """A stock trading environment for OpenAI gym"""

Полное описание класса среды достаточно объемное и я не буду приводить его здесь полностью. Ознакомиться с полным исходным кодом вы модете на github'e.

Теперь мы можем создать экземпляр среды и приступить к обучению модели:

e_train_gym = StockTradingEnv(df = train_data, **env_kwargs)
env_train, _ = e_train_gym.get_sb_env()

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

В сегодняшнем примере мы воспользуемся агентами, реализованными в популярном фреймворке stablebaseline3:

from finrl.agents.stablebaselines3.models import DRLAgent

agent = DRLAgent(env = env_train)

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

Создадим агента, обучающегося по алгоритму PPO, а так же зададим ему необходимые для работы гиперпараметры:

agent = DRLAgent(env = env_train)
PPO_PARAMS = {
    "n_steps": 2048,
    "ent_coef": 0.01,
    "learning_rate": 0.00025,
    "batch_size": 128,
}
model_ppo = agent.get_model("ppo",model_kwargs = PPO_PARAMS)

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

Для этого после цикла обучения будем сохранять нашего агента на диск. И в сулчае если он уже сохранен будем загружат.

if exists('./trained_models/trained_ppo.model'):
    trained_ppo = model_ppo.load('./trained_models/trained_ppo.model')
else:
    trained_ppo = agent.train_model(model=model_ppo, 
                            tb_log_name='ppo',
                            total_timesteps=50000) if if_using_ppo else None

    trained_ppo.save('./trained_models/trained_ppo.model')

Торговля

В начальный момент времени (TEST_START_DATE) мы будем располагать начальным капиталом в 1,000,000$. Попробуем торговать с использование наших моделей на акциях списка Dow jones 30.

Модели DRL нужно периодически обновлять, чтобы использовать последние данные. В идеале, мы должны переобучать нашу модель ежегодно, ежеквартально или ежемесячно по мере убывания ее качества предсказания. Также нам нужно настраивать параметры.

В этом примере мы используем только данные с 2009-01 по 2018-12 для настройки параметров модели один раз, поэтому здесь есть некоторое убывание качества модели со сременем.

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

df_account_value_ppo, df_actions_ppo = DRLAgent.DRL_prediction(
    model=trained_ppo, 
    environment = e_trade_gym)

Библиотека FinRL содержит богатый инструментарий backtest'a для проверки эффективности моделей.

Hidden text

К сожалению не все компоненты успевают за развитием и некоторые инструменты перестают работать. Будьте внимательны при использовании библиотеки pyfolio.

Получим простейшую оценку эффективности построенной модели:

perf_stats_all_ppo = backtest_stats(account_value=df_account_value_ppo)
  perf_stats_all_ppo = pd.DataFrame(perf_stats_all_ppo)
  perf_stats_all_ppo.to_csv("./"+config.RESULTS_DIR+"/perf_stats_all_ppo_"+now+'.csv')

Будет сформирован отчет, оценивающий модель по различным критериям:

Annual return          0.100563
Cumulative returns     0.320433
Annual volatility      0.268298
Sharpe ratio           0.492379
Calmar ratio           0.226261
Stability              0.014418
Max drawdown          -0.444455
Omega ratio            1.134475
Sortino ratio          0.697915
Skew                        NaN
Kurtosis                    NaN
Tail ratio             1.048884
Daily value at risk   -0.033278

Мы можем сравнить показатели Annual return и Cumulative returns как базовые и сравнить их с движением индекса:

print("==============Get Baseline Stats===========")
baseline_df = get_baseline(
        ticker="^DJI", 
        start = TEST_START_DATE,
        end = TEST_END_DATE)

stats = backtest_stats(baseline_df, value_col_name = 'close')

В завершение приведу сравнение нескольких моделей, которые вы сможете найти в полном коде на github:

Из 5 моделей только две смогли показать себя на тестовом периоде лучше чем движение базового индекса.
Вместе с тем, даже такая простая модель, обученная по алгоритму TD3 показала эффективность на 14% выше рынка, что является уже достаточно неплохим показателем.

В рассмотренном примере агент обладал только данными о квартальной отчетности компаний и был вынужден опираясь только на них и движении цен принимать торговые решения, тем не менее он смог научиться вести себя лучше чем “в среднем” по рынку. Это отличный результат для такой простой модели и у нас есть значительный потенциал роста.

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

Скоро в Otus стартует курс, посвященный построению финансовых моделей и я являюсь его руководителем. Я буду всех рад видеть у нас на курсе, там мы будем разбирать подобные модели более подробно. А ещё записывайтесь на бесплатные открытые уроки на странице курса.

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

Комментарии (1)


  1. Krasnoarmeec
    24.06.2024 18:05

    Не, я плюсик поставил, но он скорее за старание.

    В чём новизна-то?

    Где сравнение со стандартной портфельной моделью Марковица? Ну, хотя бы скорость модели бы привели, а то на поверку окажется, что она неделю считает.

    Как раз с 2009 по 2019 Dow Jones рос (+160%). А как покажут себя Ваши модели с 1990 по 2023? Да и Dow Jones это не то, к чему стоит стремиться. Например, NASDAQ composite за тот же период времени вырос на 300%.

    Извините за критику, но, кажется, она довольно обоснована.