English Deutsch 日本語
preview
Статистический арбитраж посредством возврата к среднему значению в парной торговле: Обыграем рынок с помощью математики

Статистический арбитраж посредством возврата к среднему значению в парной торговле: Обыграем рынок с помощью математики

MetaTrader 5Торговые системы |
119 14
Jocimar Lopes
Jocimar Lopes

Введение

«Я могу рассчитать движение небесных тел, но не безумие людей».

(Сэр Исаак Ньютон в возрасте девяноста лет, после потери почти всех своих пенсионных сбережений, вложенных в фондовые рынки.)

10 мая прошлого года мир лишился Джима Саймонса, самого успешного управляющего всех времен.

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

Существует несколько его биографий, о его жизни и карьере написаны десятки книг, он был героем сотен телешоу и тысяч статей и постов в блогах по всему миру. Самая известная его биография — "Человек, который разгадал рынок: Как Джим Саймонс запустил квантовую революцию".

В начале восьмидесятых Саймонс основал компанию Simons founded Renaissance Technologies (RenTech) и начал собирать команду высококвалифицированных «математиков, физиков, специалистов по обработке сигналов и экспертов в области статистики». Сотрудничая на протяжении десятилетий, они доказали, что при достаточном количестве данных и вычислительных мощностях для обнааружения статистических закономерностей и аномалий в этих закономерностях, рынок можно «обыграть с помощью математики».

«В 1988 году компания создала свой наиболее прибыльный портфель — фонд Medallion, использовавший улучшенный и расширенный вариант математических моделей Леонарда Баума, усовершенствованный специалистом по алгебре Джеймсом Аксом, для исследования корреляций, из которых можно было бы извлекать прибыль». (Википедия)

В период с 1988 по 2018 год средняя доходность фонда Medallion составила 66% в год, а прибыль за эти три десятилетия — более 104 миллиардов долларов. Фонд Medallion компании RenTech действует и по сей день, принося очень большую прибыль. Как и следовало ожидать, многим хотелось бы узнать, как работает компания, — подробности, секретный алгоритм, чит-код... да что угодно. Но, насколько это известно любому смертному, ее секретный ингредиент хранится в виде совершенно секретного корпоративного соглашения. Когда автор его биографии спросил Саймонса о рабочей стратегии фонда Medallion, тот ответил так же лаконично, как он отвечал нескольким интервьюерам в последующие годы: статистический арбитраж на уровне портфеля. Кроме того, он рассказал, что они с самого начала для выявления аномалий рынка использовали «что-то вроде машинного обучения».

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

Эта статья ни в коем случае не представляет собой попытку воспроизвести или, что еще хуже, «раскрыть секретный код» компании RenTech или Джима Саймонса. Как сказано выше, это было бы невозможно для кого-либо, не принимающего непосредственного участия в их деятельности. Это — попытка поделиться с вами моим пониманием общих принципов, лежащих в основе их моделей. Эти принципы могут стать основой торговой системы даже для самого скромного розничного трейдера. Разница будет заключаться в масштабе результатов, который будет пропорционален объему ресурсов, вложенных в систему и операции.

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

Цель состоит в том, чтобы внести свой вклад с помощью недорогого, легкого в использовании и простого в разработке метода анализа, который может протестировать среднестатистический розничным трейдер, использующий только инструменты, уже доступные на платформе MetaTrader 5, работающей на потребительском ноутбуке для торговли товарами и, возможно, на низкоуровневом ноутбуке. Метод должен быть полезен как трейдеру, выбирающему алгоритмическую торговлю, так и трейдеру, предпочитающему дискреционную (ситуативную) торговлю. Начнем с самой простой настройки, просто достаточной для описания процесса.

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


Общие концепции, лежащие в основе модели

До создания компании RenTech Джим Саймонс работал дешифровщиком в американской разведке во времена «холодной войны». Когда он начал торговать на финансовых рынках, он пытался предсказывать цены акций и сырьевых товаров, но потерпел неудачу. Тогда он изменил подход. Он предположил, что никогда не будет в состоянии предсказать будущее рынка. Он понимал: ему придется признать, что рынок представляет собой непостижимую загадку. Это первая релевантная концепция, лежащая в основе модели.

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

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

Рынок — непостижимая загадка

