|
//+------------------------------------------------------------------+
//| MACDBreakEA.mq5 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade\Trade.mqh>
//--- 输入参数
input int MACDFast = 12; // MACD快线周期
input int MACDSlow = 26; // MACD慢线周期
input int MACDSignal = 9; // MACD信号周期
input int MACDBreakBars = 10; // 突破周期(原10根)
input int MACDConsecutiveBars = 3;// 连续递增/递减周期(原3根)
input double LotSize = 0.1; // 交易手数
input int TakeProfitPoints = 6000;// 止盈点数
input int StopLossPoints = 5000; // 止损点数
//--- 可自定义均线参数
input int MAPeriod1 = 60; // 均线1周期
input int MAPeriod2 = 84; // 均线2周期
input int MAPeriod3 = 120; // 均线3周期
input int MAPeriod4 = 144; // 均线4周期
input int MAPeriod5 = 200; // 均线5周期
input int MAPeriod6 = 300; // 均线6周期
//--- 指标句柄
int maHandles[6];
int macdHandle;
datetime lastBarTime;
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 初始化均线指标数组
int periods[6] = {MAPeriod1, MAPeriod2, MAPeriod3, MAPeriod4, MAPeriod5, MAPeriod6};
for(int i=0; i<6; i++)
{
maHandles = iMA(_Symbol, _Period, periods, 0, MODE_SMA, PRICE_CLOSE);
if(maHandles == INVALID_HANDLE)
{
Print("MA",i+1," 初始化失败,周期:",periods);
return INIT_FAILED;
}
}
macdHandle = iMACD(_Symbol, _Period, MACDFast, MACDSlow, MACDSignal, PRICE_CLOSE);
if(macdHandle == INVALID_HANDLE)
{
Print("MACD初始化失败");
return INIT_FAILED;
}
lastBarTime = 0;
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
for(int i=0; i<6; i++)
IndicatorRelease(maHandles);
IndicatorRelease(macdHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(!IsNewBar()) return;
MqlRates rates[];
double macd[], ma1[2], ma2[2], ma3[2], ma4[2], ma5[2], ma6[2];
// 计算需要获取的MACD数据量
int requiredBars = MACDBreakBars + MACDConsecutiveBars + 1;
// 获取价格数据
if(CopyRates(_Symbol, _Period, 0, 3, rates) != 3) return;
// 获取MACD数据
if(CopyBuffer(macdHandle, 0, 0, requiredBars, macd) < requiredBars) return;
// 获取均线数据
if(CopyBuffer(maHandles[0], 0, 0, 2, ma1) < 2) return;
if(CopyBuffer(maHandles[1], 0, 0, 2, ma2) < 2) return;
if(CopyBuffer(maHandles[2], 0, 0, 2, ma3) < 2) return;
if(CopyBuffer(maHandles[3], 0, 0, 2, ma4) < 2) return;
if(CopyBuffer(maHandles[4], 0, 0, 2, ma5) < 2) return;
if(CopyBuffer(maHandles[5], 0, 0, 2, ma6) < 2) return;
ArraySetAsSeries(rates, true);
ArraySetAsSeries(macd, true);
bool hasPosition = PositionSelect(_Symbol);
// 多单逻辑
if(CheckLongConditions(rates, macd, ma1[1], ma2[1], ma3[1], ma4[1], ma5[1], ma6[1]) && !hasPosition)
{
ExecuteOrder(ORDER_TYPE_BUY);
}
// 空单逻辑
if(CheckShortConditions(rates, macd, ma1[1], ma2[1], ma3[1], ma4[1], ma5[1], ma6[1]) && !hasPosition)
{
ExecuteOrder(ORDER_TYPE_SELL);
}
}
//+------------------------------------------------------------------+
//| 执行下单操作 |
//+------------------------------------------------------------------+
void ExecuteOrder(ENUM_ORDER_TYPE orderType)
{
if(orderType == ORDER_TYPE_BUY)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
trade.Buy(LotSize, _Symbol, ask,
NormalizeDouble(ask - StopLossPoints*point, _Digits),
NormalizeDouble(ask + TakeProfitPoints*point, _Digits),
"多单");
}
else if(orderType == ORDER_TYPE_SELL)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
trade.Sell(LotSize, _Symbol, bid,
NormalizeDouble(bid + StopLossPoints*point, _Digits),
NormalizeDouble(bid - TakeProfitPoints*point, _Digits),
"空单");
}
}
//+------------------------------------------------------------------+
//| 多单入场条件检查 |
//+------------------------------------------------------------------+
bool CheckLongConditions(const MqlRates &rates[], const double &macd[],
double ma1, double ma2, double ma3,
double ma4, double ma5, double ma6)
{
// 均线过滤条件
if(!(ma1 > ma2 && ma2 > ma3 && ma3 > ma4 && ma4 > ma5 && ma5 > ma6))
return false;
// MACD突破条件
double maxMacd = GetArrayMax(macd, 1, MACDBreakBars);
if(macd[0] <= maxMacd) return false;
// 连续递增检查
for(int i=0; i<MACDConsecutiveBars-1; i++)
{
if(macd <= macd[i+1]) return false;
if(macd <= 0) return false;
}
if(macd[MACDConsecutiveBars-1] <= 0) return false;
return true;
}
//+------------------------------------------------------------------+
//| 空单入场条件检查 |
//+------------------------------------------------------------------+
bool CheckShortConditions(const MqlRates &rates[], const double &macd[],
double ma1, double ma2, double ma3,
double ma4, double ma5, double ma6)
{
// 均线过滤条件
if(!(ma1 < ma2 && ma2 < ma3 && ma3 < ma4 && ma4 < ma5 && ma5 < ma6))
return false;
// MACD突破条件
double minMacd = GetArrayMin(macd, 1, MACDBreakBars);
if(macd[0] >= minMacd) return false;
// 连续递减检查
for(int i=0; i<MACDConsecutiveBars-1; i++)
{
if(macd >= macd[i+1]) return false;
if(macd >= 0) return false;
}
if(macd[MACDConsecutiveBars-1] >= 0) return false;
return true;
}
//+------------------------------------------------------------------+
//| 辅助函数:获取数组最大值 |
//+------------------------------------------------------------------+
double GetArrayMax(const double &arr[], int start, int count)
{
double maxVal = -DBL_MAX;
int end = start + count;
if(end > ArraySize(arr)) end = ArraySize(arr);
for(int i=start; i<end; i++)
if(arr > maxVal) maxVal = arr;
return maxVal;
}
//+------------------------------------------------------------------+
//| 辅助函数:获取数组最小值 |
//+------------------------------------------------------------------+
double GetArrayMin(const double &arr[], int start, int count)
{
double minVal = DBL_MAX;
int end = start + count;
if(end > ArraySize(arr)) end = ArraySize(arr);
for(int i=start; i<end; i++)
if(arr < minVal) minVal = arr;
return minVal;
}
//+------------------------------------------------------------------+
//| 检测新K线 |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime currentTime = iTime(_Symbol, _Period, 0);
if(currentTime != lastBarTime)
{
lastBarTime = currentTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
|
|