Summary: 专业的MT4 EA源码,融合随机指标技术信号与可控马丁格尔仓位管理。包含最大持仓限制、保本止损、点差控制等风控功能,完整代码供学习研究。




# 随机指标马丁格尔EA - 完整MQL4源码

本文提供一个完整的自动交易EA,将随机指标(Stochastic Oscillator)技术信号与可控的马丁格尔仓位管理策略相结合。与纯马丁格尔系统不同,本EA仅在随机指标确认超卖/超买条件时才加仓,为入场决策提供了技术过滤。

策略逻辑



EA使用随机振荡器作为主要信号生成器。当随机指标%K线跌破超卖线(默认20)后回升至线上时产生买入信号;当突破超买线(默认80)后回落至线下时产生卖出信号。马丁格尔组件仅应用于亏损持仓,配备可配置的倍数和最大持仓限制,防止风险呈指数级增长。

完整MQL4代码



```mql4
//+------------------------------------------------------------------+
//| StochasticMartingaleEA.mq4 |
//| 自主编译 |
//| |
//+------------------------------------------------------------------+
#property copyright "AI助手"
#property link ""
#property version "1.00"
#property strict

//--- 输入参数
input double InitialLot = 0.01; // 初始手数
input double MartingaleMultiplier = 2.0; // 亏损后手数倍数
input int MaxPositions = 5; // 最大马丁格尔持仓次数
input double MaxLot = 2.0; // 最大允许手数
input int StochasticK = 5; // 随机指标%K周期
input int StochasticD = 3; // 随机指标%D周期
input int StochasticSlowing = 3; // 随机指标减速值
input int Overbought = 80; // 超买线
input int Oversold = 20; // 超卖线
input int StopLoss = 50; // 止损点数
input int TakeProfit = 100; // 止盈点数
input int BreakEvenPips = 30; // 保本触发点数(0=关闭)
input int MaxSpread = 35; // 最大允许点差
input bool UseTimeFilter = false; // 启用时间过滤
input int StartHour = 8; // 开始交易小时
input int EndHour = 20; // 结束交易小时
input int Slippage = 10; // 最大滑点
input int MagicNumber = 202413; // EA魔术号
input bool CloseOpposite = true; // 反向信号时平仓反向单

//--- 全局变量
double stochMain = 0, stochSignal = 0;
double stochMainPrev = 0, stochSignalPrev = 0;
int pointMultiplier = 10;
bool isBusy = false;

//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
// 检测平台位数
if(Digits == 3 || Digits == 5)
pointMultiplier = 10;
else if(Digits == 2 || Digits == 4)
pointMultiplier = 1;

if(StochasticK < 1 || StochasticD < 1)
{
Print("错误: 随机指标参数无效");
return(INIT_PARAMETERS_INCORRECT);
}
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| EA反初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
//| EA报价处理函数 |
//+------------------------------------------------------------------+
void OnTick()
{
if(isBusy) return;
isBusy = true;

// 时间过滤检查
if(!IsTradingTime())
{
isBusy = false;
return;
}

// 点差检查
if(!IsSpreadOK())
{
isBusy = false;
return;
}

// 计算随机指标
CalculateStochastic();

// 管理现有持仓(保本)
ManageBreakeven();

// 统计当前EA持仓数量
int currentPositions = CountPositions();

// 信号检测 - 仅当未达到最大持仓次数时入场
if(currentPositions < MaxPositions)
{
if(IsBuySignal())
{
if(CloseOpposite) CloseSellPositions();
if(CountBuyPositions() == 0)
{
double lot = CalculateLotSize(currentPositions);
OpenOrder(OP_BUY, lot);
}
}
else if(IsSellSignal())
{
if(CloseOpposite) CloseBuyPositions();
if(CountSellPositions() == 0)
{
double lot = CalculateLotSize(currentPositions);
OpenOrder(OP_SELL, lot);
}
}
}

isBusy = false;
}

//+------------------------------------------------------------------+
//| 计算随机指标值 |
//+------------------------------------------------------------------+
void CalculateStochastic()
{
stochMain = iStochastic(Symbol(), 0, StochasticK, StochasticD, StochasticSlowing, MODE_SMA, 0, MODE_MAIN, 0);
stochSignal = iStochastic(Symbol(), 0, StochasticK, StochasticD, StochasticSlowing, MODE_SMA, 0, MODE_SIGNAL, 0);
stochMainPrev = iStochastic(Symbol(), 0, StochasticK, StochasticD, StochasticSlowing, MODE_SMA, 0, MODE_MAIN, 1);
stochSignalPrev = iStochastic(Symbol(), 0, StochasticK, StochasticD, StochasticSlowing, MODE_SMA, 0, MODE_SIGNAL, 1);
}

//+------------------------------------------------------------------+
//| 检查买入信号 - 随机指标从超卖区上穿 |
//+------------------------------------------------------------------+
bool IsBuySignal()
{
if(stochMain == EMPTY_VALUE || stochMainPrev == EMPTY_VALUE)
return false;

// 主线从超卖区下方回升至线上
bool oversoldCrossover = (stochMainPrev <= Oversold && stochMain > Oversold);
bool signalConfirmation = (stochMain > stochSignal);

return (oversoldCrossover && signalConfirmation);
}

//+------------------------------------------------------------------+
//| 检查卖出信号 - 随机指标从超买区下穿 |
//+------------------------------------------------------------------+
bool IsSellSignal()
{
if(stochMain == EMPTY_VALUE || stochMainPrev == EMPTY_VALUE)
return false;

// 主线从超买区上方回落至线下
bool overboughtCrossunder = (stochMainPrev >= Overbought && stochMain < Overbought);
bool signalConfirmation = (stochMain < stochSignal);

return (overboughtCrossunder && signalConfirmation);
}

//+------------------------------------------------------------------+
//| 基于马丁格尔递进计算手数 |
//+------------------------------------------------------------------+
double CalculateLotSize(int currentLossStreak)
{
double lot = InitialLot;

// 为每个亏损序列应用马丁格尔倍数
for(int i = 0; i < currentLossStreak; i++)
{
lot = lot * MartingaleMultiplier;
}

// 限制最大手数
if(lot > MaxLot)
lot = MaxLot;

// 按允许步长取整
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
if(lotStep > 0)
lot = MathFloor(lot / lotStep) * lotStep;

double minLot = MarketInfo(Symbol(), MODE_MINLOT);
if(lot < minLot)
lot = minLot;

return NormalizeDouble(lot, 2);
}

//+------------------------------------------------------------------+
//| 开仓函数 |
//+------------------------------------------------------------------+
void OpenOrder(int cmd, double lot)
{
double price = (cmd == OP_BUY) ? Ask : Bid;
double sl = 0, tp = 0;

if(StopLoss > 0)
{
if(cmd == OP_BUY)
sl = price - StopLoss * Point * pointMultiplier;
else
sl = price + StopLoss * Point * pointMultiplier;
}

if(TakeProfit > 0)
{
if(cmd == OP_BUY)
tp = price + TakeProfit * Point * pointMultiplier;
else
tp = price - TakeProfit * Point * pointMultiplier;
}

int ticket = OrderSend(Symbol(), cmd, lot, price, Slippage, sl, tp, "StochMartingale", MagicNumber, 0, clrNONE);

if(ticket < 0)
Print("开仓失败. 错误码: ", GetLastError());
else
Print("开仓成功. 订单号: ", ticket, " 手数: ", lot);
}

//+------------------------------------------------------------------+
//| 管理保本止损 |
//+------------------------------------------------------------------+
void ManageBreakeven()
{
if(BreakEvenPips <= 0) return;

for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double breakevenPrice = OrderOpenPrice();
double currentProfit = 0;

if(OrderType() == OP_BUY)
{
currentProfit = (Bid - OrderOpenPrice()) / Point / pointMultiplier;
if(currentProfit >= BreakEvenPips && OrderStopLoss() < breakevenPrice)
{
OrderModify(OrderTicket(), OrderOpenPrice(), breakevenPrice, OrderTakeProfit(), 0, clrNONE);
Print("保本止损已触发 BUY #", OrderTicket());
}
}
else if(OrderType() == OP_SELL)
{
currentProfit = (OrderOpenPrice() - Ask) / Point / pointMultiplier;
if(currentProfit >= BreakEvenPips && (OrderStopLoss() > breakevenPrice || OrderStopLoss() == 0))
{
OrderModify(OrderTicket(), OrderOpenPrice(), breakevenPrice, OrderTakeProfit(), 0, clrNONE);
Print("保本止损已触发 SELL #", OrderTicket());
}
}
}
}
}
}

//+------------------------------------------------------------------+
//| 检查点差是否在限制范围内 |
//+------------------------------------------------------------------+
bool IsSpreadOK()
{
if(MaxSpread <= 0) return true;

int currentSpread = (int)((Ask - Bid) / Point / pointMultiplier);
return (currentSpread <= MaxSpread);
}

//+------------------------------------------------------------------+
//| 检查当前是否在允许交易时间内 |
//+------------------------------------------------------------------+
bool IsTradingTime()
{
if(!UseTimeFilter) return true;

datetime now = TimeCurrent();
MqlDateTime dt;
TimeToStruct(now, dt);

int hour = dt.hour;
return (hour >= StartHour && hour < EndHour);
}

//+------------------------------------------------------------------+
//| 统计EA的总持仓数量 |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}

//+------------------------------------------------------------------+
//| 统计买单数量 |
//+------------------------------------------------------------------+
int CountBuyPositions()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_BUY)
count++;
}
}
return count;
}

//+------------------------------------------------------------------+
//| 统计卖单数量 |
//+------------------------------------------------------------------+
int CountSellPositions()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_SELL)
count++;
}
}
return count;
}

//+------------------------------------------------------------------+
//| 平仓所有买单 |
//+------------------------------------------------------------------+
void CloseBuyPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_BUY)
{
OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrNONE);
}
}
}
}

//+------------------------------------------------------------------+
//| 平仓所有卖单 |
//+------------------------------------------------------------------+
void CloseSellPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_SELL)
{
OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrNONE);
}
}
}
}
//+------------------------------------------------------------------+
```

参数详解



| 参数 | 说明 | 推荐值 |
|------|------|--------|
| 初始手数 | 起始仓位大小 | 0.01 |
| 马丁格尔倍数 | 亏损交易后的手数倍数 | 1.5-2.0 |
| 最大持仓次数 | 连续马丁格尔最大次数 | 3-5 |
| 最大手数 | 绝对最大手数上限 | 1.0-2.0 |
| 随机指标%K | 快线周期 | 5-14 |
| 随机指标%D | 慢线/信号线周期 | 3-5 |
| 超买线 | 超买阈值 | 70-80 |
| 超卖线 | 超卖阈值 | 20-30 |
| 止损点数 | 止损距离 | 40-60 |
| 止盈点数 | 止盈距离 | 80-120 |
| 保本点数 | 移动止损到开仓价的触发点数 | 25-40 |
| 最大点差 | 允许的最大点差 | 20-35 |

安装步骤



1. 复制代码到MT4的MetaEditor(按F4)
2. 创建新的EA(文件 > 新建 > 智能交易系统)
3. 将所有默认代码替换为上方完整代码
4. 按编译按钮(F7)- 确保无错误
5. 从导航器将EA拖拽到图表上
6. 在输入参数选项卡中调整参数
7. 启用自动交易(绿色三角形按钮)

重要风险提示



马丁格尔策略本身存在大回撤的固有风险。本EA中的风控参数(最大持仓次数、最大手数、止损)是关键的安全保护机制。在考虑实盘部署前,务必在模拟账户上进行充分测试。

编译与修改技巧



主要修改方向:
  • 将马丁格尔倍数降至1.5可实现保守型加仓

  • 设置最大持仓次数为3以限制连续加仓

  • 根据时间周期调整随机指标参数(更高时间周期使用更高参数值)

  • 在IsBuySignal/IsSellSignal中嵌入ATR过滤器作为波动率确认


  • 参考来源



    本文EA源码为自主编译,基于随机指标技术分析和马丁格尔资金管理原理。实现中包含必要的风控模块,仅供学习研究使用。

    *如需更专业的优化版EA(含高级过滤器、多周期确认、完整回测套件),请查看我们的付费EA合集。订阅后可每周获取策略更新和独家交易工具。*