В поисках постоянного спреда.

В поисках постоянного спреда.

29 января 2023, 21:12
fxsaber
5
272

Сидите перед монитором десятки минут, видите, как по символу приходят сотни тиков. Как думаете, сколько раз за это время изменился спред? Да и вообще, как такая ерунда может заинтересовать, ведь, очевидно, что спред будет меняться!


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


Смотрел только рынок FOREX на некоторых noname-брокерах.

Ниже исходный код и результаты.


Исходник.

#include <fxsaber\ThirdPartyTicks\Array.mqh> // https://www.mql5.com/ru/code/20225
#include <fxsaber\Calendar\String.mqh> // https://www.mql5.com/ru/code/32430

input datetime inFrom = D'2023.01.09';

ArraySortStruct2_Define(Length) // https://www.mql5.com/ru/forum/170952/page222#comment_40289584

struct SPREAD
{
private:  
  static double GetSpread( const MqlTick &Tick )
  {
    return(::NormalizeDouble(Tick.ask - Tick.bid, 8));
  }
  
  static string TimeToString( const ulong Time )
  {
    return((string)(datetime)(Time / 1000) + "." + ::IntegerToString(Time % 1000, 3, '0'));
  }
  
public:  
  ulong Begin;
  ulong End;
  
  int Count;
  ulong Length;
  
  double Spread;
  
  STRING16 Name;

  SPREAD( void ) : Count(0), Spread(0)
  {
  }
  
  void Init( const MqlTick &Tick )
  {
    this.Begin = Tick.time_msc;
    this.End = this.Begin;
    
    this.Spread = SPREAD::GetSpread(Tick);
    this.Count = 1;
    
    this.Length = 0;
    
    return;
  }    
  
  bool Add( const MqlTick &Tick )
  {
    const double NewSpread = SPREAD::GetSpread(Tick);
    const bool Res = (this.Spread == NewSpread) && (Tick.time_msc  - this.End < 3600 * 1000);
    
    if (Res)
    {
      this.End = Tick.time_msc;
      this.Count++;      
    }
    else if (Tick.time_msc  - this.End < 3600 * 1000)
      this.End = Tick.time_msc;
      
    this.Length = this.End - this.Begin;
        
    return(Res);
  }
  
  string ToString( void ) const
  {
    return("Length = " + ::StringSubstr(SPREAD::TimeToString(this.Length), ::StringLen("xxxx.xx.xx ")) + 
           ", Ticks = " + ::IntegerToString(this.Count, 4, ' ') + 
           ", " + this.Name[] + "_spread = " +
           ::IntegerToString((int)(this.Spread / ::SymbolInfoDouble(this.Name[], SYMBOL_POINT) + 0.1), 4, ' ') +
           ", "+ " " + SPREAD::TimeToString(this.Begin) + " - " + SPREAD::TimeToString(this.End));
  }
};

bool AddData( SPREAD &Spreads[], const string Symb, const datetime From, const int MinTicks = 100, const int Amount = 1000 )
{
  MqlTick Ticks[];

  const int Size = CopyTicksRange(Symb, Ticks, COPY_TICKS_ALL, From * 1000);
  
  SPREAD Spread;;
  Spread.Name = Symb;
  
  for (int i = 0; i < Size; i++)
    if (!Spread.Add(Ticks[i]))
    {
      if ((Spread.Count >= MinTicks) && Spread.Spread)
        ARRAY::AddElement(Spreads, Spread, 100000);
      
      Spread.Init(Ticks[i]);
    }
    
  ArraySortStruct2(Spreads, Length);
  
  ArrayReverse(Spreads);
  ArrayResize(Spreads, MathMin(ArraySize(Spreads), Amount));
    
  return(Size > 0);
}

void OnStart()
{
  const string ServerName = AccountInfoString(ACCOUNT_SERVER);
  SPREAD Spreads[];
  
  for (int i = SymbolsTotal(true) - 1; i >= 0; i--)
  {
    const string Symb =SymbolName(i, true);
    
    if (!SymbolInfoInteger(Symb, SYMBOL_CUSTOM) && SymbolInfoInteger(Symb, SYMBOL_VISIBLE))
    {
      const string Str = (string)i + ": " + Symb + "_" + ServerName + " from " + (string)inFrom + " - ";;
      
      Comment(Str + "calculating...");
      
      Alert(Str + (string)AddData(Spreads, Symb, inFrom));
    }
  }

  Comment("");

  Print(ServerName + " from " + (string)inFrom);
  
  for (int i = 0; i < 100; i++)
    Print(IntegerToString(i, 2, '0') + ": " + Spreads[i].ToString());
}


Noname1.

