← К каталогу
Исходный код · ID 3299

trade-arbitrage(1).mq4

Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

Trade-Arbitrage — это советник для MetaTrader 4, написанный на MQL4. Программа анализирует валютные пары из заданного списка и генерирует синтетические символы на основе комбинаций реальных пар, доступных в Market Watch. Для каждого сгенерированного символа рассчитываются цены Bid и Ask по различным вариантам его получения.

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

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

Настройки программы

НастройкаОписание
Currencies Валюты — Список валют через запятую, используемых для генерации пар и синтетических символов
Магик (Magic) Магик — Магический номер для идентификации ордеров советника
Минимальная учитываемая разница арбитража в "старых" пунктах (MinPips) Минимальная учитываемая разница арбитража в "старых" пунктах — Минимальная учитываемая разница арбитража в старых пунктах
Допустимый SlipPage для Market-запросов (не всегда работает) (SlipPage) Допустимый SlipPage для Market-запросов (не всегда работает) — Допустимое проскальзывание для рыночных запросов (не всегда работает)
Разрешать локи или нет (Lock) Разрешать локи или нет — Разрешает или запрещает локирование (хеджирование) позиций
Объем позиции по сгенерированному символу (Lots) Объем позиции по сгенерированному символу — Объём позиции по сгенерированному символу
MaxLot Максимальный объём лота — Максимально допустимый объём лота
Необходимо задавать из-за некорректного возвращаемого знечения MarketInfo (MinLot) Необходимо задавать из-за некорректного возвращаемого знечения MarketInfo — Минимально допустимый объём лота, необходим из-за некорректного возвращаемого значения MarketInfo
Производить запись всех случающихся арбитражей в файл или нет (запись занимает время, которое критич (Monitoring) Производить запись всех случающихся арбитражей в файл или нет (запись занимает время, которое критич — Производит запись всех происходящих арбитражей в файл или нет. Запись занимает время, которое критично для арбитража
Через какое время (в минутах) будут записываться в файл статистические данные об арбитраже (TimeToWrite) Через какое время (в минутах) будут записываться в файл статистические данные об арбитраже — Через какое время в минутах будут записываться в файл статистические данные об арбитраже
Получить полный код

Поиск по коду файла

#include <stdlib.mqh> // string ErrorDescription(int error_code);

#define PAUSE 50      // Пауза в миллисекундах между расчетами
#define ALPHA 0.001   // Для сравнения объемов

#define STR_SHABLON "<!--STR-->"

#define MAX_CURRENCY 20       // Максимальное количество валют (не пар)
#define MAX_REALSYMBOLS 380   // Максимальное количесво учитываемых реальных сиволов из Market Watch (== (MAX_CURRENCY * (MAX_CURRENCY - 1)))
#define MAX_ALLSYMBOLS 380    // Максимальное количество возможных символов (== (MAX_CURRENCY * (MAX_CURRENCY - 1)))
#define MAX_VARIANTSYMBOLS 74 // Максимальное количество вариантов получения символа (== (4 * MAX_CURRENCY - 6))
#define MAX_VARIANTPAIRS 5402 // Максимальное количество сочетаний пар символов (== (MAX_VARIANTSYMBOLS * (MAX_VARIANTSYMBOLS - 1))

input string Currencies = "EUR, GBP, USD, CHF, JPY, NZD, AUD, CAD, SGD";
input int Magic       = 78787; // Магик
input double MinPips = 0.5;    // Минимальная учитываемая разница арбитража в "старых" пунктах
input int SlipPage = 0;        // Допустимый SlipPage для Market-запросов (не всегда работает)
input bool Lock = false;       // Разрешать локи или нет
input double Lots = 0.01;      // Объем позиции по сгенерированному символу
extern double MaxLot = 0.02;   //
extern double MinLot = 0.01;   // Необходимо задавать из-за некорректного возвращаемого знечения MarketInfo
input bool Monitoring = false; // Производить запись всех случающихся арбитражей в файл или нет (запись занимает время, которое критично для арбитража)
extern int TimeToWrite = 5;    // Через какое время (в минутах) будут записываться в файл статистические данные об арбитраже

int DigitsLot; // Количество цифр после запятой в десятичной записи лотов
string SymbolPrefix = "ffx";   // Префикс, который добавлен в Market Watch после стандартного написания пары

string Shablon = "<!--STR-->, <!--STR-->";  // Шаблон для выдирания чего угодно из строки. Нужен для Currencies

int AmountCurrency;            // Общее количество учитываемых валют
string Currency[MAX_CURRENCY]; // Учитываемые валюты

int AmountRealSymbols;  // Общее количество учитываемых реальных символов из Market Watch
string RealSymbols[MAX_REALSYMBOLS];  // Хранит стандартные (без префиксов) названия реальных символов из Market Watch
string REALSymbols[MAX_REALSYMBOLS];  // Хранит РЕАЛЬНЫЕ (с учетом префиксов) названия реальных символов из Market Watch

int AmountAllSymbols;                               // Общее количество сгенерированных пар (реальные + искусственные)
int AllSymbols[MAX_ALLSYMBOLS][MAX_VARIANTSYMBOLS]; // [k][m] - хранит номера реальных символов для создания k-го символа
int Math[MAX_ALLSYMBOLS][MAX_VARIANTSYMBOLS];       // [k][m] - хранит мат. действие создания k-го символа из m-х реальных символов
int Count[MAX_ALLSYMBOLS];                          // [k] - количество вариантов получения k-го символа.

double PointD[MAX_ALLSYMBOLS];   // [k] - хранит размер (старого) пункта  k-го символа
double MinPipsD[MAX_ALLSYMBOLS]; // [k] - хранит MinPips старых пунктов  k-го символа

double Bids[MAX_ALLSYMBOLS][MAX_VARIANTSYMBOLS];  // [k][m] - хранит Bid к-го символа полученного из m-х реальных символов
double Asks[MAX_ALLSYMBOLS][MAX_VARIANTSYMBOLS];  // [k][m] - хранит Ask к-го символа полученного из m-х реальных символов

double BidsReal[MAX_REALSYMBOLS]; // Bid-цены реальных символов
double AsksReal[MAX_REALSYMBOLS]; // Ask-цены реальных символов

double Position[MAX_REALSYMBOLS]; // Хранит направления и объем реальных символов для открытия
double XPosition[MAX_ALLSYMBOLS][MAX_VARIANTPAIRS];  // [k][] - Хранит арбитражное направление (+/-) и объем сразу двух вариантов получения k-го символа 
bool XTrade[MAX_ALLSYMBOLS][MAX_VARIANTPAIRS];       // [k][] - Хранит разрешение/запрет на осуществление арбитража между двумя вариантами получения k-го символа

int CountArbitrage[MAX_ALLSYMBOLS][MAX_VARIANTPAIRS];// [k][] - Хранит количество арбитражней сразу двух вариантов получения k-го символа 
int MaxCountArbitrage;

int PrevTime, CurrentTime; // Предыдущее (для записи статистики) и крайнее время сервера

string StrOut = "";        // Вывод в лог  
datetime newbar=0;

/************************************************* BEGIN BLOCK_1 *************************************************/

/************************************************* BEGIN BLOCK_1 *************************************************/

string StrDelSpaces( string Str )
{
  int Pos, Length;

  Str = StringTrimLeft(Str);
  Str = StringTrimRight(Str);

  Length = StringLen(Str) - 1;
  Pos = 1;

  while (Pos < Length)
    if (StringGetChar(Str, Pos) == ' ')
    {  
      Str = StringSubstr(Str, 0, Pos) + StringSubstr(Str, Pos + 1, 0);
      Length--;
    }
    else 
      Pos++;

  return(Str);
}

int StrToStringS( string Str, string Razdelitel, string &Output[] )
{
  int Pos, LengthSh;
  int _Count = 0;

  Str = StrDelSpaces(Str);
  Razdelitel = StrDelSpaces(Razdelitel);

  LengthSh = StringLen(Razdelitel);

  while (true)
  {
    Pos = StringFind(Str, Razdelitel);
    Output[_Count] = StringSubstr(Str, 0, Pos);
    _Count++;

    if (Pos == -1)
      break;

    Pos += LengthSh;
    Str = StringSubstr(Str, Pos);
  }

  return(_Count);
}

bool RealSymbol( string Str )
{
  return(MarketInfo(Str + SymbolPrefix, MODE_BID) != 0);
}

void GetRealSymbols()
{
  int i, j;
  string Str;

  AmountRealSymbols = 0;

  for (i = 0; i < AmountCurrency; i++)
    for (j = 0; j < AmountCurrency; j++)
      if (i != j)  // пары должны быть из разных валют
      {
        Str = Currency[i] + Currency[j];  // образуем различные комбинации пар

        if (RealSymbol(Str))
        {
          RealSymbols[AmountRealSymbols] = Str;
          REALSymbols[AmountRealSymbols] = Str + SymbolPrefix;  // в дальнейшем понадобится для ускорения расчетов
          AmountRealSymbols++;
        }
      }

  return;
}

int GetNumRealSymbol( string Str )
{
  int i;

  for (i = 0; i < AmountRealSymbols; i++)
    if (RealSymbols[i] == Str)
      return(i);

  return(-1);
}

void GetAllSymbols()
{
  int i, j, k, m;
  string Str, Str1[4], Str2[4];

  AmountAllSymbols = 0; // инициализировали количество учитываемых сгенерированных пар

  for (i = 0; i < MAX_ALLSYMBOLS; i++)
    Count[i] = 0;  // инициализировали количество вариантов получения учитываемых сгенерированных пар

  for (i = 0; i < AmountCurrency; i++) // Строим пару именно ij (не наоборот!!!)
    for (j = 0; j < AmountCurrency; j++)
      if (i != j)  // Пара должна состоять из разных валют
      {
        Str = Currency[i] + Currency[j];  // Создали пару ij

        if (RealSymbol(Str)) // Если пара реальная, то (первый) вариант ее получения - она сама.
        {
          AllSymbols[AmountAllSymbols][Count[AmountAllSymbols]] = GetNumRealSymbol(Str);
          Math[AmountAllSymbols][Count[AmountAllSymbols]] = -1; // -2 - "1 / S"; -1 - "S"; 0 - "S1 / S2"; 1 - "S1 * S2"; 2 - "1 / (S1 * S2)"; 3 - "S2 / S1"
          Count[AmountAllSymbols]++;
        }

        Str = Currency[j] + Currency[i];  // Создали обратную пару - ji

        if (RealSymbol(Str)) // Если обратная пара реальная, то вариант получения прямой пары - 1 / обратную.
        {
            AllSymbols[AmountAllSymbols][Count[AmountAllSymbols]] = GetNumRealSymbol(Str);
            Math[AmountAllSymbols][Count[AmountAllSymbols]] = -2; // -2 - "1 / S"; -1 - "S"; 0 - "S1 / S2"; 1 - "S1 * S2"; 2 - "1 / (S1 * S2)"; 3 - "S2 / S1"
            Count[AmountAllSymbols]++;
        }

        for (k = 0; k < AmountCurrency; k++)
          if ((k != i) && (k != j))
          {

            Str1[0] = Currency[i] + Currency[k];
            Str1[1] = Currency[i] + Currency[k];
            Str1[2] = Currency[k] + Currency[i];
            Str1[3] = Currency[k] + Currency[i];

            Str2[0] = Currency[j] + Currency[k];
            Str2[1] = Currency[k] + Currency[j];
            Str2[2] = Currency[j] + Currency[k];
            Str2[3] = Currency[k] + Currency[j];

            for (m = 0; m < 4; m++)
              if (RealSymbol(Str1[m]) && RealSymbol(Str2[m]))
              {

                AllSymbols[AmountAllSymbols][Count[AmountAllSymbols]] = GetNumRealSymbol(Str1[m]) * AmountRealSymbols + GetNumRealSymbol(Str2[m]);
                Math[AmountAllSymbols][Count[AmountAllSymbols]] = m; // 0 - "S1 / S2"; 1 - "S1 * S2"; 2 - "1 / (S1 * S2)"; 3 - "S2 / S1"
                Count[AmountAllSymbols]++;
              }
          }

        if (Count[AmountAllSymbols] >= 2) // Если вариантов получения ij-пары не меньше двух 

          AmountAllSymbols++; // Увеличили количество учитываемых сгенерированных пар
        else  // Иначе - не учитываем
          Count[AmountAllSymbols] = 0;
      }

  return;
}

void GetRealBidAsk()
{
  for (int i = 0; i < AmountRealSymbols; i++)
  {
    BidsReal[i] = MarketInfo(REALSymbols[i], MODE_BID);
    AsksReal[i] = MarketInfo(REALSymbols[i], MODE_ASK);
  }

  return;
}

string SymbolToStr( int i, int j )
{
  string Str = "", S1, S2;

  if (Math[i][j] == -1) // 
    Str = RealSymbols[AllSymbols[i][j]];
  else if (Math[i][j] == -2)
    Str = "1 / " + RealSymbols[AllSymbols[i][j]];
  else
  {
    S1 = RealSymbols[AllSymbols[i][j] / AmountRealSymbols];  // получили название первой пары
    S2 = RealSymbols[AllSymbols[i][j] % AmountRealSymbols];  // получили название второй пары

    switch (Math[i][j])
    {
      case 0: // 0 - "S1 / S2"
        Str = S1 + " / " + S2;
        break;
      case 1: // 1 - "S1 * S2"
        Str = S1 + " * " + S2;
        break;
      case 2: // 2 - "1 / (S1 * S2)";
        Str = "1 / (" + S1 + " * " + S2 + ")";
        break;
      case 3: // 3 - "S2 / S1"
        Str = S2 + " / " + S1;
        break;
     }
   }

  return(Str);
}  

void GetDataLot( string Symb )
{
  int Tmp = 1 / MarketInfo(Symb, MODE_LOTSTEP) + 0.01;

  Tmp /= 10;
  DigitsLot = 0;

  while (Tmp > 0)
  {
    DigitsLot++;
    Tmp /= 10;
  }

  if (MaxLot > MarketInfo(Symb, MODE_MAXLOT))
    MaxLot = MarketInfo(Symb, MODE_MAXLOT);

  if (MinLot < MarketInfo(Symb, MODE_MINLOT))
    MinLot = MarketInfo(Symb, MODE_MINLOT);

  if (MinLot > MarketInfo(Symb, MODE_LOTSTEP) + ALPHA)
    Alert(WindowExpertName(), " - WARNING: MinLot (", MinLot, ") > LotStep (", MarketInfo(Symb, MODE_LOTSTEP), ")");

  return;
}

void GetSymbolPrefix( string Symb )
{
  SymbolPrefix = StringSubstr(Symb, 6);

  return;
}

void GetXTrade( string FileName )
{
  int i, j, k, m, Pos;
  int handle;
  int AmountStrings = 0;
  string Str1, Str2, Str3, Str[MAX_VARIANTPAIRS];

  handle = FileOpen(FileName, FILE_READ);

  while (!FileIsEnding(handle))
  {
    Str[AmountStrings] = FileReadString(handle);
    AmountStrings++;
  }

  FileClose(handle);

  for (i = 0; i < AmountAllSymbols; i++)
  {
    Pos = 0;

    for (j = 0; j < Count[i] - 1; j++)
    {
      Str1 = SymbolToStr(i, j);
      Pos += j + 1;

      for (k = j + 1; k < Count[i]; k++)
      {
        Str2 = Str1 + " && " + SymbolToStr(i, k);
        Str3 = SymbolToStr(i, k) + " && " + Str1;

        for (m = 0; m < AmountStrings; m++)
          if ((Str[m] == Str2) || (Str[m] == Str3))
            break;

        if (m == AmountStrings)
          XTrade[i][Pos] = false;   
        else
          XTrade[i][Pos] = true;

        XPosition[i][Pos] = 0;
        CountArbitrage[i][Pos] = 0;

        Pos++;
      }
    }
  }

  return;
}

void GetPipsD()
{
  GetRealBidAsk();

  for (int i = 0; i < AmountAllSymbols; i++)
  {
    GetBidAsk(i, 0);           

    if (Bids[i][0] > 10)
    {
      PointD[i] = 0.01;
      MinPipsD[i] = MinPips * 0.01;
    }
    else
    {
      PointD[i] = 0.0001;
      MinPipsD[i] = MinPips * 0.0001;
    }
  }

  return;
}

void InitArbitrage()
{
  GetDataLot(Symbol());
  GetSymbolPrefix(Symbol());

  AmountCurrency = StrToStringS(Currencies, ",", Currency);

  GetRealSymbols();
  GetAllSymbols();
  GetPipsD();

  MaxCountArbitrage = 0;

  for (int i = 0; i < AmountRealSymbols; i++)
    Position[i] = 0;

  GetXTrade("Trade-Arbitrage.txt");

  return;
}

void PrintXTrade()
{
  int i, j, k, Pos;

  for (i = 0; i < AmountAllSymbols; i++)
  {
    Pos = 0;

    for (j = 0; j < Count[i] - 1; j++)
    {
      Pos += j + 1;

      for (k = j + 1; k < Count[i]; k++)
      {
        if  (XTrade[i][Pos])
          Print(SymbolToStr(i, j) + " && " + SymbolToStr(i, k));

        Pos++;
      }
    }
  }

  return;
}

void PrintBeginInfo()
{
  int i, Max;

  Print("MAX_CURRENCY = " + AmountCurrency);
  Print("MAX_REALSYMBOLS = " + AmountRealSymbols);
  Print("MAX_ALLSYMBOLS = " + AmountAllSymbols);

  Max = 0;

  for (i = 0; i < AmountAllSymbols; i++)
    if (Count[i] > Max)
      Max = Count[i];

  Print("MAX_VARIANTSYMBOLS = " + Max);

  Max = 0;

  for (i = 0; i < AmountAllSymbols; i++)
    if (Count[i] * (Count[i] - 1) > Max)
      Max = Count[i] * (Count[i] - 1);

  Print("MAX_VARIANTPAIRS = " + Max);

  Max = 0;

  for (i = 0; i < AmountAllSymbols; i++)
    Max += Count[i];

  Print("SumAllCounts = " + Max);

  Max = 0;

  for (i = 0; i < AmountAllSymbols; i++)
    Max += Count[i] * (Count[i] - 1);

  Print("SumAllVariants = " + Max);

  PrintXTrade();

  return;
}

/************************************************* END BLOCK_1 *************************************************/

/************************************************* END BLOCK_1 *************************************************/

/************************************************* BEGIN BLOCK_2 *************************************************/

/************************************************* BEGIN BLOCK_2 *************************************************/

string ArbitragePositions()
{
  string Str = WindowExpertName() + ": MinPips = " + DoubleToStr(MinPips, 1);
  int i, j, k, Pos;  

  for (i = 0; i < AmountAllSymbols; i++)
  {
    Pos = 0;

    for (j = 0; j < Count[i] - 1; j++)
    {
      Pos += j + 1;

      for (k = j + 1; k < Count[i]; k++)
      {
        if  (XTrade[i][Pos])
        {
          if (XPosition[i][Pos] < -ALPHA)
            Str = Str + "\n" + SymbolToStr(i, j) + " (SELL) && " + SymbolToStr(i, k) + " (BUY)";
          else if (XPosition[i][Pos] > ALPHA)
            Str = Str + "\n" + SymbolToStr(i, j) + " (BUY) && " + SymbolToStr(i, k) + " (SELL)";
        }

        Pos++;
      }
    }
  }

  return(Str);
}

string SymbolToFile( int i, int j )
{
  string Str = "";
  int S1, S2;

  if (Math[i][j] < 0)
  {
    S1 = AllSymbols[i][j];

    Str = RealSymbols[S1] + ": " + DoubleToStr(BidsReal[S1], MarketInfo(REALSymbols[S1], MODE_DIGITS)) + " " +
                                   DoubleToStr(AsksReal[S1], MarketInfo(REALSymbols[S1], MODE_DIGITS));
  } 
  else
  {
    S1 = AllSymbols[i][j] / AmountRealSymbols;
    S2 = AllSymbols[i][j] % AmountRealSymbols;
    Str = RealSymbols[S1] + ": " + DoubleToStr(BidsReal[S1], MarketInfo(REALSymbols[S1], MODE_DIGITS)) + " " +
                                   DoubleToStr(AsksReal[S1], MarketInfo(REALSymbols[S1], MODE_DIGITS)) + "\n" +
          RealSymbols[S2] + ": " + DoubleToStr(BidsReal[S2], MarketInfo(REALSymbols[S2], MODE_DIGITS)) + " " +
                                   DoubleToStr(AsksReal[S2], MarketInfo(REALSymbols[S2], MODE_DIGITS));
  }

  return(Str);
}

void StringToFile( string FileName, string Str )
{
  int handle;

  handle = FileOpen(FileName, FILE_READ|FILE_WRITE, "\t");
  FileSeek(handle, 0, SEEK_END);

  FileWrite(handle, Str);

  FileClose(handle);

  return;
}

void MonitoringArbitrage( int NumSymbol, int Variant1, int Variant2 )
{
  int V;
  string Str;

  if (Variant1 < Variant2)
    V = Variant1 * Count[NumSymbol] + Variant2;
  else
    V = Variant2 * Count[NumSymbol] + Variant1;

  CountArbitrage[NumSymbol][V]++;

  if (CountArbitrage[NumSymbol][V] > MaxCountArbitrage)
    MaxCountArbitrage = CountArbitrage[NumSymbol][V];

  if (Monitoring)
  {
    Str = "Time = " + TimeToStr(CurrentTime, TIME_DATE|TIME_SECONDS) + "\n";
    Str = Str + "Bid \"" + SymbolToStr(NumSymbol, Variant1) + "\" (" + DoubleToStr(Bids[NumSymbol][Variant1], 5) +
          ") > (" + DoubleToStr(Asks[NumSymbol][Variant2], 5) + ") Ask \"" + SymbolToStr(NumSymbol, Variant2) +
          "\", Difference = " + DoubleToStr((Bids[NumSymbol][Variant1] - Asks[NumSymbol][Variant2]) / PointD[NumSymbol], 1) + " pips";
    Str = Str + "\n" + SymbolToFile(NumSymbol, Variant1) + "\n" + SymbolToFile(NumSymbol, Variant2) + "\n";
    Str = Str + "Count = " + CountArbitrage[NumSymbol][V];

    StringToFile("Arbitrage.txt", Str); 
  }

  return;
}

void WriteStatistic( string FileName )
{
  string Str = WindowExpertName() + ": MinPips = " + DoubleToStr(MinPips, 1);
  int i, j, k, Pos;
  int handle, Cnt;
  int BenchTime = GetTickCount();

  Cnt = MaxCountArbitrage;

  while (Cnt 

Показано первые 50% кода (символов: 24900)

Открыть по тарифу

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

Разовая покупка файла

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

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
2 490₽ ≈ $30.43