//+------------------------------------------------------------------+
//| MACD_Quantitative_EA.mq4 |
//| Copyright 2025, Expert Advisor Developer |
//| https://yourwebsite.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Your Name"
#property link "https://yourwebsite.com/"
#property version "1.00"
#property strict
// 输入参数
input int FastEMA = 12; // 快速EMA周期
input int SlowEMA = 26; // 慢速EMA周期
input int SignalSMA = 9; // 信号线周期
input double LotSize = 0.1; // 固定交易手数
input int StopLoss = 100; // 止损点数
input int TakeProfit = 200; // 止盈点数
input int TrailingStart = 50; // 启动跟踪止损的盈利点数
input int TrailingStop = 30; // 跟踪止损点数
input bool UseTrailingStop = true; // 是否启用跟踪止损
input bool UseMACDAreaSignal = true; // 是否启用MACD面积缩小信号
input bool UseMACDAreaClose = true; // 是否启用MACD面积扩大平仓
input double MinMACDArea = 0.0001; // MACD最小有效面积
input int AreaLookback = 5; // 面积回溯周期
input int MaxTrendBars = 8; // 趋势末端最大连续上涨/下跌根数
input int DivergenceLookback = 20; // 背离检测周期
input int CrossAngleLookback = 3; // MACD交叉角度检测周期
input double DistanceThreshold = 0.0002; // MACD线与信号线最小距离
input int AccelerationLookback = 5; // 加速度计算周期
// 全局变量
int ticket = 0;
//+------------------------------------------------------------------+
//| 初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
Print("MACD量化交易EA已加载");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 主函数 OnTick |
//+------------------------------------------------------------------+
void OnTick()
{
if (OrdersTotal() > 0)
{
if (UseMACDAreaClose)
CheckMACDAreaClose(); // 检查MACD面积是否扩大,决定是否平仓
ManageTrailingStop(); // 管理跟踪止损
}
if (OrdersTotal() == 0)
{
int signal = 0;
// 1. 基础金叉/死叉
signal = GetMACDSignal();
if (signal == 0 && UseMACDAreaSignal)
signal = GetMACDAreaSignal(); // 如果没有金叉/死叉,再判断面积缩小信号
if (signal == 0)
signal = GetMACDTrendSignal(); // 最后判断趋势延续信号
if (signal == 0)
signal = DetectMACDTopBottom(); // 判断顶部/底部信号
if (signal == 0)
signal = DetectMACDCombinedDivergence(); // 加入背离信号
if (signal == 0)
signal = IsMACDPeakOrValley(); // 加入柱形态信号
if (signal == 0)
signal = IsMACDHistogramCrossZero(); // 新增:柱零轴穿越
if (signal == 0)
signal = GetMACDSignalWithZeroZone(); // 新增:判断金叉是否在0轴上方
if (signal == 0)
signal = CheckMACDHistogramReacceleration(); // 新增:二次放大信号
if (signal == 0)
signal = DetectMACDTrendAcceleration(); // 新增:线斜率变化
if (signal == 1)
OpenBuyOrder(); // 做多
else if (signal == -1)
OpenSellOrder(); // 做空
}
}
//+------------------------------------------------------------------+
//| 获取MACD金叉/死叉信号 |
//+------------------------------------------------------------------+
int GetMACDSignal()
{
double macdMain = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, 0);
double macdSignal = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 1, 0);
double macdPrevMain = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, 1);
double macdPrevSignal = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 1, 1);
// 金叉:当前MACD线上穿信号线
if (macdPrevMain < macdPrevSignal && macdMain > macdSignal)
{
if (IsMACDCrossWithSteepAngle() && GetMACDLineDistanceFromSignal() > DistanceThreshold)
return 1;
}
// 死叉:当前MACD线下穿信号线
if (macdPrevMain > macdPrevSignal && macdMain < macdSignal)
{
if (IsMACDCrossWithSteepAngle() && GetMACDLineDistanceFromSignal() > DistanceThreshold)
return -1;
}
return 0;
}
//+------------------------------------------------------------------+
//| 获取MACD面积缩小信号(优化版:连续5根K线) |
//+------------------------------------------------------------------+
int GetMACDAreaSignal()
{
double hist[5] = {0, 0, 0, 0, 0}; // 显式初始化
for (int i = 0; i < 5; i++)
{
hist[i] = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, i);
}
// 做多信号:负柱状图连续缩小(下跌动能减弱)
bool shrinkingNegative = true;
for (int i = 0; i < 4; i++)
{
if (MathAbs(hist[i]) >= MathAbs(hist[i + 1]))
{
shrinkingNegative = false;
break;
}
}
if (shrinkingNegative && hist[0] < 0 && hist[1] < 0 && hist[2] < 0 && hist[3] < 0 && hist[4] < 0)
return 1;
// 做空信号:正柱状图连续缩小(上涨动能减弱)
bool shrinkingPositive = true;
for (int i = 0; i < 4; i++)
{
if (hist[i] <= hist[i + 1])
{
shrinkingPositive = false;
break;
}
}
if (shrinkingPositive && hist[0] > 0 && hist[1] > 0 && hist[2] > 0 && hist[3] > 0 && hist[4] > 0)
return -1;
return 0; // 无信号
}
//+------------------------------------------------------------------+
//| 获取MACD趋势信号(在0轴上方未跌破则继续做多,反之做空) |
//+------------------------------------------------------------------+
int GetMACDTrendSignal()
{
double hist[5] = {0, 0, 0, 0, 0}; // 显式初始化
for (int i = 0; i < 5; i++)
{
hist[i] = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, i);
}
// 多头趋势:所有MACD柱都在0轴上方,且未跌破
bool allAboveZero = true;
for (int i = 0; i < 5; i++)
{
if (hist[i] <= 0)
{
allAboveZero = false;
break;
}
}
if (allAboveZero)
return 1;
// 空头趋势:所有MACD柱都在0轴下方,且未上穿
bool allBelowZero = true;
for (int i = 0; i < 5; i++)
{
if (hist[i] >= 0)
{
allBelowZero = false;
break;
}
}
if (allBelowZero)
return -1;
return 0; // 无趋势信号
}
//+------------------------------------------------------------------+
//| 判断MACD是否出现顶部/底部形态(连续上涨/下跌后反转) |
//+------------------------------------------------------------------+
int DetectMACDTopBottom()
{
int trendBars = CountMACDBarTrend();
double currentHist = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, 0);
double prevHist = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, 1);
// 顶部:连续上涨超过阈值,且当前柱反转
if (currentHist > 0 && prevHist > 0 && currentHist < prevHist && trendBars >= MaxTrendBars)
return -1;
// 底部:连续下跌超过阈值,且当前柱反转
if (currentHist < 0 && prevHist < 0 && currentHist > prevHist && trendBars >= MaxTrendBars)
return 1;
return 0;
}
//+------------------------------------------------------------------+
//| 检测MACD面积与价格背离 |
//+------------------------------------------------------------------+
int DetectMACDAreaDivergence()
{
double priceHigh = iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, DivergenceLookback, 0));
double priceLow = iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, DivergenceLookback, 0));
double areaHigh = CalculateMACDArea(DivergenceLookback);
double areaLow = CalculateMACDArea(DivergenceLookback);
// 顶部背离:价格创新高,但MACD面积未创新高
if (Bid > priceHigh && areaHigh < CalculateMACDArea(DivergenceLookback - 5))
return -1;
// 底部背离:价格创新低,但MACD面积未创新低
if (Ask < priceLow && areaLow > CalculateMACDArea(DivergenceLookback - 5))
return 1;
return 0;
}
//+------------------------------------------------------------------+
//| 检测MACD柱连续上涨/下跌与价格背离 |
//+------------------------------------------------------------------+
int DetectMACDBarDivergence()
{
double priceHigh = iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, DivergenceLookback, 0));
double priceLow = iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, DivergenceLookback, 0));
int trendBars = CountMACDBarTrend();
// 顶部背离:价格创新高,但MACD连续上涨根数未创新高
if (Bid > priceHigh && trendBars < DivergenceLookback - 3)
return -1;
// 底部背离:价格创新低,但MACD连续下跌根数未创新低
if (Ask < priceLow && trendBars < DivergenceLookback - 3)
return 1;
return 0;
}
//+------------------------------------------------------------------+
//| 检测MACD面积和根数双重背离(最强信号) |
//+------------------------------------------------------------------+
int DetectMACDCombinedDivergence()
{
int areaSignal = DetectMACDAreaDivergence();
int barSignal = DetectMACDBarDivergence();
if (areaSignal == -1 && barSignal == -1)
return -1; // 双重顶部背离
if (areaSignal == 1 && barSignal == 1)
return 1; // 双重底部背离
return 0;
}
//+------------------------------------------------------------------+
//| 检测MACD柱是否出现“山峰”或“谷底”形态(动能衰竭) |
//+------------------------------------------------------------------+
int IsMACDPeakOrValley(int lookback = 5)
{
double hist[5] = {0, 0, 0, 0, 0}; // 显式初始化
for (int i = 0; i < 5; i++)
hist[i] = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, i);
// 山峰形态(中间最高)
if (hist[1] < hist[2] && hist[2] > hist[3] && hist[0] < hist[2])
return 1;
// 谷底形态(中间最低)
if (hist[1] > hist[2] && hist[2] < hist[3] && hist[0] > hist[2])
return -1;
return 0;
}
//+------------------------------------------------------------------+
//| 判断MACD线与信号线交叉是否角度陡峭 |
//+------------------------------------------------------------------+
bool IsMACDCrossWithSteepAngle(int lookback = 3)
{
double angle = 0;
for (int i = 0; i < lookback - 1; i++)
{
double currentMain = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, i);
double currentSignal = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 1, i);
double nextMain = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, i + 1);
double nextSignal = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 1, i + 1);
angle += MathAbs(currentMain - currentSignal) - MathAbs(nextMain - nextSignal);
}
return MathAbs(angle) > 0.0001;
}
//+------------------------------------------------------------------+
//| 计算MACD线与信号线之间的平均距离(用于衡量趋势强度) |
//+------------------------------------------------------------------+
double GetMACDLineDistanceFromSignal(int lookback = 5)
{
double sum = 0;
for (int i = 0; i < lookback; i++)
{
double macd = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, i);
double signal = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 1, i);
sum += MathAbs(macd - signal);
}
return sum / lookback;
}
//+------------------------------------------------------------------+
//| 判断MACD线是否刚刚穿越 0 轴(趋势强度信号) |
//+------------------------------------------------------------------+
int IsMACDLineCrossZero()
{
double macdMain0 = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, 0);
double macdMain1 = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, 1);
if (macdMain1 < 0 && macdMain0 > 0) return 1; // 从下向上穿越
if (macdMain1 > 0 && macdMain0 < 0) return -1; // 从上向下穿越
return 0;
}
//+------------------------------------------------------------------+
//| 判断MACD柱是否刚刚穿越零轴(趋势延续信号) |
//+------------------------------------------------------------------+
int IsMACDHistogramCrossZero()
{
double hist0 = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, 0);
double hist1 = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, 1);
if (hist1 < 0 && hist0 > 0) return 1; // 从下向上穿越
if (hist1 > 0 && hist0 < 0) return -1; // 从上向下穿越
return 0;
}
//+------------------------------------------------------------------+
//| 判断金叉是否发生在0轴上方/下方(增强信号强度) |
//+------------------------------------------------------------------+
int GetMACDSignalWithZeroZone()
{
double macdMain = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, 0);
double macdSignal = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 1, 0);
double macdPrevMain = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, 1);
double macdPrevSignal = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 1, 1);
if (macdPrevMain < macdPrevSignal && macdMain > macdSignal)
{
if (macdMain > 0) return 1; // 在0轴上方金叉,强度更高
else return 0; // 在0轴下方金叉,不采用
}
if (macdPrevMain > macdPrevSignal && macdMain < macdSignal)
{
if (macdMain < 0) return -1; // 在0轴下方死叉,强度更高
else return 0; // 在0轴上方死叉,不采用
}
return 0;
}
//+------------------------------------------------------------------+
//| 检测MACD线斜率变化(判断趋势是否加速/减速) |
//+------------------------------------------------------------------+
int DetectMACDTrendAcceleration()
{
double slope = 0;
for (int i = 0; i < 3; i++)
{
double current = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, i);
double next = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 0, i + 1);
slope += (next - current);
}
if (slope > 0) return 1; // 加速上涨
if (slope < 0) return -1; // 加速下跌
return 0;
}
//+------------------------------------------------------------------+
//| 检测MACD柱的“二次放大”信号 |
//+------------------------------------------------------------------+
int CheckMACDHistogramReacceleration()
{
double hist[5] = {0, 0, 0, 0, 0};
for (int i = 0; i < 5; i++)
hist[i] = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, i);
// 判断是否先缩小后放大(二次加速)
if (hist[0] < hist[1] && hist[1] > hist[2] && hist[2] < hist[3] && hist[3] < hist[4])
return 1; // 多头二次加速
if (hist[0] > hist[1] && hist[1] < hist[2] && hist[2] > hist[3] && hist[3] > hist[4])
return -1; // 空头二次加速
return 0;
}
//+------------------------------------------------------------------+
//| 检查MACD面积是否缩小(用于平仓) |
//+------------------------------------------------------------------+
void CheckMACDAreaClose()
{
for (int i = 0; i < OrdersTotal(); i++)
{
if (!OrderSelect(i, SELECT_BY_POS)) continue;
if (OrderSymbol() != Symbol()) continue;
double currentArea = CalculateMACDArea(AreaLookback);
if (currentArea == 0) continue;
int type = OrderType();
if (type == OP_BUY)
{
// 多单:MACD面积缩小 + 持续下降趋势
if (MathAbs(currentArea) < MinMACDArea || IsMACDAreaShrinking(AreaLookback))
{
if (!OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrRed))
Print("平仓失败,错误码: ", GetLastError());
else
Print("【MACD面积衰减】多单平仓 @ ", DoubleToStr(Bid, Digits));
}
}
if (type == OP_SELL)
{
// 空单:MACD面积缩小 + 持续下降趋势
if (MathAbs(currentArea) < MinMACDArea || IsMACDAreaShrinking(AreaLookback))
{
if (!OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrRed))
Print("平仓失败,错误码: ", GetLastError());
else
Print("【MACD面积衰减】空单平仓 @ ", DoubleToStr(Ask, Digits));
}
}
}
}
//+------------------------------------------------------------------+
//| 开多单 |
//+------------------------------------------------------------------+
void OpenBuyOrder()
{
double sl = Ask - StopLoss * Point;
double tp = Ask + TakeProfit * Point;
ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp, "MACD Buy", 0, 0, clrGreen);
if (ticket < 0)
Print("多单开仓失败,错误码: ", GetLastError());
else
Print("【多单开仓】价格: ", DoubleToStr(Ask, Digits), " 止损: ", DoubleToStr(sl, Digits), " 止盈: ", DoubleToStr(tp, Digits));
}
//+------------------------------------------------------------------+
//| 开空单 |
//+------------------------------------------------------------------+
void OpenSellOrder()
{
double sl = Bid + StopLoss * Point;
double tp = Bid - TakeProfit * Point;
ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp, "MACD Sell", 0, 0, clrRed);
if (ticket < 0)
Print("空单开仓失败,错误码: ", GetLastError());
else
Print("【空单开仓】价格: ", DoubleToStr(Bid, Digits), " 止损: ", DoubleToStr(sl, Digits), " 止盈: ", DoubleToStr(tp, Digits));
}
//+------------------------------------------------------------------+
//| 管理跟踪止损 |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
for (int i = 0; i < OrdersTotal(); i++)
{
if (!OrderSelect(i, SELECT_BY_POS)) continue;
if (OrderSymbol() != Symbol()) continue;
double openPrice = OrderOpenPrice();
double currentPrice = (OrderType() == OP_BUY) ? Bid : Ask;
double profitPoints = (OrderType() == OP_BUY)
? (currentPrice - openPrice) / Point
: (openPrice - currentPrice) / Point;
if (UseTrailingStop && profitPoints >= TrailingStart)
{
double newStopLoss = 0;
if (OrderType() == OP_BUY)
newStopLoss = currentPrice - TrailingStop * Point;
else
newStopLoss = currentPrice + TrailingStop * Point;
if (newStopLoss != OrderStopLoss())
{
if (!OrderModify(OrderTicket(), openPrice, newStopLoss, OrderTakeProfit(), 0, clrGreen))
Print("跟踪止损更新失败,错误码: ", GetLastError());
else
Print("【跟踪止损更新】新止损: ", DoubleToStr(newStopLoss, Digits));
}
}
}
}
//+------------------------------------------------------------------+
//| 计算MACD面积(Histogram的累计值) |
//+------------------------------------------------------------------+
double CalculateMACDArea(int bars = 5)
{
double area = 0;
for (int i = 0; i < bars; i++)
{
double hist = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, i);
area += hist;
}
return area;
}
//+------------------------------------------------------------------+
//| 判断MACD面积是否连续缩小(用于趋势衰减判断) |
//+------------------------------------------------------------------+
bool IsMACDAreaShrinking(int bars = 5)
{
double areas[];
ArrayResize(areas, bars);
for (int i = 0; i < bars; i++)
{
areas[i] = 0;
for (int j = 0; j <= i; j++)
{
double hist = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, j);
areas[i] += hist;
}
}
// 多头:面积持续缩小(正值减少)
if (areas[0] > 0)
{
for (int i = 0; i < bars - 1; i++)
if (MathAbs(areas[i]) <= MathAbs(areas[i + 1]))
return false;
return true;
}
// 空头:面积持续缩小(负值减少)
else if (areas[0] < 0)
{
for (int i = 0; i < bars - 1; i++)
if (MathAbs(areas[i]) <= MathAbs(areas[i + 1]))
return false;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 判断MACD柱状图连续上涨/下跌的根数 |
//+------------------------------------------------------------------+
int CountMACDBarTrend(int maxBars = 20)
{
int count = 0;
double prevHist = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, 0);
for (int i = 1; i < maxBars; i++)
{
double currentHist = iMACD(NULL, 0, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE, 2, i);
if ((prevHist > 0 && currentHist > prevHist) || (prevHist < 0 && currentHist < prevHist))
{
count++;
prevHist = currentHist;
}
else
break;
}
return count;
}
帮我加K线形态
最新发布