Tickmill-Live from 2023.01.09 00:00:00
00: Length = 01:21:58.610, Ticks =  547, EURSGD_spread =   500,  2023.01.23 00:06:43.957 - 2023.01.23 01:28:42.567
01: Length = 01:15:14.474, Ticks =  208, USDSGD_spread =   200,  2023.01.23 00:51:36.983 - 2023.01.23 02:06:51.457
02: Length = 01:01:27.143, Ticks =  330, EURSGD_spread =   500,  2023.01.16 00:00:30.077 - 2023.01.16 01:01:57.220
03: Length = 00:57:57.114, Ticks =  189, EURSGD_spread =   500,  2023.01.09 00:02:45.148 - 2023.01.09 01:00:42.262
04: Length = 00:55:28.760, Ticks =  174, NZDSGD_spread =   500,  2023.01.09 00:04:34.152 - 2023.01.09 01:00:02.912
05: Length = 00:55:02.365, Ticks =  142, GBPSEK_spread = 10000,  2023.01.20 00:10:00.429 - 2023.01.20 01:05:02.794
06: Length = 00:44:43.227, Ticks = 1139, GBPCHF_spread =    32,  2023.01.10 08:00:25.525 - 2023.01.10 08:45:08.752
07: Length = 00:39:10.978, Ticks =  146, EURSGD_spread =   500,  2023.01.13 00:16:32.769 - 2023.01.13 00:55:43.747
08: Length = 00:35:30.601, Ticks =  109, GBPCAD_spread =   450,  2023.01.13 00:24:29.678 - 2023.01.13 01:00:00.279
09: Length = 00:33:41.767, Ticks =  538, EURCHF_spread =     8,  2023.01.13 20:00:29.187 - 2023.01.13 20:34:10.954
10: Length = 00:33:23.316, Ticks =  291, EURNOK_spread =  4000,  2023.01.16 01:45:14.165 - 2023.01.16 02:18:37.481

В первой строке показано, что 81 минуту спред на EURSGD не менялся, при этом пришло 547 тиков. Сам спред был 500.

Обращает внимание, что значения спредов почти по всем приведенным символам круглые. Например, спред GBPSEK = 10000 пипсов ровно.


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

  • Реальный спред гораздо больше. И чтобы не сносило стопы, максимальный спред ограничен заданным числом.
  • Высока вероятность раздевания брокера на этом суточном интервале/символе, поэтому держит столь высокий спред.

Однако, выделяется GBPCHF - не ролловер. Сложно объяснить, зачем в течение 44-х минут брокер дал 1139 подряд тиков без изменения спреда. Возможно, технический сбой.


Noname2.

ICMarketsSC-MT5 from 2023.01.09 00:00:00
00: Length = 01:16:43.571, Ticks = 1034, AUDSGD_spread =   22,  2023.01.23 01:18:52.473 - 2023.01.23 02:35:36.044
01: Length = 01:00:05.359, Ticks =  318, CHFSGD_spread =  500,  2023.01.16 00:04:55.096 - 2023.01.16 01:05:00.455
02: Length = 00:57:39.937, Ticks =  395, GBPUSD_spread =   70,  2023.01.16 00:02:20.282 - 2023.01.16 01:00:00.219
03: Length = 00:56:04.979, Ticks =  177, USDSGD_spread =  250,  2023.01.16 00:04:55.046 - 2023.01.16 01:01:00.025
04: Length = 00:55:05.173, Ticks =  322, GBPCHF_spread =  200,  2023.01.16 00:04:55.038 - 2023.01.16 01:00:00.211
05: Length = 00:48:48.990, Ticks =  280, AUDSGD_spread =  200,  2023.01.16 00:12:11.099 - 2023.01.16 01:01:00.089
06: Length = 00:46:59.475, Ticks =  214, GBPCHF_spread =  200,  2023.01.13 00:00:01.874 - 2023.01.13 00:47:01.349
07: Length = 00:46:47.711, Ticks =  464, GBPJPY_spread =  200,  2023.01.13 00:00:01.829 - 2023.01.13 00:46:49.540
08: Length = 00:45:36.329, Ticks = 2326, CHFJPY_spread =  200,  2023.01.17 00:02:33.427 - 2023.01.17 00:48:09.756
09: Length = 00:43:10.653, Ticks =  268, GBPCAD_spread =  200,  2023.01.13 00:00:01.645 - 2023.01.13 00:43:12.298
10: Length = 00:41:54.697, Ticks = 1118, XAUUSD_spread =    9,  2023.01.12 01:04:44.544 - 2023.01.12 01:46:39.241

На этом брокере почти такая же картина с круглыми спредами.


Оставил только CHF-символы.

08: Length = 00:32:48.672, Ticks = 1743, GBPCHF_spread =   26,  2023.01.16 01:00:00.211 - 2023.01.16 01:32:48.883
10: Length = 00:31:35.540, Ticks =  864, GBPCHF_spread =   26,  2023.01.20 01:00:00.243 - 2023.01.20 01:31:35.783
13: Length = 00:30:07.934, Ticks = 1140, CADCHF_spread =   15,  2023.01.16 01:00:00.218 - 2023.01.16 01:30:08.152
16: Length = 00:27:21.244, Ticks =  387, GBPCHF_spread =   26,  2023.01.11 01:00:00.230 - 2023.01.11 01:27:21.474
20: Length = 00:23:45.795, Ticks =  569, AUDCHF_spread =   13,  2023.01.18 01:00:00.235 - 2023.01.18 01:23:46.030
24: Length = 00:22:18.612, Ticks =  778, GBPCHF_spread =   26,  2023.01.27 01:00:00.190 - 2023.01.27 01:22:18.802
25: Length = 00:21:41.541, Ticks =  945, AUDCHF_spread =   13,  2023.01.16 01:00:00.220 - 2023.01.16 01:21:41.761
28: Length = 00:20:27.507, Ticks = 1102, GBPCHF_spread =   26,  2023.01.12 01:00:04.286 - 2023.01.12 01:20:31.793
29: Length = 00:19:52.241, Ticks =  453, AUDCHF_spread =   13,  2023.01.20 01:00:00.243 - 2023.01.20 01:19:52.484
31: Length = 00:17:55.349, Ticks =  296, CADCHF_spread =   15,  2023.01.20 01:04:58.239 - 2023.01.20 01:22:53.588
33: Length = 00:17:06.185, Ticks =  897, GBPCHF_spread =   26,  2023.01.25 01:00:00.222 - 2023.01.25 01:17:06.407
34: Length = 00:17:05.645, Ticks =  383, GBPCHF_spread =   26,  2023.01.23 01:00:00.266 - 2023.01.23 01:17:05.911
35: Length = 00:17:04.727, Ticks =  344, CADCHF_spread =   15,  2023.01.18 01:00:00.232 - 2023.01.18 01:17:04.959
36: Length = 00:16:53.920, Ticks =  807, AUDCHF_spread =   13,  2023.01.12 01:00:00.207 - 2023.01.12 01:16:54.127
37: Length = 00:16:48.420, Ticks =  481, AUDCHF_spread =   13,  2023.01.23 01:00:00.265 - 2023.01.23 01:16:48.685
38: Length = 00:16:38.373, Ticks =  515, GBPCHF_spread =   26,  2023.01.18 01:00:00.236 - 2023.01.18 01:16:38.609
39: Length = 00:16:19.085, Ticks =  299, AUDCHF_spread =   13,  2023.01.25 01:00:00.222 - 2023.01.25 01:16:19.307
41: Length = 00:15:36.084, Ticks =  318, CADCHF_spread =   15,  2023.01.23 01:00:31.181 - 2023.01.23 01:16:07.265
42: Length = 00:15:01.875, Ticks =  352, CADCHF_spread =   15,  2023.01.13 01:00:00.218 - 2023.01.13 01:15:02.093
43: Length = 00:15:00.227, Ticks =  701, CADCHF_spread =   15,  2023.01.27 01:00:00.185 - 2023.01.27 01:15:00.412
44: Length = 00:15:00.118, Ticks =  331, AUDCHF_spread =   13,  2023.01.27 01:00:00.189 - 2023.01.27 01:15:00.307
45: Length = 00:14:05.477, Ticks =  128, CADCHF_spread =   15,  2023.01.11 01:01:01.543 - 2023.01.11 01:15:07.020
46: Length = 00:13:36.015, Ticks =  531, GBPCHF_spread =   26,  2023.01.19 01:00:00.077 - 2023.01.19 01:13:36.092
47: Length = 00:12:45.220, Ticks =  432, GBPCHF_spread =   26,  2023.01.13 01:03:22.394 - 2023.01.13 01:16:07.614
48: Length = 00:12:36.700, Ticks =  408, CADCHF_spread =   15,  2023.01.12 01:05:33.438 - 2023.01.12 01:18:10.138
49: Length = 00:11:57.105, Ticks =  496, CADCHF_spread =   15,  2023.01.25 01:00:00.214 - 2023.01.25 01:11:57.319
50: Length = 00:11:50.949, Ticks =  186, AUDCHF_spread =   13,  2023.01.26 01:00:00.124 - 2023.01.26 01:11:51.073
51: Length = 00:11:50.872, Ticks =  323, CADCHF_spread =   15,  2023.01.26 01:00:00.203 - 2023.01.26 01:11:51.075
52: Length = 00:11:38.345, Ticks =  189, CADCHF_spread =   15,  2023.01.24 01:00:00.151 - 2023.01.24 01:11:38.496
53: Length = 00:11:36.444, Ticks =  152, GBPCHF_spread =   26,  2023.01.26 01:00:00.219 - 2023.01.26 01:11:36.663

Обращает внимание, что спреды некрупные и сразу после часа ночи. Зачем это нужно брокеру? Это не совпадение, т.к. спреды повторяются.


Две гипотезы.

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


Итог.

Как видите, никакой полезной информации. Вы зря потратили свое время. Не пишите такие скрипты, как приложенный ниже.


Файлы: