Читать книгу 10 роботов для автоматической торговли на Форекс - - Страница 4

Робот 4: «Гармоничный паттерн» (Harmonic Pattern Scanner)

Оглавление

Гармоничный паттерн (Harmonic Pattern Scanner) для MetaTrader 5


```mq5

//+–+

//| HarmonicPatternScanner.mq5 |

//| Copyright 2023, MetaQuotes Ltd. |

//| https://www.mql5.com |

//+–+

#property copyright "Copyright 2023, MetaQuotes Ltd."

#property link "https://www.mql5.com"

#property version "1.00"


//+–+

//| Входные параметры эксперта |

//+–+

input double LotSize = 0.1; // Размер лота

input int StopLoss_Points = 200; // Стоп-лосс в пунктах

input int TakeProfit_Points = 400; // Тейк-профит в пунктах

input int MagicNumber = 112233; // Магический номер

input double FiboTolerance = 0.05; // Допуск для уровней Фибо (5%)

input int MinPatternBars = 20; // Минимум баров в паттерне

input int MaxPatternBars = 300; // Максимум баров в паттерне

input bool ShowPatternLines = true; // Показывать линии паттернов

input color PatternColor = clrBlue; // Цвет линий паттернов


//+–+

//| Перечисление типов паттернов |

//+–+

enum PATTERN_TYPE

{

PATTERN_NONE = 0,

PATTERN_GARTLEY = 1,

PATTERN_BUTTERFLY = 2,

PATTERN_CRAB = 3,

PATTERN_BAT = 4,

PATTERN_SHARK = 5,

PATTERN_CYPHER = 6

};


//+–+

//| Структура для хранения точек паттерна |

//+–+

struct PatternPoints

{

double X, A, B, C, D;

datetime timeX, timeA, timeB, timeC, timeD;

PATTERN_TYPE type;

int direction; // 1 – бычий, -1 – медвежий

};


//+–+

//| Глобальные переменные |

//+–+

PatternPoints lastPattern;

bool patternFound = false;

int lastPatternBar = 0;

int zigzagHandle;

double zigzagBuffer[];

datetime timeBuffer[];

double highBuffer[], lowBuffer[];

int lastCalculated = 0;


//+–+

//| Expert initialization function |

//+–+

int OnInit()

{

// Проверка входных параметров

if(LotSize <= 0 || LotSize > 100)

{

Print("Некорректный размер лота!");

return INIT_PARAMETERS_INCORRECT;

}


// Создание индикатора ZigZag для поиска экстремумов

zigzagHandle = iCustom(_Symbol, _Period, "Examples\\ZigZag.ex5", 12, 5, 3);


if(zigzagHandle == INVALID_HANDLE)

{

Print("Ошибка создания индикатора ZigZag!");

return INIT_FAILED;

}


// Настройка массивов

ArraySetAsSeries(zigzagBuffer, true);

ArraySetAsSeries(timeBuffer, true);

ArraySetAsSeries(highBuffer, true);

ArraySetAsSeries(lowBuffer, true);


return INIT_SUCCEEDED;

}


//+–+

//| Expert deinitialization function |

//+–+

void OnDeinit(const int reason)

{

if(zigzagHandle != INVALID_HANDLE) IndicatorRelease(zigzagHandle);

DeletePatternLines();

}


//+–+

//| Expert tick function |

//+–+

void OnTick()

{

// Проверяем наличие открытых позиций по этому символу и магику

if(PositionSelect(_Symbol)) return;


// Получаем текущее время бара

datetime currentTime = iTime(_Symbol, _Period, 0);


// Ищем паттерны каждые N баров или при смене дня

static datetime lastScanTime = 0;

if(currentTime – lastScanTime < 3600) return; // Сканируем раз в час


// Обновляем данные ZigZag

if(!UpdateZigZagData()) return;


// Ищем гармонические паттерны

PatternPoints foundPattern = ScanForPatterns();


if(foundPattern.type != PATTERN_NONE)

{

patternFound = true;

lastPattern = foundPattern;

lastPatternBar = iBarShift(_Symbol, _Period, currentTime);


// Отображаем паттерн на графике

if(ShowPatternLines) DrawPattern(foundPattern);


// Открываем сделку в точке D

OpenPatternTrade(foundPattern);


lastScanTime = currentTime;

}

}


//+–+

//| Обновление данных ZigZag |

//+–+

bool UpdateZigZagData()

{

// Копируем данные ZigZag

if(CopyBuffer(zigzagHandle, 0, 0, 500, zigzagBuffer) <= 0)

{

Print("Ошибка копирования данных ZigZag!");

return false;

}


// Копируем временные метки

if(CopyTime(_Symbol, _Period, 0, 500, timeBuffer) <= 0) return false;


// Копируем High и Low

if(CopyHigh(_Symbol, _Period, 0, 500, highBuffer) <= 0) return false;

if(CopyLow(_Symbol, _Period, 0, 500, lowBuffer) <= 0) return false;


return true;

}


//+–+

//| Поиск гармонических паттернов |

//+–+

PatternPoints ScanForPatterns()

{

PatternPoints result;

result.type = PATTERN_NONE;


// Собираем экстремумы из ZigZag

double extremes[];

datetime extremeTimes[];

int extremeBars[];


CollectExtremes(extremes, extremeTimes, extremeBars);


int extremeCount = ArraySize(extremes);

if(extremeCount < 5) return result;


// Ищем паттерны среди экстремумов

for(int i = 4; i < extremeCount; i++)

{

// Проверяем XABCD паттерны

for(int x = i-4; x <= i-4; x++)

for(int a = x+1; a <= i-3; a++)

for(int b = a+1; b <= i-2; b++)

for(int c = b+1; c <= i-1; c++)

for(int d = c+1; d <= i; d++)

{

// Проверяем временные рамки паттерна

int patternBars = extremeBars[d] – extremeBars[x];

if(patternBars < MinPatternBars || patternBars > MaxPatternBars) continue;


// Проверяем бычий паттерн (X – low, A – high, B – low, C – high, D – low)

if(extremes[x] < extremes[a] && extremes[a] > extremes[b] &&

extremes[b] < extremes[c] && extremes[c] > extremes[d])

{

PatternPoints bullPattern;

bullPattern.X = extremes[x];

bullPattern.A = extremes[a];

bullPattern.B = extremes[b];

bullPattern.C = extremes[c];

bullPattern.D = extremes[d];

bullPattern.timeX = extremeTimes[x];

bullPattern.timeA = extremeTimes[a];

bullPattern.timeB = extremeTimes[b];

bullPattern.timeC = extremeTimes[c];

bullPattern.timeD = extremeTimes[d];

bullPattern.direction = 1;


// Проверяем тип паттерна

bullPattern.type = CheckPatternType(bullPattern);

if(bullPattern.type != PATTERN_NONE)

{

// Проверяем, что точка D – последняя (или почти последняя)

int barsSinceD = iBarShift(_Symbol, _Period, extremeTimes[d]);

if(barsSinceD <= 3) // Паттерн свежий

{

return bullPattern;

}

}

}


// Проверяем медвежий паттерн (X – high, A – low, B – high, C – low, D – high)

if(extremes[x] > extremes[a] && extremes[a] < extremes[b] &&

extremes[b] > extremes[c] && extremes[c] < extremes[d])

{

PatternPoints bearPattern;

bearPattern.X = extremes[x];

bearPattern.A = extremes[a];

bearPattern.B = extremes[b];

bearPattern.C = extremes[c];

bearPattern.D = extremes[d];

bearPattern.timeX = extremeTimes[x];

bearPattern.timeA = extremeTimes[a];

bearPattern.timeB = extremeTimes[b];

bearPattern.timeC = extremeTimes[c];

bearPattern.timeD = extremeTimes[d];

bearPattern.direction = -1;


// Проверяем тип паттерна

bearPattern.type = CheckPatternType(bearPattern);

if(bearPattern.type != PATTERN_NONE)

{

// Проверяем, что точка D – последняя (или почти последшая)

int barsSinceD = iBarShift(_Symbol, _Period, extremeTimes[d]);

if(barsSinceD <= 3) // Паттерн свежий

{

return bearPattern;

}

}

}

}

}


return result;

}


//+–+

//| Сбор экстремумов из ZigZag |

//+–+

void CollectExtremes(double &extremes[], datetime &times[], int &bars[])

{

ArrayResize(extremes, 0);

ArrayResize(times, 0);

ArrayResize(bars, 0);


for(int i = 100; i >= 0; i–)

{

if(zigzagBuffer[i] != 0 && zigzagBuffer[i] != EMPTY_VALUE)

{

int size = ArraySize(extremes);

ArrayResize(extremes, size + 1);

ArrayResize(times, size + 1);

ArrayResize(bars, size + 1);


extremes[size] = zigzagBuffer[i];

times[size] = timeBuffer[i];

bars[size] = i;

}

}


// Ограничиваем количество экстремумов

int count = ArraySize(extremes);

if(count > 20)

{

ArrayResize(extremes, 20);

ArrayResize(times, 20);

ArrayResize(bars, 20);

}

}


//+–+

//| Проверка типа паттерна |

//+–+

PATTERN_TYPE CheckPatternType(const PatternPoints &pattern)

{

// Вычисляем соотношения Фибоначчи

double XA = MathAbs(pattern.A – pattern.X);

double AB = MathAbs(pattern.B – pattern.A);

double BC = MathAbs(pattern.C – pattern.B);

double CD = MathAbs(pattern.D – pattern.C);


// Отношения

double AB_XA = (XA != 0) ? AB / XA : 0;

double BC_AB = (AB != 0) ? BC / AB : 0;

double CD_BC = (BC != 0) ? CD / BC : 0;

double XC_XA = (XA != 0) ? MathAbs(pattern.C – pattern.X) / XA : 0;

double XD_XA = (XA != 0) ? MathAbs(pattern.D – pattern.X) / XA : 0;


// Уровни Фибоначчи

double fib_0382 = 0.382;

double fib_0500 = 0.5;

double fib_0618 = 0.618;

double fib_0707 = 0.707;

double fib_0786 = 0.786;

double fib_0886 = 0.886;

double fib_1130 = 1.13;

double fib_1272 = 1.272;

double fib_1414 = 1.414;

double fib_1618 = 1.618;

double fib_2000 = 2.0;

double fib_2240 = 2.24;

double fib_2618 = 2.618;


// Проверяем паттерн Гартли (Gartley)

// AB = 0.618 XA, BC = 0.382-0.886 AB, CD = 1.272-1.618 BC, XD = 0.786 XA

if(MathAbs(AB_XA – fib_0618) < FiboTolerance &&

(MathAbs(BC_AB – fib_0382) < FiboTolerance ||

MathAbs(BC_AB – fib_0886) < FiboTolerance) &&

(MathAbs(CD_BC – fib_1272) < FiboTolerance ||

MathAbs(CD_BC – fib_1618) < FiboTolerance) &&

MathAbs(XD_XA – fib_0786) < FiboTolerance)

{

return PATTERN_GARTLEY;

}


// Проверяем паттерн Бабочка (Butterfly)

// AB = 0.786 XA, BC = 0.382-0.886 AB, CD = 1.618-2.24 BC, XD = 1.272-1.618 XA

if(MathAbs(AB_XA – fib_0786) < FiboTolerance &&

(MathAbs(BC_AB – fib_0382) < FiboTolerance ||

MathAbs(BC_AB – fib_0886) < FiboTolerance) &&

(MathAbs(CD_BC – fib_1618) < FiboTolerance ||

MathAbs(CD_BC – fib_2240) < FiboTolerance) &&

(MathAbs(XD_XA – fib_1272) < FiboTolerance ||

MathAbs(XD_XA – fib_1618) < FiboTolerance))

{

return PATTERN_BUTTERFLY;

}


// Проверяем паттерн Краб (Crab)

// AB = 0.382-0.618 XA, BC = 0.382-0.886 AB, CD = 2.618-3.618 BC, XD = 1.618 XA

if((MathAbs(AB_XA – fib_0382) < FiboTolerance ||

MathAbs(AB_XA – fib_0618) < FiboTolerance) &&

(MathAbs(BC_AB – fib_0382) < FiboTolerance ||

MathAbs(BC_AB – fib_0886) < FiboTolerance) &&

(MathAbs(CD_BC – fib_2618) < FiboTolerance ||

MathAbs(CD_BC – 3.618) < FiboTolerance) &&

MathAbs(XD_XA – fib_1618) < FiboTolerance)

{

return PATTERN_CRAB;

}


// Проверяем паттерн Летучая мышь (Bat)

// AB = 0.382-0.5 XA, BC = 0.382-0.886 AB, CD = 1.618-2.618 BC, XD = 0.886 XA

if((MathAbs(AB_XA – fib_0382) < FiboTolerance ||

MathAbs(AB_XA – fib_0500) < FiboTolerance) &&

(MathAbs(BC_AB – fib_0382) < FiboTolerance ||

MathAbs(BC_AB – fib_0886) < FiboTolerance) &&

(MathAbs(CD_BC – fib_1618) < FiboTolerance ||

MathAbs(CD_BC – fib_2618) < FiboTolerance) &&

MathAbs(XD_XA – fib_0886) < FiboTolerance)

{

return PATTERN_BAT;

}


// Проверяем паттерн Акула (Shark)

// 0X = 1.13-1.618 XA, AB = 1.13-1.618 0X, BC = 0.886-1.13 AB

// Специфический паттерн, требует особой логики


return PATTERN_NONE;

}


//+–+

//| Отображение паттерна на графике |

//+–+

void DrawPattern(const PatternPoints &pattern)

{

// Удаляем старые линии

DeletePatternLines();


// Создаем уникальные имена для объектов

string prefix = "HP_"+IntegerToString(MagicNumber)+"_";


// Рисуем линии паттерна

ObjectCreate(0, prefix+"X_A", OBJ_TREND, 0, pattern.timeX, pattern.X, pattern.timeA, pattern.A);

ObjectSetInteger(0, prefix+"X_A", OBJPROP_COLOR, PatternColor);

ObjectSetInteger(0, prefix+"X_A", OBJPROP_WIDTH, 2);

ObjectSetInteger(0, prefix+"X_A", OBJPROP_RAY, false);


ObjectCreate(0, prefix+"A_B", OBJ_TREND, 0, pattern.timeA, pattern.A, pattern.timeB, pattern.B);

ObjectSetInteger(0, prefix+"A_B", OBJPROP_COLOR, PatternColor);

ObjectSetInteger(0, prefix+"A_B", OBJPROP_WIDTH, 2);

ObjectSetInteger(0, prefix+"A_B", OBJPROP_RAY, false);


ObjectCreate(0, prefix+"B_C", OBJ_TREND, 0, pattern.timeB, pattern.B, pattern.timeC, pattern.C);

ObjectSetInteger(0, prefix+"B_C", OBJPROP_COLOR, PatternColor);

ObjectSetInteger(0, prefix+"B_C", OBJPROP_WIDTH, 2);

ObjectSetInteger(0, prefix+"B_C", OBJPROP_RAY, false);


ObjectCreate(0, prefix+"C_D", OBJ_TREND, 0, pattern.timeC, pattern.C, pattern.timeD, pattern.D);

ObjectSetInteger(0, prefix+"C_D", OBJPROP_COLOR, PatternColor);

ObjectSetInteger(0, prefix+"C_D", OBJPROP_WIDTH, 2);

ObjectSetInteger(0, prefix+"C_D", OBJPROP_RAY, false);


// Добавляем точки

CreatePoint(prefix+"X", pattern.timeX, pattern.X, 218);

CreatePoint(prefix+"A", pattern.timeA, pattern.A, 218);

CreatePoint(prefix+"B", pattern.timeB, pattern.B, 218);

CreatePoint(prefix+"C", pattern.timeC, pattern.C, 218);

CreatePoint(prefix+"D", pattern.timeD, pattern.D, 218);


// Добавляем метки

CreateLabel(prefix+"Label_X", "X", pattern.timeX, pattern.X);

CreateLabel(prefix+"Label_A", "A", pattern.timeA, pattern.A);

CreateLabel(prefix+"Label_B", "B", pattern.timeB, pattern.B);

CreateLabel(prefix+"Label_C", "C", pattern.timeC, pattern.C);

CreateLabel(prefix+"Label_D", "D", pattern.timeD, pattern.D);


// Добавляем название паттерна

string patternName = GetPatternName(pattern.type);

CreateLabel(prefix+"PatternName", patternName + " " + ((pattern.direction == 1) ? "Bullish" : "Bearish"),

pattern.timeD, pattern.D, 12, clrRed);

}


//+–+

//| Создание точки на графике |

//+–+

void CreatePoint(string name, datetime time, double price, int code)

{

ObjectCreate(0, name, OBJ_ARROW, 0, time, price);

ObjectSetInteger(0, name, OBJPROP_ARROWCODE, code);

ObjectSetInteger(0, name, OBJPROP_COLOR, PatternColor);

ObjectSetInteger(0, name, OBJPROP_WIDTH, 3);

}


//+–+

//| Создание метки на графике |

//+–+

void CreateLabel(string name, string text, datetime time, double price, int fontSize = 8, color clr = clrBlack)

{

ObjectCreate(0, name, OBJ_TEXT, 0, time, price);

ObjectSetString(0, name, OBJPROP_TEXT, text);

ObjectSetInteger(0, name, OBJPROP_COLOR, clr);

ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);

ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_UPPER);

}


//+–+

//| Удаление линий паттерна |

//+–+

void DeletePatternLines()

{

string prefix = "HP_"+IntegerToString(MagicNumber)+"_";


for(int i = ObjectsTotal(0)-1; i >= 0; i–)

{

string name = ObjectName(0, i);

if(StringFind(name, prefix) == 0)

{

ObjectDelete(0, name);

}

}

}


//+–+

//| Получение названия паттерна |

//+–+

string GetPatternName(PATTERN_TYPE type)

{

switch(type)

{

case PATTERN_GARTLEY: return "Gartley";

case PATTERN_BUTTERFLY: return "Butterfly";

case PATTERN_CRAB: return "Crab";

case PATTERN_BAT: return "Bat";

case PATTERN_SHARK: return "Shark";

case PATTERN_CYPHER: return "Cypher";

default: return "Unknown";

}

}


//+–+

//| Открытие сделки по паттерну |

//+–+

void OpenPatternTrade(const PatternPoints &pattern)

{

// Получаем текущую цену

MqlTick lastTick;

if(!SymbolInfoTick(_Symbol, lastTick)) return;


// Определяем направление сделки

ENUM_ORDER_TYPE orderType;

double entryPrice;

double slPrice, tpPrice;


if(pattern.direction == 1) // Бычий паттерн – покупаем

{

orderType = ORDER_TYPE_BUY;

entryPrice = lastTick.ask;


// Стоп-лосс ниже точки D

slPrice = pattern.D – StopLoss_Points * _Point;


// Тейк-профит на уровне точки B или A (в зависимости от паттерна)

if(pattern.type == PATTERN_GARTLEY || pattern.type == PATTERN_BAT)

tpPrice = entryPrice + (pattern.B – pattern.D);

else

tpPrice = entryPrice + TakeProfit_Points * _Point;

}

else // Медвежий паттерн – продаем

{

orderType = ORDER_TYPE_SELL;

entryPrice = lastTick.bid;


// Стоп-лосс выше точки D

slPrice = pattern.D + StopLoss_Points * _Point;


// Тейк-профит на уровне точки B или A

if(pattern.type == PATTERN_GARTLEY || pattern.type == PATTERN_BAT)

tpPrice = entryPrice – (pattern.D – pattern.B);

else

tpPrice = entryPrice – TakeProfit_Points * _Point;

}


// Открываем сделку

MqlTradeRequest request = {};

MqlTradeResult result = {};


request.action = TRADE_ACTION_DEAL;

request.symbol = _Symbol;

request.volume = LotSize;

request.type = orderType;

request.price = entryPrice;

request.sl = slPrice;

request.tp = tpPrice;

request.deviation = 10;

request.magic = MagicNumber;

request.comment = GetPatternName(pattern.type);


if(!OrderSend(request, result))

{

Print("Ошибка открытия позиции по паттерну: ", GetLastError());

}

else

{

Print("Позиция открыта по паттерну: ", GetPatternName(pattern.type),

" (", (pattern.direction == 1) ? "Bullish" : "Bearish", ")");

}

}


//+–+

//| Функция для ручного тестирования паттернов |

//+–+

void TestPatternRecognition()

{

// Эта функция может быть использована для тестирования

// алгоритма распознавания паттернов на исторических данных


Print("Начинаем тестирование распознавания паттернов…");


for(int i = 100; i < Bars(_Symbol, _Period) – 100; i += 10)

{

// Здесь можно добавить код для тестирования на разных участках истории

}

}

```


Дополнительные функции для расширенного распознавания:


```mq5

//+–+

//| Улучшенная функция распознавания паттернов (опционально) |

//+–+

PatternPoints AdvancedPatternScan()

{

PatternPoints result;

result.type = PATTERN_NONE;


// Используем алгоритм поиска экстремумов без ZigZag

// для более точного распознавания


// 1. Ищем swing highs и swing lows

double swingHighs[], swingLows[];

datetime swingHighTimes[], swingLowTimes[];


FindSwingPoints(swingHighs, swingHighTimes, swingLows, swingLowTimes);


// 2. Комбинируем экстремумы в правильном порядке

// 3. Проверяем больше типов паттернов

// 4. Добавляем фильтры по объему и времени


return result;

}


//+–+

//| Поиск точек разворота (swing points) |

//+–+

void FindSwingPoints(double &highs[], datetime &highTimes[],

double &lows[], datetime &lowTimes[],

int lookback = 5)

{

ArrayResize(highs, 0);

ArrayResize(highTimes, 0);

ArrayResize(lows, 0);

ArrayResize(lowTimes, 0);


for(int i = lookback; i < Bars(_Symbol, _Period) – lookback; i++)

{

// Проверяем swing high

bool isSwingHigh = true;

for(int j = 1; j <= lookback; j++)

{

if(iHigh(_Symbol, _Period, i) <= iHigh(_Symbol, _Period, i+j) ||

iHigh(_Symbol, _Period, i) <= iHigh(_Symbol, _Period, i-j))

{

isSwingHigh = false;

break;

}

}


if(isSwingHigh)

{

int size = ArraySize(highs);

ArrayResize(highs, size + 1);

ArrayResize(highTimes, size + 1);

highs[size] = iHigh(_Symbol, _Period, i);

highTimes[size] = iTime(_Symbol, _Period, i);

}


// Проверяем swing low

bool isSwingLow = true;

for(int j = 1; j <= lookback; j++)

{

if(iLow(_Symbol, _Period, i) >= iLow(_Symbol, _Period, i+j) ||

iLow(_Symbol, _Period, i) >= iLow(_Symbol, _Period, i-j))

{

isSwingLow = false;

break;

}

}


if(isSwingLow)

{

int size = ArraySize(lows);

ArrayResize(lows, size + 1);

ArrayResize(lowTimes, size + 1);

lows[size] = iLow(_Symbol, _Period, i);

lowTimes[size] = iTime(_Symbol, _Period, i);

}

}

}


//+–+

//| Фильтр паттернов по дополнительным критериям |

//+–+

bool ValidatePattern(const PatternPoints &pattern)

{

// 1. Проверяем объемы в точках разворота

// 2. Проверяем временные соотношения

// 3. Проверяем наличие дивергенций

// 4. Проверяем контекст рынка


// Пример: проверяем, что в точке D объем выше среднего

int barD = iBarShift(_Symbol, _Period, pattern.timeD);

long volumeD = iVolume(_Symbol, _Period, barD);

long avgVolume = iMA(_Symbol, _Period, 20, 0, MODE_SMA, VOLUME_TICK, barD);


if(volumeD < avgVolume * 0.8) return false;


// Проверяем временные соотношения

double timeAB = double(pattern.timeB – pattern.timeA);

double timeBC = double(pattern.timeC – pattern.timeB);

double timeCD = double(pattern.timeD – pattern.timeC);


// Время CD не должно быть меньше времени BC (для большинства паттернов)

if(timeCD < timeBC * 0.5) return false;


return true;

}

```


Ключевые особенности робота:


1. Алгоритм распознавания:

· Использует индикатор ZigZag для поиска экстремумов

· Проверяет соотношения Фибоначчи с заданным допуском

· Распознает 6 основных гармонических паттернов

2. Точность распознавания:

· Настраиваемый допуск для уровней Фибо

· Фильтры по времени и количеству баров

· Проверка чередования экстремумов

3. Визуализация:

· Отображение паттерна на графике

· Подписанные точки X, A, B, C, D

· Разные цвета для бычьих и медвежьих паттернов

4. Торговая логика:

· Вход в точке завершения паттерна (D)

10 роботов для автоматической торговли на Форекс

Подняться наверх