English
preview
Создаем алгоритм маркет-мейкинга на MQL5

Создаем алгоритм маркет-мейкинга на MQL5

MetaTrader 5Трейдинг | 11 января 2024, 16:41
999 27
Yevgeniy Koshtenko
Yevgeniy Koshtenko

Что такое ликвидность

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

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

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

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


Как действует маркет-мейкер, и почему это не "кукловод"?

Многие трейдеры уверены в том, что маркет-мейкер является каким-то кукловодом, манипулятором, который двигает цены туда, куда ему нужно, срывает стопы толпы, разводит толпу на стоп-приказы, и т.п.

На самом деле, маркет-мейкеру совершенно не нужно сливать никакую "толпу". "Толпа" на рынке успешно сливается и сама по себе, благодаря постепенной потере на спреде, комиссии, и свопах. 

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

Без маркет-мейкеров рынок был бы совершенно другим: мы бы постоянно видели ценовые разрывы, разрывы котировок, наблюдали бы постоянные сквизы в обе стороны, огромные скачки цен в обе стороны. Все это и сегодня можно встретить на тех рынках, где присутствовать маркет-мейкеру невыгодно. К примеру, на многих грошовых акциях США (пенни-сток).


Новые технологии AMM на крипто-рынке

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

Примерно так появились децентрализованные биржи (DEX), на которых впервые был применен механизм АММ (автоматического маркет-мейкинга). Алгоритм АММ работает через специальный пул ликвидности, используя ресурс участников для сделок между ними, цена и объем обменов всегда будет контролироваться алгоритмом. Это позволяет свести всех продавцов со всеми покупателями, якобы без потерь для участников. На самом деле, на практике на всех DEX есть огромное проскальзывание цены, при большом объеме сделки вы гарантированно потеряете большой процент на обмене токенов.

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

Как маркет-мейкеры борятся с манипуляциями ценой?

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


Когда маркет-мейкеры уходят с рынка?

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

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


Что такое inventory risk у маркет-мейкера?

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

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

Разбираем отчетность крупнейшего маркет-мейкера планеты - компании Кена Гриффина

Анализируя активность крупнейшего маркет-мейкера в мире — компании Citadel Securities, основанной Кеном Гриффином — становится ясно, насколько важна их роль на финансовых рынках.

Отчеты компании говорят о впечатляющем влиянии: 7 из 10 сделок на американском фондовом рынке зависят от ликвидности, которую предоставляет этот маркет-мейкер. Такая активность свидетельствует о значимой функции Citadel Securities в поддержании стабильности и доступности ликвидности на данном рынке.

Чтобы оценить масштаб влияния компании Гриффина, можно упомянуть, что ежедневно через их алгоритмы проходит около 900 миллионов лотов акций США. Этот значительный объем торгов отражает высокую активность и влияние компании на американской фондовой бирже.

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

Что касается маркет-мейкеров на фондовом рынке РФ, то главную скрипку тут играет БрокерКредитСервис, или по-простому, БКС, почти все высоколиквидные акции первого эшелона котируются именно этой компанией. Также в качестве мейкеров работают Финам, АЛОР, и не совсем известный мне банк Держава. 

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

Заготовка эксперта - маркетмейкера

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

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

Самая простая реализация маркет-мейкинга на MQL5

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

//+------------------------------------------------------------------+
//|                                                  MarketMaker.mq5 |
//|                                Copyright 2023, Evgeniy Koshtenko |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Evgeniy Koshtenko"
#property link      "https://www.mql5.com/ru/users/koshtenko"
#property version   "1.00"

#include <Trade\Trade.mqh>        // Подключаем торговый класс CTrade

//--- входные параметры
input double Lots       = 0.1;    // лот
input double Profit     = 0.1;    // прибыль
input double BProfit    = 11;     // прибыль покупок
input double SProfit    = 11;     // прибыль продаж
input int StopLoss      = 0;      // стоп лосс
input int TakeProfit    = 0;      // тейк профит
input int    Count      = 5;      // число ордеров
input int    Delta      = 55;     // дельта
input int    Magic      = 123;    // магик

input bool   BuyLimit   = 1;      // Buy Limit
input bool   SellLimit  = 1;      // Sell Limit

input string Symbol1    = "EURUSD";
input string Symbol2    = "GBPUSD";
input string Symbol3    = "USDCHF";
input string Symbol4    = "USDJPY";
input string Symbol5    = "USDCAD";
input string Symbol6    = "AUDUSD";
input string Symbol7    = "NZDUSD";
input string Symbol8    = "EURGBP";
input string Symbol9    = "CADCHF";
input int MaxOrders = 20; // Макс. число ордеров
CTrade trade;

datetime t=0;
int delta=0;

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

Функции инициализации и деинициализации в целом стандартны. Функция OnInit() вызывается при запуске советника, а OnDeinit() при его завершении. OnInit() задает магический номер советника и таймер для работы торговой функции:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   // Установка таймера с разрешением 10000 миллисекунд (10 секунд)
   EventSetMillisecondTimer(100000);
   trade.SetExpertMagicNumber(Magic);
//---
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {// Отключение таймера
   EventKillTimer();
   Comment("");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

Вот функции подсчета открытых ордеров и открытых позиций. CountOrders и CountTrades занимаются подсчетом открытых ордеров и позиций для определенного символа с учетом магического номера советника.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountOrders(string symbol, ENUM_ORDER_TYPE orderType) {
  int count = 0;
  
  for(int i = OrdersTotal()-1; i >= 0; i--) {
      
    ulong ticket = OrderGetTicket(i);
      
    if(!OrderSelect(ticket)) {
      continue;
    }
      
    if(OrderGetInteger(ORDER_TYPE) != orderType) {
      continue;
    }
    
    if(PositionGetString(POSITION_SYMBOL) != symbol ||
       PositionGetInteger(POSITION_MAGIC) != Magic) {
      continue; 
    }
      
    count++;
  }
  
  return count;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountTrades(string symbol, ENUM_POSITION_TYPE type) {
  int count = 0;
  
  for(int i=PositionsTotal()-1; i>=0; i--) {
    
    ulong ticket=PositionGetTicket(i);
      
    if(!PositionSelectByTicket(ticket)) {
      continue;
    }
    
    if(PositionGetString(POSITION_SYMBOL)==symbol && 
       PositionGetInteger(POSITION_TYPE)==type) {
        
      count++;
    }
  }
  
  return count;
}

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

//+------------------------------------------------------------------+
//|  Position Profit                                                 |
//+------------------------------------------------------------------+
double AllProfit(string symbol, int positionType = -1) {

  double profit = 0;

  for(int i = PositionsTotal()-1; i >= 0; i--) {

    ulong ticket = PositionGetTicket(i);

    if(!PositionSelectByTicket(ticket)) {
      continue;
    }

    if(PositionGetString(POSITION_SYMBOL) != symbol ||
       PositionGetInteger(POSITION_MAGIC) != Magic) {
      continue;
    }

    if(positionType != -1 && 
       PositionGetInteger(POSITION_TYPE) != positionType) {
      continue;
    }

    profit += PositionGetDouble(POSITION_PROFIT);

  }

  return profit;

}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseAll(string symbol, int positionType = -1) {

  for(int i = PositionsTotal()-1; i >= 0; i--) {

    ulong ticket = PositionGetTicket(i);

    if(!PositionSelectByTicket(ticket)) {
      continue;
    }

    if(PositionGetString(POSITION_SYMBOL) != symbol ||
       PositionGetInteger(POSITION_MAGIC) != Magic) {
      continue;
    }

    if(positionType != -1 && 
       PositionGetInteger(POSITION_TYPE) != positionType) {
      continue;  
    }

    trade.PositionClose(ticket);

  }

}

И наконец, две главные функции - функция торговли и тиковая функция. Trade отвечает за размещение лимитных ордеров на покупку и продажу, учитывая заданные параметры. OnTimer вызывает функцию Trade для торговли выбранным символом и отображает информацию о прибыли для этого символа.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Trade(string symb)
  {
   double sl = 0, tp = 0;
   double pr=0;
   double Bid=SymbolInfoDouble(symb,SYMBOL_BID);
  
   if(AllProfit(symb)>Profit && Profit>0)
      CloseAll(symb);
   
   if(AllProfit(symb)>Profit && Profit>0)
      CloseAll(symb);
      
   if(AllProfit(symb,0)>BProfit && BProfit>0)
      CloseAll(symb,0);
  
      for(int i=1; i<=Count; i++)
        {
         if(BuyLimit)
           {
           
            if (StopLoss > 0)
                sl = NormalizeDouble(Bid - (StopLoss) * Point(), _Digits);
            if (TakeProfit > 0)
                tp = NormalizeDouble(Bid + (TakeProfit) * Point(), _Digits);
                
            pr=NormalizeDouble(Bid-(Delta+Step)*_Point*i,_Digits);
            trade.BuyLimit(Lots,pr,symb,sl, tp,0,0,"");
           }
         if(SellLimit)
           {
            
            if (StopLoss > 0)
                sl = NormalizeDouble(Bid + (_Point * StopLoss) * Point(), _Digits);
            if (TakeProfit > 0)
                tp = NormalizeDouble(Bid - (_Point * TakeProfit) * Point(), _Digits);
                
            pr=NormalizeDouble(Bid+(Delta+Step)*_Point*i,_Digits);
            trade.SellLimit(Lots,pr,symb,sl, tp,0,0,"");
           }
         
        }
     
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTimer()
  {
   DelOrder();
   Trade(Symbol1);
   Trade(Symbol2);
   Trade(Symbol3);
   Comment("\n All Profit: ",AllProfit(Symbol1),
           "\n Buy Profit: ",AllProfit(Symbol1,0),
           "\n Sell Profit: ",AllProfit(Symbol1,1));
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+--------+

Вот в целом и весь код данного простого эксперта.

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

Итак, запускаем советника с дефолтными настройками в тестере. Вот что советник выдал на парах EURUSD, GBPUSD, EURGBP, USDJPY, EURJPY, за период с 1 февраля 2023 по 18 февраля 2024:

Тест советника

Просадки по отношению к прибылям очень большие, просадка по средствам в целом больше годовой прибыли. Советник ведет себя не сильно иначе, чем себя ведут обычные сеточные советники. Вот статистика тестирования:

Статистика тестирования

Приходим к выводу, что данный советник никак не окупает свои риски. Как и любой алгоритм без стопа, он является бомбой замедленного действия. Несмотря на отсутствие сливов, не факт что на рынке не повторится история с обвалом валют на 10-15% за сутки. Лично меня последние четыре года научили, что на рынке возможно абсолютно все, и даже самые невероятные сценарии могут реализоваться, поэтому боевой советник должен быть готов ко всему. Данный эксперт не подходит под мои критерии оценки, поэтому я и решил его опубликовать.

Заключение

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


Прикрепленные файлы |
Experts.zip (34.63 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (27)
Roman Shiredchenko
Roman Shiredchenko | 15 янв. 2024 в 13:04
JRandomTrader #:

Как-то давно в одном из неликвидных фьючей сам был "маркетмейкером" - до четверти всех сделок были мои. Хотя были там и мощные заявки от настоящего маркетоса, но в отдалении от актуальных цен.

Ну вот.... ;-)
Roman Shiredchenko
Roman Shiredchenko | 15 янв. 2024 в 13:04
Renat Akhtyamov #:

там клиринг все решает

да.... ;-)
Sergey Chalyshev
Sergey Chalyshev | 16 янв. 2024 в 19:14
Renat Akhtyamov #:

там клиринг все решает

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

Renat Akhtyamov
Renat Akhtyamov | 16 янв. 2024 в 20:04
Sergey Chalyshev #:

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

мне больше ничо не надо, все уже есть

Stanislav Korotky
Stanislav Korotky | 26 янв. 2024 в 16:46
Описанный алгоритм применим только к хеджинговым счетам или есть вариант для неттинга?
Нейросети — это просто (Часть 72): Прогнозирование траекторий в условиях наличия шума Нейросети — это просто (Часть 72): Прогнозирование траекторий в условиях наличия шума
Качество прогнозирование будущих состояний играет важную роль в метода Goal-Conditioned Predictive Coding, с которым мы познакомились в предыдущей статье. В данной статье я хочу познакомить Вас с алгоритмом, способным значительно повысить качество прогнозирования в стохастических средах, к которым можно отнести и финансовые рынки.
Разметка данных в анализе временных рядов (Часть 1):Создаем набор данных с маркерами тренда с помощью графика советника Разметка данных в анализе временных рядов (Часть 1):Создаем набор данных с маркерами тренда с помощью графика советника
В этой серии статей представлены несколько методов маркировки временных рядов, которые могут создавать данные, соответствующие большинству моделей искусственного интеллекта (ИИ). Целевая маркировка данных может сделать обученную модель ИИ более соответствующей пользовательским целям и задачам, повысить точность модели и даже помочь модели совершить качественный скачок!
Выставление ордеров в MQL5 Выставление ордеров в MQL5
При создании любой торговой системы есть задача, которую необходимо эффективно решить. Эта задача заключается в выставлении ордеров либо в их автоматической обработке торговой системой. В статье рассмотрено создание торговой системы с точки зрения эффективного выставления ордеров.
Популяционные алгоритмы оптимизации: Гибридный алгоритм оптимизации бактериального поиска с генетическим алгоритмом (Bacterial Foraging Optimization - Genetic Algorithm, BFO-GA) Популяционные алгоритмы оптимизации: Гибридный алгоритм оптимизации бактериального поиска с генетическим алгоритмом (Bacterial Foraging Optimization - Genetic Algorithm, BFO-GA)
В статье представлен новый подход к решению оптимизационных задач, путём объединения идей алгоритмов оптимизации бактериального поиска пищи (BFO) и приёмов, используемых в генетическом алгоритме (GA), в гибридный алгоритм BFO-GA. Он использует роение бактерий для глобального поиска оптимального решения и генетические операторы для уточнения локальных оптимумов. В отличие от оригинального BFO бактерии теперь могут мутировать и наследовать гены.