
Машинное обучение и Data Science (Часть 04): Предсказание биржевого краха
Введение
В Части 2 этой серии статей мы создали простую логистическую модель на основе данных о Титанике. Сегодня будем строить логистическую модель, которая может помочь нам предсказать падения фондового рынка.
В этой статье мы перейдем к полезному применению наших логистических моделей — создадим прогностическую модель биржевого краха. Чтобы протестировать нашу модель, мы будем использовать тестовые данные о текущем падении фондового рынка. Думаю, это будет быть актуальным для всех нас.
Биржевой крах
Биржевой крах — это обвальное падение общей стоимости рынка, при котором цены могут снижаться более чем на 10% в течение нескольких дней. Известными примерами крупных крахов являются черный понедельник 1987 года и ипотечный пузырь на рынке недвижимости в 2008 году. Крах обычно связан с лопнувшим ценовым пузырем и случается как следствие массовой продажи, когда большинство участников фондового рынка одновременно пытаются продать свои активы.
Прежде чем мы перейдем к изучению этой темы, я хотел бы предостеречь читателей:
Внимание! Данная статья не содержит финансовых или торговых советов. Нужно понимать, что я не Уоррен Баффетт и не Чарли Мангер, я не профессиональный инвестор на фондовом рынке. Я просто специалист по данным, который ищет способ связать научные модели с трейдингом. Не воспринимайте информацию из этой статьи слишком серьезно, поскольку большинство мнений были собраны из разных источников в интернете (хотя я старался использовать различные надежные источники — ссылка на справочный раздел в конце статьи). Проведите собственное исследование, прежде чем решите использовать любой из подходов, обсуждаемых в этой статье, для принятия торговых решений.
С этим разобрались, теперь идем дальше.
Прежде всего, давайте определим факторы, влияющие на стоимость акций. Как только мы их поймем, станет понятно, с чего начать, потому что эти факторы можно использовать в качестве данных (независимых переменных) для нашей логистической модели.
Факторы, влияющие на стоимость акций
Существует множество различных факторов, влияющих на фондовый рынок, вот лишь некоторые из них. Не забывайте, что еще не было четкого индикатора, точно описывающего поведение рынка. Я буду использовать следующие факторы:
- Спрос и предложение
- Факторы, связанные с компанией
- Процентные ставки
- Текущие события
- Инфляция
1. Спрос и предложение
Есть множество факторов, влияющих на биржевой рынок, но если отделить все внешнее, останется самый основной фактор. Он прост — это спрос и предложение. Дисбаланс между спросом и предложением будет повышать и понижать цену акций.
Если яблок внезапно станет не хватать, все больше и больше людей будут выстраиваться в очередь, чтобы купить их, и цена на яблоки немедленно взлетит до небес.
Точно так же, если дела у какой-то компании идут хорошо и все хотят купить акции именно этой компании, акций будет не хватать, что приведет к росту стоимости акций компании. И наоборот, если акций слишком много, и при этом никто не хочет их покупать, цены таких акций пойдут вниз.
Невозможно получить данные о спросе и предложении, которые можно было бы использовать в нашей модели. Поэтому этот фактор мы не будем включать в наш набор данных. Но я уверен, если кто-то сможет получить точные данные, он станет на шаг ближе к созданию святого Грааля.
2. Факторы, связанные с компанией
Все, что происходит внутри компании, будет напрямую влиять на стоимость акций: если компания находится на подъеме, у нее успешные запуски продуктов, доходы ее растут, долг сокращается, компания успешно привлекает инвесторов, тогда ее стоимость будет неизбежно расти, потому что все захотят купить акции такой компании, которая растет все выше и выше.
И наоборот, если компания регистрирует убытки, ее продукт работает нестабильно, долг растет, то большинство акционеров захотят продать акции компании, что снизит их цену.
Хорошим примером, объясняющим этот фактор, являются Netflix и Apple.
Мы наблюдали за тем, как Netflix потерял более 200 000 подписчиков на сервисы в течение первых трех месяцев 2022 года из-за их ценовой политики и внутренних дел, произошедших внутри компании, которые непосредственно привели к падению курса акций Netflix.
Apple наоборот, очень долгое время была успешной компанией благодаря успешным запускам продуктов, хорошему руководству и другим позитивным внутренним ситуациям, которые и привели к бычьему курсу акций в последние годы.
Чтобы определить состояние компании, мы будем использовать соотношение цены к прибыли.
Соотношение цены и прибыли
Соотношение цены и прибыли (PE) при оценке компании измеряет текущую цену ее акций по отношению к ее прибыли на акцию (EPS). Соотношение PE также можно использовать в качестве индикатора общего здоровья компании. Вот как выглядят графики на основе стоимости акций и коэффициента PE по компаниям Apple и Netflix.
APPLE:
Источник данных: macrotrends.net
NETFLIX
Источник данных: macrotrends.net
Поскольку соотношение PE рассчитывается ежеквартально (четыре раза в год) по крайней мере такие данные доступны в открытых источниках, хотя наверняка есть и платные ресурсы, для нас получается, что в данных есть пробелы, поскольку нам нужно одинаковое количество строк во всех столбцах нашего набора данных, чтобы расчеты в моделях были эффективными. Вот такие данные есть по компании APPLEL:
Так как данные рассчитываются каждый квартал года, то для остальной части квартала мы будем использовать те же данные, которые были предварительно рассчитаны до следующего квартала, поэтому в этом случае просто продублируем данные:
То же самое повторим для NETFLIX.
3. Процентные ставки
Действия федерального резервного банка напрямую влияют на цены акций. Резервные банки/центробанки регулярно меняют ставки для стабилизации экономики. Естественно, более высокая процентная ставка означает, что компаниям придется платить больше за кредиты, что приведет к меньшей прибыли. Это снизит цену их акций. И наоборот, низкие ставки означают, что компания может взять в кредит бо`льшую сумму с меньшими затратами, сохранить капитал и получить более высокую прибыль. В этом случае цены на акции будут расти.
ФРС в последнее время повышает ставки, чтобы понизить спрос и заставить предприятия снизить цены и, в конечном счете, помочь снизить инфляцию.
График ставки по фондам ФРС с 2010 года по сегодняшний день выглядит так:
4. Текущие события
События, происходящие в стране или мире в целом, также могут оказать огромное влияние на фондовый рынок. Думаю, все согласятся, что пандемия Covid-19 оказала очень сильное негативное влияние на фондовый рынок в конце 2019 и 2020 гг. А вспомним беспорядки и движение за равноправие в США в том же году.
Также на фондовый рынок влияют войны и террористические атаки.
Все эти события неизбежно приведут к резкому падению цен на акции и повлияют на волатильность рынка.
Я не буду собирать какие-либо данные по этому фактору, потому что для обучения этим событиям потребовалось бы так слишком много работы и моделей. Это выходит за рамки того, что мы уже рассмотрели в этой серии статей.
5. Инфляция
Инфляция — это снижение покупательной способности данной валюты во времени. Количественная оценка скорости, с которой происходит снижение покупательной способности, может отражаться в увеличении среднего уровня цен на корзину определенных товаров и услуг в экономике за определенный период времени. Повышение общего уровня цен, часто выражаемое в процентах, означает, что за единицу валюты фактически можно купить меньше, чем в предыдущие периоды.
Прочитать подробнее об инфляции можно здесь: https://www.investopedia.com/terms/i/inflation.asp
Существует два основных типа инфляции: Core CPI и CPI.
- Core CPI — индекс цен на все, за исключением энергоносителей и продуктов питания.
- CPI — все, что существует в экономике, включая энергоносители, продукты, образование, развлечение и т.д. Все, что существует в повседневной жизни людей определенной экономики
Поскольку инфляция снижает стоимость доллара, рынку может быть сложно оценить текущую стоимость компаний, составляющих рыночные индексы. Кроме того, более высокие цены на материалы, оборудование и рабочую силу могут повлиять на прибыль компаний. В результате цены на акции колеблются, на рынке возникает волатильность.
Хорошая новость заключается в том, что, хотя ужесточение ФРС может негативно сказаться на инвестициях в ценные бумаги с фиксированным доходом, исторически акции часто приносили хорошие результаты в такие циклы.
Посмотрим на график CPI США с 1970 года.
Теперь соберем все необходимые данные и сохраним их в одном CSV-файле.
Начнем с APPLE:
Сбор данных
3Вот такие данные мы будем собирать для файла CSV: индексы Core CPI, CPI, процентная ставка ФРС, EPS и коэффициент PE. У меня есть все эти данные.
В этом наборе данных не хватает только одних данных — нашей зависимой переменной. У нас есть только необработанные данные значений цен на акции. Давайте создадим скрипт, который сможет показать, был ли в конкретном месяце крах или нет.
Код CrashClassifyScript.mq5:
void DetectCrash(double &prices[], int& out_binary[]) { double prev_high = prices[0]; ArrayResize(out_binary,ArraySize(prices)-1); //уменьшаем размер на единицу, чтобы пропустить текущее - предсказываем предыдущее for (int i=1; i<ArraySize(prices); i++) { int prev = i-1; if (prices[i] >= prev_high) prev_high = prices[i]; //получение максимальной цены double percent_crash = ((prev_high - prices[i]) / prev_high) * 100.0; //конвертируем падение в процент printf("crash percentage %.2f high price %.4f curr price %.4f ", percent_crash,prev_high,prices[i]); //согласно определению краха рынки должны упасть больше чем на 10% if (percent_crash > 10) out_binary[prev] = 0; //downtrend (crash) else out_binary[prev] = 1; //uptrend (no crash ) } }
Если внимательно посмотреть на первую prev_high, можно заметить, что сначала ей было присвоено значение предыдущей цены, потому что я скопировал данные по Apple с 1 декабря 2009 г. вместо 1 января 2010 г. Я хотел обеспечить возможность обнаружить крах при первом же расчете, и это стало возможно благодаря добавлению этого месяца. В выходном наборе этот месяц игнорируем, потому что этот период нам не нужен. Именно поэтому предыдущий индекс out_binary[prev] в коде, то есть значение по индексу i-1, а цикл начинается с индекса 1.
Вот результат, который выводим в массив output binary:
CrashClassifyScript DATE 1/1/2010 TREND 1
CrashClassifyScript DATE 2/1/2010 TREND 1
.........
CrashClassifyScript DATE 4/1/2022 TREND 0
CrashClassifyScript DATE 5/1/2022 TREND 0
Добавляем все столбцы в единый файл csv в Excel и получаем в итоге вот такой файл:
Отлично! Теперь все готово, и мы можем приступить к работе с кодом.
Мы уже выяснили, что за нашей логистической моделью стоит алгоритм линейной регрессии, и прежде, чем мы использовать какие-либо данные в линейной модели, нужно проверить, коррелируют ли они со своей независимой переменной. Будем проверять это, вызвав метод corrcoeff, который мы добавили в нашу библиотеку LinearRegression, созданную в предыдущей статье.
Код скрипта TestScript.mq5:
m_lr = new CMatrixRegression; Print("Matrix multiple regression"); m_lr.Init(8,"2,4,5,6,7",file_name,",",0.7); m_lr.corrcoeff(); m_lr.MultipleMatLinearRegMain(); delete m_lr;
Вывод будет таким:
Матричная множественная регрессия
TestScript Init, number of X columns chosen =5
TestScript "2" "4" "5" "6" "7"
TestScript All data Array Size 740 consuming 52 bytes of memory
TestScript Correlation Coefficients
TestScript Independent Var Vs Trend = 0.225
TestScript Independent Var Vs CPI = -0.079
TestScript Independent Var Vs Core CPI = -0.460
TestScript Independent Var Vs EPS($) = -0.743
TestScript Independent Var Vs PE Ratio = -0.215
Похоже, что все данные, которые мы только что собрали из разных мест, не коррелируют с ценой акций. Хотя что многие в интернете заявляют, что эти факторы влияют на фондовый рынок. Я понимаю, что источники изначально показывают предупреждение, что нет четкого индикатора поведения рынков. Однако цифры в линейно модели показывают совсем другую историю. Например, индекс потребительских цен CPI и стоимость акций Apple. Я ожидал увидеть очень сильную отрицательную корреляцию, но оказалось, что корреляция слишком слабая, чтобы ее можно было использовать в линейной регрессии. Только базовый ИПЦ (Core CPI) показал отрицательную корреляция около -0,46. Самый сильный результат — у EPS (прибыль на акцию), которая показала отрицательную корреляцию около 0,743, т.е. -74,3%
Не будем останавливаться на этой. Очень важно визуализировать данные в python и убедиться в этом на случай, если мы что-то упустили по цифрам в случае с проблемами в расчетах:

Вывод
Думаю, к этому моменту совершенно очевидно, что между большинством собранных данных нет сильной связи. Поэтому отфильтруем наши данные.
Мы будем использовать только три независимые переменные для построения нашей модели, а именно:
- Базовый CPI (корреляция примерно на -46%, около половины)
- EPS (коррелирует примерно на -74,2%, коррелирует лучше других данных)
- Наконец, процентная ставка ФРС (коррелирует примерно на -33%, наименее коррелированная. Я бы не рекомендовал эти данные для построения серьезной модели.)
Теперь инициализируем нашу библиотеку только с нужными столбцами:
log_reg.Init(file_name,delimiter,2,"3,5,6",0.7);
Если вы пропустили основные функции логистической регрессии, рекомендую прочитать эту статью.
Дальнейшее улучшение библиотеки
//Необходимо вызвать до Init void FixMissingValues(string columns); void LabelEncoder(string columns, string members);
Логистические модели чувствительны к отсутствующим значениям, и, поскольку это классифицирующая модель машинного обучения, она обрабатывает нулевые данные, которые могут указывать на отсутствующие данные. Как класс, она также может обрабатывать значения nan и строки как нули в зависимости от того, как мы читаем файлы в MQL5. Поэтому я внес некоторые улучшения в библиотеку.
Я добавил функцию для замены отсутствующих значений средним значением и функцию для преобразования строк в метки.
Эти необходимо вызывать перед функцией Init.
Теперь наша логистическая библиотека наследует компоненты из библиотеки MatrixRegression, которую мы создали в предыдущей статье
class CLogisticRegression: protected CMatrixRegression
Пора переходить к следующей части и посмотреть, насколько хороша наша модель.
Результат вызова будет таким
Матрица путаницы [ 0 13 ] [ 0 31 ] Точность тестируемой модели =0.7045
Точность нашей модели на тестовых данных составила 70,45% 😲. Я здесь ошарашен.
Я думал, что из-за недостатка данных, отмеченного ранее, я не смогу достичь даже отметки 50%. Я думал, что в какой-то момент вероятно произошла ошибка, пока не попробовал то же самое на Python — результат был тем же.
Та-дам!
Имейте в виду, что нашей зависимой переменной является столбец тренда, который мы собрали с помощью нашего скрипта для поиска крахов ранее в этой статье. Столбец цены использовался только для отображения коэффициентов корреляции для наших линейных моделей, потому что для поиска корреляции мы не можем использовать бинарные значения 0 и 1, которые указывают тренд вниз и вверх соответственно. В этом случае это скорее реальные цены на акции.
Теперь перейдем к данным NETFLIX.
Вот как выглядят коэффициенты корреляции для этой компании.
Correlation Coefficients Independent Var Vs Trend = 0.071 Independent Var Vs rate (FEDs rate) = 0.310 Independent Var Vs CPI = 0.509 Independent Var Vs Core CPI = 0.607 Independent Var Vs EPS = 0.917 Independent Var Vs PE Ratio = -0.213
Похоже, что большинство факторов, которые мы обсуждали, положительно влияют на NETFLIX. Отрицательно повлияло только соотношение цены к прибыли. Самым сильным фактором явилась прибыль на акцию с корреляцией около 92% к цене акции. Поэтому для анализа NETFLIX будем использовать только три варианта данных для построения модели:
- EPS — прибыль на акцию
- Core CPI — базовый индекс потребительских цен
- и CPI — индекс потребительских цен
Снова визуализируем данные.
На данных NETFLIX получилось гораздо лучше, чем в прошлый раз на Apple.
Получается так:
log_reg = new CLogisticRegression(); Print("NETFLIX"); file_name = "Netflix Dataset.csv"; log_reg.Init(file_name,delimiter,2,"4,5,6",0.7); log_reg.LogisticRegressionMain(accuracy); printf("Tested model accuracy =%.4f",accuracy); delete log_reg;
Вывод:
FN 0 07:54:45.106 TestScript NETFLIX PN 0 07:54:45.108 TestScript ==== TRAINED LINEAR REGRESSION MODEL COEFFICIENTS ==== ED 0 07:54:45.108 TestScript [ RO 0 07:54:45.108 TestScript 1.43120 -0.05632 -0.54159 0.48957 EE 0 07:54:45.108 TestScript ] CQ 0 07:54:45.108 TestScript columns = 4 rows = 1 PH 0 07:54:45.108 TestScript ========= LINEAR REGRESSION MODEL TESTING STARTED ========= QP 0 07:54:45.108 TestScript Tested Linear Model R square is = -0.35263665822405277 GR 0 07:54:45.108 TestScript Confusion Matrix EE 0 07:54:45.108 TestScript [ 0 18 ] HN 0 07:54:45.108 TestScript [ 0 26 ] MJ 0 07:54:45.108 TestScript Tested model accuracy =0.5909
Несмотря на наличие данных, которые имели сильную линейную корреляцию с ценой акций, модель NETFLIX показала меньшую точность — примерно60%, в то время как модель по APPLE показала точность в 70%. Вы можете самостоятельно поиграть с остальным набором данных и посмотреть, как может выглядеть модель.
Тестирование фондового рынка в реальном времени
Чтобы иметь возможность тестировать на реальном рынке, нужно внести некоторые изменения в нашу основную функцию логистической регрессии — функция должна сохранять прогнозируемые значения с соответствующими датами в файле CSV, который будем использовать в тестере стратегий, чтобы получить сигналы о том, куда пойдет рынок согласно нашей модели.
Вот как мы будем собирать данные и сохранять их в файл csv:
WriteToCSV(TestPredicted,dates,"Predicted "+m_filename,m_delimiter);
Напомню, здесь мы собираем только результаты тестового набора данных.
Вот краткий обзор того, как данные хранятся в CSV-файле:
NETFLIX Predicted, date_time 1,8/1/2018 1,9/1/2018 1,10/1/2018 1,11/1/2018 1,12/1/2018 1,1/1/2019 APPLE Predicted, date_time 1,9/1/2018 1,10/1/2018 1,11/1/2018 1,12/1/2018 1,1/1/2019 1,2/1/2019
Если вы внимательно почитали про матрицу путаницы, то заметите, что наша модель является хорошим предиктором восходящего тренда, тейк-профита (истинно положительным было большое количество всех матричных строк в Матрице).
Советник для тестирования цен акций в реальном времени
Первым шагом при создании нашего советника является сбор данных из нашего CSV-файла. Но перед нужно сообщить нашему тестеру стратегий, что мы собираемся использовать этот файл во время тестирования.
#property tester_file "Predicted Apple Dataset.csv"
Ниже дан просто краткий обзор функций, вызов которых добавлен в функцию OnInit.
GetColumnDatatoArray(1,Trend); GetColumnDatatoArray(2,dates);
Мы часто использовали эти функции в нашей библиотеке. По факту мы собираем данные из первого столбца, а затем сохраняем их в массив Trend[]. То же самое для массива dates[].
Следующим важным моментом является преобразование времени, которое мы получили из файла csv, в стандартный формат времени, который можно было бы понять вMQL5.
ConvertTimeToStandard();
Вот что внутри этой функции:
void ConvertTimeToStandard() { // Однократная попытка преобразовать дату в гг.мм.дд ArrayResize(date_datetime,ArraySize(dates)); for (int i=0; i<ArraySize(dates); i++) { StringReplace(dates[i],"/","."); //заменяем запятую на точку в каждой дате //Print(dates[i]); string mm_dd_yy[]; ushort sep = StringGetCharacter(".",0); StringSplit(dates[i],sep,mm_dd_yy); //отдельный месяц, день и год //Print("mm dd yy date format"); //ArrayPrint(mm_dd_yy); string year = mm_dd_yy[2]; string day = mm_dd_yy[1]; string month = mm_dd_yy[0]; dates[i] = year+"."+month+"."+day; //сохраняем в формате yy.mm.dd date_datetime[i] = StringToTime(dates[i]); //наконец, преобразуем строку datetime в фактические дату и время } }
Думаю, это все функции, которые стоит объяснить — это то, что происходит в функции Init().
Следующим шагом является проверка прогнозов модели в функции Ontick. Это основа нашего советника:
datetime today[1]; int trend_signal = -1; //1 сигнал на покупку, 0 - на продажу CopyTime(Symbol(),PERIOD_D1,0,1,today); if (isNewBar()) for (int i=0; i<ArraySize(date_datetime); i++) { if (today[0] == date_datetime[i]) //обучение только на этом конкретном дне { if ((int)Trend[i] == 1) trend_signal = 1; else trend_signal = 0; // закрываем все существующие позиции, так как получаем новые сигналы данных ClosePosByType(POSITION_TYPE_BUY); ClosePosByType(POSITION_TYPE_SELL); break; } if (MQLInfoInteger(MQL_TESTER) && today[0] > date_datetime[ArrayMaximum(date_datetime)]) { Print("we've run out of the testing data, Tester will be cancelled"); ExpertRemove(); } } //--- Время перейти к торговле MqlTick tick; SymbolInfoTick(Symbol(),tick); double ask = tick.ask , bid = tick.bid; //--- if (trend_signal == 1 && PositionCounter(POSITION_TYPE_BUY)<1) { m_trade.Buy(Lots,Symbol(),ask,0,0," Buy trade "); ClosePosByType(POSITION_TYPE_SELL); //если модель предсказывает бычий рынок, закрываем все сделки на продажу, если таковые имеются } if (trend_signal == 0 && PositionCounter(POSITION_TYPE_SELL)<1) { m_trade.Sell(Lots,Symbol(),bid,0,0,"Sell trade"); ClosePosByType(POSITION_TYPE_BUY); //и наоборот, если модель предсказывает медвежий рынок } }
Причина, по которой я решил обучать модель именно на данных этого дня. Используем хэндл события NewBar, который должен снизить затраты тестирования приложения. Чтобы еще больше снизить затраты, я также добавил в код условие, согласно которому тестер стратегии должен остановиться, как только у нас закончится набор данных для тестирования.
Вот и все. Смотрите полный код по ссылке ниже. Теперь пришло время протестировать модель в тестере стратегий.
Результаты тестирования APPLE
График
Для сравнения Netflix. Отчет тестера:
График тестера
Отлично! Как видите, модель Apple показала точность около 70%. Она создала хорошую прогностическую модель с хорошим графиком на тестере стратегий по сравнению с ее конкурентом NETFLIX.
Заключение
Преимущество логистических моделей заключается в том, что их легко построить и обучить. Они довольно хорошо справляются с классификацией данных, хотя поиск данных, которые можно найти в нашей модели, не следует воспринимать как нечто само собой разумеющееся. Это из разряда самых важных шагов, одна ошибка в которых может сделать всю модель неэффективной.
Вы также можете внести дополнительные улучшения в нашу библиотеку и заново собрать данные, потому что я все же считаю, что способ, которым я собирал данные и классифицировал их в скрипте Crashclassify, не самый эффективный способ поиска падений рынка.
Ссылка на мой репозиторий с кодами, рассматриваемыми в статье: https://github.com/MegaJoctan/LogisticRegression-MQL5-and-python.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/10983





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования