trade-arbitrage(1).mq4
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «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? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.