Рынок — непостижимая загадка, но в отличие от одноименной шифровальной машины (название машины — «Энигма» — в переводе с английского означает как раз непостижимую загадку) времен Второй мировой войны, код которой взломали Алан Тьюринг и его сотрудники, у загадки рынка отсутствует детерминистский алгоритм, который можно было бы подвергнуть обратному инжинирингу и взломать. Между входом и выходом могут произойти непредвиденные события. В то время как повышение центральным банком страны процентных ставок, как ожидается, приведет к укреплению валюты этой страны, возникновение в другой, отдаленной стране какого-то политического конфликта может привести к противоположному эффекту, уравновешивая повышение процентных ставок, снижая влияние такого повышения, нивелируя его или даже ослабляя эту валюту.

Рынок представляет собой непостижимую загадку, потому что между входом и выходом существует иррациональность экономических объектов, непредсказуемых характер политики и хаотичный аспект взаимодействия сил, которые ею управляют. Между продолжающимся в течение года бычьего рынка золота и начавшимся через неделю его резким падением на целый месяц находится поведение людей. Именно за это психолог Даниэль Канеман был удостоен Нобелевской премии по экономике. Потому что он рассматривает именно этот вопрос.
И даже несмотря на то, что рынок представляет собой непостижимую загадку, управляемую иррациональными экономическими объектами внутри хаотической среды, инвестиционные баки покупают и продают акции на основе финансовых моделей, хедж-фонды используют модель Блэка-Шоулза для количественной оценки опционов, а почти все крупнейшие игроки на рынках тратят миллионы долларов на разработку количественных торговых стратегий. Почему? Потому что это работает, конечно. Почему же это работает, если рынок так непредсказуем, непрогнозируем, иррационален и хаотичен?

Джим Саймонс, как и тысячи других успешных количественных, алгоритмических и дискреционных трейдеров, дает на этот вопрос самый откровенный ответ. Урок, который всякий, кто хочет быть трейдером, должен каждое утро повторять как мантру перед выходом на рынок:

«Успех в трейдинге заключается не в том, чтобы всегда быть правым. Речь идет об увеличении прибылей до максимума и сведении потерь к минимуму».

В этом и заключается цель финансовых моделей, уравнения Блэка-Шоулза и стратегий количественной торговли: увеличение прибыли до максимума и сведение потерь к минимуму. Тут нет ничего нового. Ответ успешных трейдеров на рыночную загадку — это общеизвестная истина, существовавшая еще до того, как японский торговец рисом Мунэхиса Хомма изобрел графики японских свечей: управление рисками.

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

Рынок находится в состоянии непрерывных изменений

Рынок изменяется постоянно. Единственной константой на рынке является постоянное наличие изменений. Значения наших параметров выбраны не потому, что они наилучшим образом соответствуют конкретному состоянию рынка, а потому, что они наилучшим образом соответствуют конкретному изменению рынка. Между моментом, когда мы разместили выигрышный ордер, и моментом, когда этот ордер был закрыт, рынок изменялся именно так, как мы и ожидали. И напротив, между моментом, когда мы разместили убыточный ордер, и моментом, когда этот ордер был закрыт, рынок изменился таким образом, какого мы не ожидали. Это верно, даже если мы не в состоянии сказать, какое именно изменение оказало на конечный результат наибольшее влияние.

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

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

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


Формирование портфеля

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

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

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

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

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

Выберите группу ценных бумаг, с которой хотите начать

На момент написания статьи на моем аккаунте в терминале MetaTrader 5 было доступно более десяти тысяч символов. В своем анализе мы будем использовать вот эту интеграцию Python для Metatrader 5.

print("Total symbols =",mt5.symbols_total()) # display all symbols
Total symbols = 10563
Таким образом, по практическим соображениям, нам сначала нужно выбрать подмножество всех доступных символов. Начнем с пар, содержащих XAU.
# get symbols containing XAU in their names
xau_symbols=mt5.symbols_get("*XAU*")
print('len(*XAU*): ', len(xau_symbols))
for s in xau_symbols:
    print(s.name)

len(*XAU*):  6
XAUUSD
XAUEUR
XAUAUD
* XAUG
XAUCHF
XAUGBP

* XAUG представляет собой торгуемый инвестиционный фонд (ETF), поэтому мы на данный момент можем исключить его и сосредоточиться на остальных пяти парах. Посмотрим, как каждая из них коррелирует с XAUUSD.

Теперь нам нужно рассчитать их корреляцию на исторических ценах. В реальном сценарии нам может потребоваться изучить все возможные комбинации выбранных символов, возможно, сотни символов акций, поскольку не предполагаем, что у нас имеются какие-либо знания о них. Но здесь мы их отфильтруем, чтобы увидеть только корреляцию цен между котировкой золота в долларах США (XAUUSD) и котировкой золота в евро, австралийских долларах, швейцарских франках и британских фунтах стерлингов.
Нам нужны данные по ежедневным ценам закрытия за один год, начиная с сегодняшнего дня, что для валютных рынков составляет примерно 250 торговых дней.
# get 250 D1 bars from the current day
xauusd_rates = mt5.copy_rates_from_pos("XAUUSD", mt5.TIMEFRAME_D1, 0, 250)
xaueur_rates = mt5.copy_rates_from_pos("XAUEUR", mt5.TIMEFRAME_D1, 0, 250)
xauaud_rates = mt5.copy_rates_from_pos("XAUAUD", mt5.TIMEFRAME_D1, 0, 250)
xauchf_rates = mt5.copy_rates_from_pos("XAUCHF", mt5.TIMEFRAME_D1, 0, 250)
xaugbp_rates = mt5.copy_rates_from_pos("XAUGBP", mt5.TIMEFRAME_D1, 0, 250)

(...)

# calculate correlation coefficients
import numpy as np
usd_eur_corr = np.corrcoef(xauusd_close['close'], xaueur_close['close'])
usd_aud_corr = np.corrcoef(xauusd_close['close'], xauaud_close['close'])
usd_chf_corr = np.corrcoef(xauusd_close['close'], xauchf_close['close'])
usd_gbp_corr = np.corrcoef(xauusd_close['close'], xaugbp_close['close'])

Это даст нам следующие результаты:


Корреляция XAUUSD (по Пирсону)
XAUEUR
0.9692368
XAUAUD
0.96677962
XAUCHF
0.8418827
XAUGBP
0.90490282

Таблица 1. Дневная корреляция цен закрытия для золота в долларах США (XAUUSD) и для золота в евро, австралийскийх долларах, швейцарских франках и британских фунтах стерлингов в период с 2024-04-09 по 2025-03-26.

На графике ниже мы можем наглядно увидеть, как выглядит ценовая корреляция, близкая к 0.97.

Дневные цены закрытия торгов на золото за один год, котированные в долларах США и в евро

Рис. 1. Дневные цены закрытия торгов на золото за один год, котированные в долларах США и в евро

Обратите внимание, что представленный выше график может вводить в заблуждение. У нас может возникнуть соблазн «торговать спредом» между парами, но это не настоящий спред, если таковой вообще имеется. Конвертируем XAUEUR в доллары США по текущему обменному курсу дня.
adjusted_for_dollars = pd.concat([xauusd_close, xaueur_close['close'], eurusd_close['close']], join='inner', axis=1)
adjusted_for_dollars.columns = ['time', 'xauusd', 'xaueur', 'eurusd']
adjusted_for_dollars['xaueur_dollars'] = adjusted_for_dollars['xaueur'] * adjusted_for_dollars['eurusd']
adjusted_for_dollars['diff'] = abs(adjusted_for_dollars['xauusd'] - adjusted_for_dollars['xaueur_dollars'])

print(adjusted_for_dollars)

         time   xauusd   xaueur   eurusd  xaueur_dollars       diff
0   2024-04-12  2344.22  2202.92  1.06237     2340.316120   3.903880
1   2024-04-15  2383.10  2242.90  1.06181     2381.533649   1.566351
2   2024-04-16  2382.85  2243.81  1.06720     2394.594032  11.744032
3   2024-04-17  2361.16  2212.14  1.06425     2354.269995   6.890005
4   2024-04-18  2378.86  2234.79  1.06557     2381.325180   2.465180
..         ...      ...      ...      ...             ...        ...
245 2025-03-25  3019.81  2797.81  1.07918     3019.340596   0.469404
246 2025-03-26  3018.85  2807.50  1.07370     3014.412750   4.437250
247 2025-03-27  3056.42  2829.26  1.07975     3054.893485   1.526515
248 2025-03-28  3084.20  2847.12  1.08276     3082.747651   1.452349
249 2025-03-31  3118.19  2882.78  1.08152     3117.784226   0.405774

[250 rows x 6 columns]
adjusted_for_dollars.plot(title = 'One Year of XAUUSD and XAUEUR in US Dollars (D1)', x='time', y=['xauusd', 'xaueur_dollars'])
plt.show()

Дневные цены закрытия торгов на золото за один год, котированные в долларах США и в евро
Рис. 2. Дневные цены закрытия торгов на золото за один год, котированные в долларах США и в евро, скорректированные на доллары США

Рассматривая разницу между котировкой золота в долларах США и котировкой золота в евро… 

print("median: ", adjusted_for_dollars['diff'].median())
adjusted_for_dollars['diff'].describe()

median:  4.052404150000029
count    250.000000
mean       5.894673
std        6.238511
min        0.050646
25%        1.279615
50%        4.052404
75%        8.587763
max       51.483719
median:  4.052404150000029

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

Выберем статистическую взаимосвязь для поиска

Затем мы решаем начать формировать наш статистический арбитражный портфель на основе тесной связи, которую мы обнаружили между XAUUSD и XAUEUR за последний торговый год (около 250 дней). Но является ли корреляция цен правильным или даже просто более благоприятным статистическим соотношением, на которое следует обращать внимание при формировании портфеля статистического арбитража?

Когда мы говорим о корреляции в исторических ценах, нас могут ввести в заблуждение некоторые различия между общепринятым использованием этого термина и его правильным статистическим значением. Этот факт еще более очевиден в форекс-сообществе. Простой поиск по запросу «коррелирующие пары на форексе» выведет нас на множество ресурсов, где перечисляются наиболее или наименее коррелирующие пары, а также даются советы по торговле ими. Наша цель здесь состоит не в том, чтобы объявить тот или иной ресурс, котировку или торговую подсказку правильными или ошибочными. Нам следует помнить, что мы закладываем основу для статистического арбитража на уровне портфеля, который не должен ограничиваться валютными парами. Вместо этого наша система должна быть в целом применима к любому классу активов на любом рынке и в любом временном интервале, лишь бы она соответствовала требованиям о нейтральности к рынку и проверяемости.

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

«Нестационарные данные, как правило, непредсказуемы и не поддаются моделированию или прогнозированию. Результаты, полученные с применением нестационарных временных рядов, могут быть ложными, поскольку они могут указывать на связь между двумя переменными, которой на самом деле не существует. Чтобы получить последовательные и надежные результаты, нестационарные даты нужно преобразовать в стационарные». (Nason, G. P. (2006). Stationary and non-stationary time series. Investopedia)

Затем, поскольку мы — трейдеры, стремящиеся создать статистический арбитражный портфель, необходимо принять решение: достаточно этой «ложной корреляции», или нам нужная корреляция, правильная с точки зрения статистики? На данном этапе принимаем первую, несовершенную меру в качестве достаточной меры для нашей упрощенной модели. Но мы не должны забывать, что коррелирующие пары могут продолжать расширять спред в течение длительных периодов времени, одновременно поднимаясь или опускаясь, то есть они могу не возвращаться к среднему значению в течение длительных периодов времени, а статистическая корреляция при этому будет по-прежнему применима. Такое состояние является исключением при торговле валютами, но очень распространено при работе с товарами, фьючерсами или временными рядами цен на акции. Таким образом, уровни стоп-лосса и расчет времени для позиции являются обязательными при работе со стратегиями «ожидаемый возврат к среднему значению».

Выберите статистическую меру, которая будет запускать торговлю

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

Итак, никакого «рецепта» не существует. Вы должны принять решение самостоятельно, основываясь на собственных данных и здравом смысле. Вы даже можете решить вообще не использовать ни среднее значение, ни медиану. Вместо этого вы можете провести исследования и решить, что в вашем случае для использования больше подойдет другая взаимосвязь.
Я же возьму среднее значение и установлю параметр для нашей торговой стратегии на основе расширения среднего спреда. Допустим, когда спред между XAUUSD и XAUEUR расширяется более чем на 50% от среднего значения, мы открываем сделку, покупая символ, проигрывающий гонку, и одновременно продавая символ, который растет быстрее.

Как мы можем определить, какой символ растет, а какой падает? В нашем конкретном случае, поскольку мы предполагаем, что после конвертации обе котировки золота должны быть одинаковыми, мы можем просто принять символ с большей ценой в качестве растущей пары, а другой — в качестве растущей. Если бы мы имели дело со спредом цен на акции, возвращающиеся к среднему значению, мы могли бы использовать экспоненциальную скользящую среднюю с очень коротким периодом и предположить, что символ, который торгуется выше EMA, растет, и наоборот.

bool IsRising(const int symbol)
  {
   switch(symbol)
     {
      case BASE_PAIR:
         //Print("Base pair is rising? ", quotes_base[0] > ema_base[0]);
         return quotes_base[0] > ema_base[0];
      case CORR_PAIR:
         //Print("Corr pair is rising? ", quotes_corr[0] > ema_corr[0]);
         return quotes_corr[0] > ema_corr[0];
      default:
         return false;
     }
  }

bool IsFalling(const int symbol)
  {
   switch(symbol)
     {
      case BASE_PAIR:
         //Print("Base pair is falling? ", quotes_base[0] < ema_base[0]);
         return quotes_base[0] < ema_base[0];
      case CORR_PAIR:
         //Print("Corr pair is falling? ", quotes_corr[0] < ema_corr[0]);
         return quotes_corr[0] < ema_corr[0];
      default:
         return false;
     }
  }
Или можем использовать наклон.

void CalculateSlopes(double & slope_b[], double & slope_c[])
  {
   slope_b[0] = MathAbs((quotes_base[0] - quotes_base[SlopePeriod]) / SlopePeriod);
   slope_c[0] = MathAbs((quotes_corr[0] - quotes_corr[SlopePeriod]) / SlopePeriod);
  }
В нашем случае просто используем символ с самой высокой ценой.

if(quotes_base[0] > quotes_corr[0])



Торговля портфелем

Мы создали простой экспертный советник для проверки своей гипотезы на исторических данных. 

Получаем при OnInit() начальные котировки и обновляем их в OnTimer(). Это связано с тем, что мы не можем полагаться на обработчик событий OnTick для обновления котировок пары, которая не является котировкой текущего рабочего графика, поскольку вызов OnTick() осуществляется только для текущего символа или графика. См. мультивалютные или мультисимвольные советники.

int OnInit()
  {
   ArrayResize(quotes_base, CountQuotes);
   ArrayResize(quotes_corr, CountQuotes);
   ArrayResize(quotes_conv, CountQuotes);
//--- Get start quotes for both pairs
   GetQuotes();
//--- EMA indicators
   EMA_Handle_Base = iMA(BasePair, _Period, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   EMA_Handle_Corr = iMA(CorrPair, _Period, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   if(EMA_Handle_Base == INVALID_HANDLE ||
      EMA_Handle_Corr == INVALID_HANDLE)
     {
      printf(__FUNCTION__ + ": EMA initialization failed");
      return(INIT_FAILED);
     }
//--- create timer
   EventSetTimer(5); // seconds
//---
   return(INIT_SUCCEEDED);
  }

bool GetQuotes()
  {
   if(CopyClose(BasePair, _Period, 0, CountQuotes, quotes_base) != CountQuotes)
     {
      Print(__FUNCTION__ + ": CopyClose failed. No data");
      //printf("Size quotes base pair %i ", ArraySize(quotes_base));
      return false;
     }
   if(CopyClose(CorrPair, _Period, 0, CountQuotes, quotes_corr) != CountQuotes)
     {
      Print(__FUNCTION__ + ": CopyClose failed. No data");
      //printf("Size quotes corr pair %i ", ArraySize(quotes_corr));
      return false;
     }
   if(CheckMode == PRICE)
     {
      if(CopyClose(ConvPair, _Period, 0, CountQuotes, quotes_conv) != CountQuotes)
        {
         Print(__FUNCTION__ + ": CopyClose failed. No data");
         //printf("Size quotes conv pair %i ", ArraySize(quotes_conv));
         return false;
        }
      //---
      for(int i = 0; i < CountQuotes; i++)
        {
         quotes_corr[i] *= quotes_conv[i];
        }
     }
   return true;
  }

void OnTimer()
  {
   UpdateQuotes();
   CalculateMeanSpread();
   if(CheckMode == EMA)
     {
      GetEMAs();
     }
  }

void UpdateQuotes()
  {
   ArrayRemove(quotes_base, ArraySize(quotes_base) - 1);
   double new_quote_base[1];
   CopyClose(BasePair, _Period, 0, 1, new_quote_base);
   ArrayInsert(quotes_base, new_quote_base, 0, 0);
//---
   ArrayRemove(quotes_corr, ArraySize(quotes_corr) - 1);
   double new_quote_corr[1];
   CopyClose(CorrPair, _Period, 0, 1, new_quote_corr);
   ArrayInsert(quotes_corr, new_quote_corr, 0, 0);
//---
   if(CheckMode == PRICE)
     {
      ArrayRemove(quotes_conv, ArraySize(quotes_conv) - 1);
      double new_quote_conv[1];
      CopyClose(ConvPair, _Period, 0, 1, new_quote_conv);
      ArrayInsert(quotes_conv, new_quote_conv, 0, 0);
      quotes_corr[0] *= quotes_conv[0];
     }
  }

Рассчитаем средний спред:

bool CalculateMeanSpread()
  {
   int sz_base_p = ArraySize(quotes_base);
   int sz_corr_p = ArraySize(quotes_corr);
   int sz_conv_p = ArraySize(quotes_conv);
   if(sz_base_p != sz_corr_p ||
      sz_corr_p != sz_conv_p)
     {
      Print(__FUNCTION__ + " Failed: Arrays must be of same size");
      return false;
     }
//---
   ArrayResize(pairs_spread, CountQuotes);
   for(int i = 0; i < sz_base_p; i++)
     {
      pairs_spread[i] = MathAbs(quotes_base[i] - quotes_corr[i]);
     }
   double max_spread = pairs_spread[ArrayMaximum(pairs_spread)];
   double min_spread = pairs_spread[ArrayMinimum(pairs_spread)];
   mean_spread = MathMean(pairs_spread);
//---
//printf("Last quote XAUUSD %f ", quotes_base[0]);
//printf("Last quote XAUEUR %f ", quotes_corr[0]);
//printf("Last spread %f ", pairs_spread[0]);
//printf("Max  spread %f ", max_spread);
//printf("Min  spread %f ", min_spread);
//printf("Mean spread %f ", mean_spread);
   return true;
  }

Проверяем торговые сигналы на OnTick.

void OnTick()
  {
//---
   CheckForClose();
   CheckForOpen();
  }

Когда спред больше среднего значения по крайней мере на установленный нами процент,

bool HasSpreadTrigger()
  {
   double trigger_spread = mean_spread + (mean_spread * (PercentTrigger / 100.0));
//printf(" trigger spread %f ", trigger_spread);
   double current_spread = pairs_spread[0];
//printf(" current spread %f ", current_spread);
   return current_spread >= trigger_spread;
  }

покупаем символ, цена которого низка, и продаем символ, цена которого высока. В нашем примере такое переключение выполняется для перечисления (enum) CheckMode. 

void CheckForOpen()
  {
   if(PositionsTotal() == 0 && HasSpreadTrigger())
     {
      switch(CheckMode)
        {
         case EMA:
            if(IsRising(BASE_PAIR) && IsFalling(CORR_PAIR))
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            if(IsFalling(BASE_PAIR) && IsRising(CORR_PAIR))
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
            break;
         case SLOPE:
            CalculateSlopes(slope_base, slope_corr);
            if(slope_base[0] > slope_corr[0])
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            else
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
            break;
         case PRICE:
            if(quotes_base[0] > quotes_corr[0])
              {
               OpenShort(BasePair);
               OpenLong(CorrPair);
              }
            else
              {
               OpenLong(BasePair);
               OpenShort(CorrPair);
              }
        }
     }
  }

Позиции будут закрыты по стоп-лоссу или тейк-профиту либо по возврату к среднему значению на CheckForClose().

void CheckForClose()
  {
   int total = PositionsTotal();
   ulong ticket = 0;
   if(total > 0)
     {
      if(PositionSelect(BasePair) || PositionSelect(CorrPair))
        {
         for(int i = 0; i < total; i++)
           {
            ticket = PositionGetTicket(i);
            if(ticket == 0)
               continue;
            if(pairs_spread[0] <= mean_spread)
              {
               ExtTrade.PositionClose(ticket);
              }
           }
        }
     }
  }

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

Рис. 1. График капитала при тестировании на исторических данных

Рис. 3. График капитала по результатам тестирования на исторических данных

Хотя тестирование на исторических данных подтверждает нашу гипотезу, вы можете видеть, что этот конкретный алгоритм требует усовершенствований для сглаживания кривой капитала. Возможно, динамический размер ордера (объем торговли здесь зафиксирован на уровне минимум 0.01 - микролот) и оптимизация соотношения стоп-лосс / тейк-профит. Но не прибыльность является главным поводом для нашего беспокойства в этой статье. Тем не менее, рассмотрим некоторые интересные результаты, которые, по мнению некоторых авторов, представляются обычными для операций статистического арбитража.

Рис. 2. Результаты тестирования на исторических данных

Рис 4. Результаты тестирования на истории

Количество сделок большое, соотношение между выигрышами и проигрышами невелико (примерно 55 / примерно 45), а максимальная просадка баланса относительно низкая.

Рис. 3. Тестирование времени торговли на исторических данных

Рис. 5. Тестирование времени торговли на исторических данных

Концентрация в окрестностях определенных периодов (часов, дней недели и т. д.). В нашем случае концентрация приходится на открытие североамериканской сессии с пиком, приходящимся на апрель 2024 года.

Рис. 6. Прибыль X времени удержания позиций по тестированию на исторических данных

Рис. 6. Прибыль X времени удержания позиций по тестированию на исторических данных

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

Что может быть лучше?

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

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

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

  1. Контролировать количество открываемых позиций в зависимости от оцененного риска в каждой точке
  2. Располагать плавающим процентом спреда для срабатывания, который учитывает волатильность
  3. Разработать динамическую стратегию применению стоп-лосса/тейк-профита, которая извлекает вероятность прибыли из значения спреда для срабатывания и, возможно, других переменных

Вот некоторые возможные направления дальнейшего совершенствования этого советника.

Краткое описание масштабной модели

1. Начнем с гипотезы

Спред между коррелирующими парами имеет тенденцию возвращаться к среднему значению. Вот наша гипотеза для данного случая.

С точки зрения трейдера, концепция возврата к среднему значению проста и интуитивна: когда текущая цена ниже средней цены, можно ожидать, что она вырастет, а когда текущая цена выше средней цены, есть основания ожидать ее падения. Как говорится, цена всегда «ищет среднее значение».

Перекупленные или перепроданные ценные бумаги имеют тенденцию возвращаться к средней цене

Рис. 7. Перекупленные или перепроданные ценные бумаги имеют тенденцию возвращаться к средней цене (Источник: ResearchGate CC BY 4.0)

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

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

Например: «12 декабря 1980 года компания Apple начала торговать своими акциями на бирже по цене 22.00 доллара за акцию. С момента первого публичного размещения (IPO) акции дробились пять раз, поэтому с поправкой на дробление цена акции на момент IPO составляла 0.10 доллара».

На момент написания этой статьи акции Apple котируются по цене 192.00 доллара за акцию (около 875% от первоначальной). И они продолжают расти. Теоретического предела не существует.

С другой стороны, нельзя ожидать даже 50%-ного повышения или понижения обменных курсов между двумя валютами, не думая при этом о таких чрезвычайных факторах, как гиперинфляция или даже полномасштабная война. В обычных условиях обменный курс, определяющий «цену» пары при торговле на рынке Форекс, должен вернуться к среднему значению гораздо раньше.

2. Поиск закономерностей в данных для проверки гипотезы

Составляющая 0.97 корреляция Пирсона между XAUUSD и XAUEUR отражает нашу закономерность: цены на эти две ценные бумаги имеют тенденцию расти или падать одновременно.

3. Мониторинг аномалий в закономерностях

Наша аномалия — среднее значение спреда между XAUUSD и XAUEUR, сильно отклоняющееся от общего среднего значения. Нахождение аномалий в моделях рынка является основой статистического арбитража на уровне портфеля, поскольку именно это использовалось в работе команды Саймонса.

4. Разработка автоматических средств для торговли аномалиями

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


Заключение

Среднестатистический розничный трейдер практически не может применять статистический арбитраж на уровне портфеля в том виде, в каком его используют крупные игроки. Потому что нам нужно будет работать в сфере высокочастотной торговли (High-Frequency Trading, HFT), имея высококвалифицированную команду, высококачественные большие данные и большие деньги. Чтобы превратить нашу масштабную модель в нечто похожее или даже близкое к деятельности хедж-фонда Джима Саймонса, я сказал бы с долей иронии: все, что нам нужно, это иметь возможность

  • Проводить анализ рынка с точностью до секунды для сотен символов активов в каждом портфеле в режиме реального времени. (В какой-то момент команда Саймонса имела дело с более чем восемью тысячами различных акций на дюжине рынков и территорий.)
  • Отправлять ордера на миллионы долларов и заполнять их за миллионную долю секунды
  • Регулярно обновлять модель 

Что ж, полагаю, мы можем начать регулярное обновление модели. 🙂

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

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

Мы можем даже следовать по пути машинного обучения для обнаружения таких закономерностей и аномалий. Это доступно смертным, и, кажется, это будущее уже стало настоящим, прямо здесь и прямо сейчас. Существует в буквальном смысле сотни высококачественных статей об использовании машинного обучения в среде MetaTrader 5. Сегодня нам НЕ обязательно знать базовую математику, чтобы использовать в нашей торговой системе машинное обучение. Мы можем использовать MQL5 или Python, причем оба — с батареями, входящими в комплект поставки, то есть с библиотеками машинного обучения высокого уровня. 

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

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

Прикрепленный файл Описание
 pairs-trading.mq5 В этом файле содержится пример кода советника для воспроизведения эксперимента. Для этого требуется (#<include>) файл PairsTradingFunctions.mqh.
 PairsTradingFunctions.mqh Этот файл является включаемым, который требуется предыдущему файлу в этом списке, и на данный момент содержит только одно перечисление (enum) режима проверки, используемого советником для определения растущего/падающего символа в парах.
 pairs-trading.ipynb Этот файл представляет собой файл блокнота Jupyter, содержащий код на языке Python для запуска статистического анализа.
 stat_arb_pairs_trading_GOLD_XAUEUR.ini  Этот файл представляет собой настройки конфигурации Metatrader 5 Tester для воспроизведения эксперимента.


Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/17735

Прикрепленные файлы |
pairs-trading.mq5 (13.77 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (14)
Anthony Fidel
Anthony Fidel | 7 июл. 2025 в 00:33
Stanislav Korotky #:

Тогда весь режим с iMA будет неверным, потому что он привязан к барам. Вам нужно рассчитать MA по 5-секундным сэмплам вручную.

Как
Stanislav Korotky
Stanislav Korotky | 7 июл. 2025 в 11:20
Anthony Fidel #:
Как

Считать тиковую историю (реализовать самостоятельно с помощью функций CopyTicks/CopyTickRange или найти готовый индикатор/скрипт в кодовой базе) и вычислить 5-секундные виртуальные бары в виде массива, затем применить алгоритмы сглаживания из стандартной библиотеки (mqh-файлы, поставляемые вместе с MT5).

Janis Ozols
Janis Ozols | 16 сент. 2025 в 15:20

Не по теме статьи вопрос, но очень интересно...

Как получилось так, что статья опубликована сегодня (16 сентября), а первые комментарии к ней датируются 11 апреля?

Roman Shiredchenko
Roman Shiredchenko | 16 сент. 2025 в 15:28
Janis Ozols #:

Не по теме статьи вопрос, но очень интересно...

Как получилось так, что статья опубликована сегодня (16 сентября), а первые комментарии к ней датируются 11 апреля?

это же перевод как я понял с другого языка форума.... на родном языке вышла раньше видимо... опубликована

Aleksey Nikolayev
Aleksey Nikolayev | 16 сент. 2025 в 16:23

> Сэр Исаак Ньютон в возрасте девяноста лет ...

Ньютон прожил 84 года (кривой перевод на русский?).

Особенности написания Пользовательских Индикаторов Особенности написания Пользовательских Индикаторов
Написание пользовательских индикаторов в торговой системе MetaTrader 4
Торговый инструментарий MQL5 (Часть 5): Расширение EX5-библиотеки для управления историей функциями последнего исполненного отложенного ордера Торговый инструментарий MQL5 (Часть 5): Расширение EX5-библиотеки для управления историей функциями последнего исполненного отложенного ордера
Узнайте, как создать EX5-модуль экспортируемых функций, который легко запрашивает и сохраняет данные последнего исполненного отложенного ордера. В этом пошаговом руководстве мы улучшим EX5-библиотеку для управления историей (History Management), разработав специализированные и обособленные функции для извлечения основных свойств последнего исполненного отложенного ордера. К этим свойствам относятся тип ордера, время установки, время исполнения, тип исполнения и другие важные данные, необходимые для эффективного управления и анализа истории торговли отложенными ордерами.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
От новичка до эксперта: Создание анимированного советника для новостей в MQL5 (VIII) — Кнопки быстрой торговли на новостях От новичка до эксперта: Создание анимированного советника для новостей в MQL5 (VIII) — Кнопки быстрой торговли на новостях
В то время как алгоритмические торговые системы управляют автоматизированными операциями, многие новостные трейдеры и скальперы предпочитают активный контроль во время важных новостных событий и быстро меняющихся рыночных условий, требующих быстрого исполнения ордеров и управления ими. Это подчеркивает необходимость в интуитивно понятных интерфейсных инструментах, которые объединяют новостные ленты в режиме реального времени, данные экономического календаря, аналитические данные по индикаторам, аналитику на основе ИИ и адаптивное управление торговлей.