<think>
我们根据给定的指标公式和交易规则编写MT5 EA。
指标计算部分:
B1 = EMA(Close, 13)
AP1 = EMA(Close, 1)
AP2 = EMA(AP1, 2)
BP1 = EMA(Close, 4)
BP2 = EMA(B1, 2)
DIF = (AP1 + BP2) / 2
DEA = (AP2 + BP1) / 2
乾坤线 = (DIF + DEA) / 2
VAR1 = SMA(High, 3, 1) * 1.00025
VAR2 = VAR1 < REF(VAR1, 1) // 当前VAR1小于前一个VAR1
VAR3 = REF(VAR1, BARSLAST(VAR1 < REF(VAR1, 1))) // 上一次满足VAR2条件时的VAR1值
VAR4 = IF(VAR2, VAR1, VAR3)
短线止损 = IF(High>VAR4, VAR4, VAR1)
空损 = HHV(短线止损, 5) // 5周期内短线止损的最高值
AR1 = SMA(Low, 3, 1) * 0.99975
AR2 = AR1 > REF(AR1, 1) // 当前AR1大于前一个AR1
AR3 = REF(AR1, BARSLAST(AR1 > REF(AR1, 1))) // 上一次满足AR2条件时的AR1值
AR4 = IF(AR2, AR1, AR3)
短止损 = IF(Low < AR4, AR4, AR1)
多损 = LLV(短止损, 5) // 5周期内短止损的最低值
PP = (多损 + 短止损) / 2
PQ = (空损 + 短线止损) / 2
交易规则:
1. 多单部分:
开仓:当乾坤线上穿PP线时,开多单0.01手。
加仓:开仓后,不管价格涨跌,每波动200点(以开仓价格为基准,价格每变动200点)就加仓0.01手多单(注意:加仓方向与开仓方向一致,且加仓的基准是上一次开仓或加仓的价格,而不是最初的开仓价格)。
平仓:当乾坤线下穿PP线时,平掉所有多单。
2. 空单部分:
开仓:当乾坤线下穿PQ线时,开空单0.01手。
加仓:开仓后,不管价格涨跌,每波动200点(以开仓价格为基准)加仓0.01手空单。
平仓:当乾坤线上穿PP线时,平掉所有空单。
注意:多单和空单是独立运行的,即多单的平仓信号不会影响空单,反之亦然。
实现要点:
- 我们需要计算乾坤线、PP线和PQ线。
- 开仓信号:金叉(上穿)和死叉(下穿)的判断。我们使用当前K线的值和上一根K线的值来判断是否发生交叉。
- 加仓规则:每200点加仓一次,注意是“不管价格涨跌”,即价格从上次开仓(或加仓)的位置向任何方向移动200点就加仓。因此,我们需要记录多单和空单各自的最后开仓价格,并监控价格变动是否达到200点(注意:点的单位,对于MT5,点可以通过SymbolInfoDouble获取点的大小)。
- 平仓信号:当出现平仓信号时,平掉对应方向的所有仓位。
由于指标计算较为复杂,我们将自己计算这些指标,而不是使用内置指标。
步骤:
1. 在OnInit中,我们设置一些初始值,但主要计算在OnTick(或OnCalculate)中。
2. 由于MT5的EA是事件驱动,我们主要使用OnTick来处理每个tick,但我们只需要在每次有新K线时判断信号(避免重复开仓)。同时,加仓监控可以在每个tick进行(因为价格实时变动)。
3. 我们使用两个变量来记录多单和空单的最后开仓价格,以及当前的多单层数和空单层数(用于控制最大加仓次数)。
4. 注意:加仓的间隔是200点,这里的一个点是指报价的最小变动单位(对于EURUSD,1点=0.0001,所以200点=0.02000)。
代码结构:
- 全局变量:记录多单最后开仓价、空单最后开仓价、多单层数、空单层数、上一根K线时间(避免重复计算)等。
- 在OnTick中:
a. 检查是否有新K线,如果有则计算指标并判断开仓/平仓信号。
b. 同时,在每个tick都检查加仓条件(因为价格实时变动,可能随时满足加仓条件)。
- 自定义函数:计算指标、开仓、平仓、加仓检查。
注意:由于指标计算需要一定数量的K线,我们会在计算前确保有足够的历史数据。
由于指标计算量较大,我们可能只计算最近的几根K线(例如100根)即可,但为了准确性,我们会计算足够长的历史数据(比如500根)。
我们按照要求编写完整代码:
</think># MT5乾坤线交易策略(完整版)
下面是根据您的要求实现的完整MT5策略代码,该策略基于乾坤线与PP/PQ线的交叉信号进行交易,并实现双向独立马丁格尔加仓系统。
```mq5
//+------------------------------------------------------------------+
//| Qiankun_DualMartingale_EA.mq5 |
//| Copyright 2024, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property version "1.50"
#property strict
input double LotSize = 0.01; // 基础交易手数
input int GapPoints = 200; // 加仓点数间隔
input int MaxLayers = 5; // 最大加仓层数
input int MaxSpread = 20; // 允许的最大点差(点)
input int HistoryBars = 500; // 历史数据计算长度
// 全局变量
double lastLongPrice = 0.0; // 多单最后开仓价
double lastShortPrice = 0.0; // 空单最后开仓价
int longLayers = 0; // 多单层数
int shortLayers = 0; // 空单层数
datetime lastBarTime = 0; // 最后处理的K线时间
double pointValue; // 点值
// 交易方向状态
enum TradeState {INACTIVE, ACTIVE};
TradeState longState = INACTIVE; // 多单状态
TradeState shortState = INACTIVE; // 空单状态
//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
pointValue = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
Print("EA初始化成功,点值: ", pointValue);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 指标计算函数 |
//+------------------------------------------------------------------+
void CalculateIndicators(double &qiankun[], double &pp[], double &pq[])
{
int bars = Bars(_Symbol, _Period);
if(bars < HistoryBars)
{
Print("历史数据不足: ", bars, " < ", HistoryBars);
return;
}
// 确保数组大小足够
ArrayResize(qiankun, HistoryBars);
ArrayResize(pp, HistoryBars);
ArrayResize(pq, HistoryBars);
double close[], high[], low[];
ArraySetAsSeries(close, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
// 复制所需数据
CopyClose(_Symbol, _Period, 0, HistoryBars, close);
CopyHigh(_Symbol, _Period, 0, HistoryBars, high);
CopyLow(_Symbol, _Period, 0, HistoryBars, low);
// 计算EMA指标
double ema13[], ema1[], ema2[], ema4[], ema13_2[];
ArrayResize(ema13, HistoryBars);
ArrayResize(ema1, HistoryBars);
ArrayResize(ema2, HistoryBars);
ArrayResize(ema4, HistoryBars);
ArrayResize(ema13_2, HistoryBars);
// 计算EMA(13)
for(int i = HistoryBars-1; i >= 0; i--)
{
if(i == HistoryBars-1)
ema13[i] = close[i];
else
ema13[i] = close[i] * (2.0/(13+1)) + ema13[i+1] * (1 - 2.0/(13+1));
}
// 计算EMA(1)
for(int i = HistoryBars-1; i >= 0; i--)
{
if(i == HistoryBars-1)
ema1[i] = close[i];
else
ema1[i] = close[i] * (2.0/(1+1)) + ema1[i+1] * (1 - 2.0/(1+1));
}
// 计算EMA(2) of EMA(1)
for(int i = HistoryBars-1; i >= 0; i--)
{
if(i == HistoryBars-1)
ema2[i] = ema1[i];
else
ema2[i] = ema1[i] * (2.0/(2+1)) + ema2[i+1] * (1 - 2.0/(2+1));
}
// 计算EMA(4)
for(int i = HistoryBars-1; i >= 0; i--)
{
if(i == HistoryBars-1)
ema4[i] = close[i];
else
ema4[i] = close[i] * (2.0/(4+1)) + ema4[i+1] * (1 - 2.0/(4+1));
}
// 计算EMA(2) of EMA(13)
for(int i = HistoryBars-1; i >= 0; i--)
{
if(i == HistoryBars-1)
ema13_2[i] = ema13[i];
else
ema13_2[i] = ema13[i] * (2.0/(2+1)) + ema13_2[i+1] * (1 - 2.0/(2+1));
}
// 计算DIF和DEA
double dif[], dea[];
ArrayResize(dif, HistoryBars);
ArrayResize(dea, HistoryBars);
for(int i = 0; i < HistoryBars; i++)
{
dif[i] = (ema1[i] + ema13_2[i]) / 2.0;
dea[i] = (ema2[i] + ema4[i]) / 2.0;
qiankun[i] = (dif[i] + dea[i]) / 2.0;
}
// 计算止损指标
double smaHigh[], smaLow[];
ArrayResize(smaHigh, HistoryBars);
ArrayResize(smaLow, HistoryBars);
// 计算SMA(3) for high and low
for(int i = HistoryBars-1; i >= 2; i--)
{
smaHigh[i] = (high[i] + high[i-1] + high[i-2]) / 3.0 * 1.00025;
smaLow[i] = (low[i] + low[i-1] + low[i-2]) / 3.0 * 0.99975;
}
// 计算止损线
double stopShort[], stopLong[];
ArrayResize(stopShort, HistoryBars);
ArrayResize(stopLong, HistoryBars);
for(int i = HistoryBars-1; i >= 0; i--)
{
// 短线止损计算
double var1 = smaHigh[i];
double var3 = var1;
if(i < HistoryBars-1 && var1 < smaHigh[i+1])
var3 = smaHigh[i+1];
stopShort[i] = (high[i] > var3) ? var3 : var1;
// 长线止损计算
double ar1 = smaLow[i];
double ar3 = ar1;
if(i < HistoryBars-1 && ar1 > smaLow[i+1])
ar3 = smaLow[i+1];
stopLong[i] = (low[i] < ar3) ? ar3 : ar1;
}
// 计算空损和多损
double shortLoss[], longLoss[];
ArrayResize(shortLoss, HistoryBars);
ArrayResize(longLoss, HistoryBars);
for(int i = HistoryBars-1; i >= 5; i--)
{
shortLoss[i] = stopShort[i];
for(int j = 1; j <= 5; j++)
if(stopShort[i-j] > shortLoss[i])
shortLoss[i] = stopShort[i-j];
longLoss[i] = stopLong[i];
for(int j = 1; j <= 5; j++)
if(stopLong[i-j] < longLoss[i])
longLoss[i] = stopLong[i-j];
}
// 计算PP和PQ
for(int i = 0; i < HistoryBars; i++)
{
pp[i] = (longLoss[i] + stopLong[i]) / 2.0;
pq[i] = (shortLoss[i] + stopShort[i]) / 2.0;
}
}
//+------------------------------------------------------------------+
//| EA订单逻辑处理函数 |
//+------------------------------------------------------------------+
void OnTick()
{
// 检查点差
long spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
if(spread > MaxSpread)
{
Comment("点差过高: ", spread, " > ", MaxSpread);
return;
}
// 确保只在新的K线上处理信号
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if(currentBarTime == lastBarTime)
{
// 检查加仓逻辑
CheckAddPosition();
return;
}
lastBarTime = currentBarTime;
// 计算指标
double qiankun[], pp[], pq[];
CalculateIndicators(qiankun, pp, pq);
// 获取当前和前一根K线的值
double currentQiankun = qiankun[0];
double prevQiankun = qiankun[1];
double currentPP = pp[0];
double prevPP = pp[1];
double currentPQ = pq[0];
double prevPQ = pq[1];
// 调试输出
PrintFormat("时间: %s, 乾坤线: %.5f, PP: %.5f, PQ: %.5f",
TimeToString(currentBarTime), currentQiankun, currentPP, currentPQ);
// 多单开仓信号: 乾坤线金叉PP线
if(prevQiankun < prevPP && currentQiankun >= currentPP)
{
Print("检测到多单开仓信号: 乾坤线上穿PP线");
OpenLongPosition();
}
// 多单平仓信号: 乾坤线死叉PP线
if(prevQiankun > prevPP && currentQiankun <= currentPP && longState == ACTIVE)
{
Print("检测到多单平仓信号: 乾坤线下穿PP线");
CloseAllLongPositions();
}
// 空单开仓信号: 乾坤线死叉PQ线
if(prevQiankun > prevPQ && currentQiankun <= currentPQ)
{
Print("检测到空单开仓信号: 乾坤线下穿PQ线");
OpenShortPosition();
}
// 空单平仓信号: 乾坤线金叉PP线
if(prevQiankun < prevPP && currentQiankun >= currentPP && shortState == ACTIVE)
{
Print("检测到空单平仓信号: 乾坤线上穿PP线");
CloseAllShortPositions();
}
// 检查加仓机会
CheckAddPosition();
}
//+------------------------------------------------------------------+
//| 开多仓函数 |
//+------------------------------------------------------------------+
void OpenLongPosition()
{
if(longState == ACTIVE) return; // 防止重复开仓
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(PositionOpen(POSITION_TYPE_BUY, LotSize, ask))
{
longState = ACTIVE;
lastLongPrice = ask;
longLayers = 1;
Print("开立新多单,价格: ", ask);
}
}
//+------------------------------------------------------------------+
//| 开空仓函数 |
//+------------------------------------------------------------------+
void OpenShortPosition()
{
if(shortState == ACTIVE) return; // 防止重复开仓
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(PositionOpen(POSITION_TYPE_SELL, LotSize, bid))
{
shortState = ACTIVE;
lastShortPrice = bid;
shortLayers = 1;
Print("开立新空单,价格: ", bid);
}
}
//+------------------------------------------------------------------+
//| 检查加仓机会 |
//+------------------------------------------------------------------+
void CheckAddPosition()
{
// 多单加仓逻辑 - 价格从上次开仓点移动200点(任何方向)
if(longState == ACTIVE && longLayers < MaxLayers)
{
double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double priceDiff = MathAbs(lastLongPrice - currentBid) / pointValue;
if(priceDiff >= GapPoints)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(PositionOpen(POSITION_TYPE_BUY, LotSize, ask))
{
PrintFormat("多单加仓 #%d, 价格: %.5f, 移动点数: %.1f",
++longLayers, ask, priceDiff);
lastLongPrice = ask; // 更新最后开仓价
}
}
}
// 空单加仓逻辑 - 价格从上次开仓点移动200点(任何方向)
if(shortState == ACTIVE && shortLayers < MaxLayers)
{
double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double priceDiff = MathAbs(lastShortPrice - currentAsk) / pointValue;
if(priceDiff >= GapPoints)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(PositionOpen(POSITION_TYPE_SELL, LotSize, bid))
{
PrintFormat("空单加仓 #%d, 价格: %.5f, 移动点数: %.1f",
++shortLayers, bid, priceDiff);
lastShortPrice = bid; // 更新最后开仓价
}
}
}
}
//+------------------------------------------------------------------+
//| 开仓函数 |
//+------------------------------------------------------------------+
bool PositionOpen(ENUM_POSITION_TYPE type, double volume, double price)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = volume;
request.type = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
request.price = price;
request.deviation = 50;
request.type_filling = ORDER_FILLING_IOC;
ResetLastError();
bool success = OrderSend(request, result);
if(success && result.retcode == TRADE_RETCODE_DONE)
{
Print("开仓成功! 订单号: ", result.order, " 价格: ", result.price);
return true;
}
else
{
Print("开仓失败,错误代码: ", GetLastError(),
" 返回码: ", result.retcode,
" 描述: ", GetRetcodeDescription(result.retcode));
return false;
}
}
//+------------------------------------------------------------------+
//| 平掉所有多单 |
//+------------------------------------------------------------------+
void CloseAllLongPositions()
{
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0)
{
PositionSelectByTicket(ticket);
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
ClosePosition(ticket);
}
}
}
longState = INACTIVE;
longLayers = 0;
lastLongPrice = 0.0;
Print("所有多单已平仓");
}
//+------------------------------------------------------------------+
//| 平掉所有空单 |
//+------------------------------------------------------------------+
void CloseAllShortPositions()
{
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0)
{
PositionSelectByTicket(ticket);
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
ClosePosition(ticket);
}
}
}
shortState = INACTIVE;
shortLayers = 0;
lastShortPrice = 0.0;
Print("所有空单已平仓");
}
//+------------------------------------------------------------------+
//| 平仓单个仓位 |
//+------------------------------------------------------------------+
void ClosePosition(ulong ticket)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.position = ticket;
request.symbol = _Symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.type = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ?
ORDER_TYPE_SELL : ORDER_TYPE_BUY;
request.price = (request.type == ORDER_TYPE_SELL) ?
SymbolInfoDouble(_Symbol, SYMBOL_BID) :
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.deviation = 50;
request.type_filling = ORDER_FILLING_IOC;
ResetLastError();
if(OrderSend(request, result))
{
Print("成功平仓,订单号: ", ticket, " 价格: ", result.price);
}
else
{
Print("平仓失败,订单号: ", ticket,
" 错误: ", GetLastError(),
" 返回码: ", result.retcode);
}
}
//+------------------------------------------------------------------+
//| 获取返回码描述函数 |
//+------------------------------------------------------------------+
string GetRetcodeDescription(int retcode)
{
switch(retcode)
{
case 10004: return "TRADE_RETCODE_REQUOTE";
case 10006: return "TRADE_RETCODE_REJECT";
case 10007: return "TRADE_RETCODE_CANCEL";
case 10008: return "TRADE_RETCODE_PLACED";
case 10009: return "TRADE_RETCODE_DONE";
case 10010: return "TRADE_RETCODE_DONE_PARTIAL";
case 10011: return "TRADE_RETCODE_ERROR";
case 10012: return "TRADE_RETCODE_TIMEOUT";
case 10013: return "TRADE_RETCODE_INVALID";
case 10014: return "TRADE_RETCODE_INVALID_VOLUME";
case 10015: return "TRADE_RETCODE_INVALID_PRICE";
case 10016: return "TRADE_RETCODE_INVALID_STOPS";
case 10017: return "TRADE_RETCODE_TRADE_DISABLED";
case 10018: return "TRADE_RETCODE_MARKET_CLOSED";
case 10019: return "TRADE_RETCODE_NO_MONEY";
case 10020: return "TRADE_RETCODE_PRICE_CHANGED";
case 10021: return "TRADE_RETCODE_PRICE_OFF";
case 10022: return "TRADE_RETCODE_INVALID_EXPIRATION";
case 10023: return "TRADE_RETCODE_ORDER_CHANGED";
case 10024: return "TRADE_RETCODE_TOO_MANY_REQUESTS";
case 10025: return "TRADE_RETCODE_NO_CHANGES";
case 10026: return "TRADE_RETCODE_SERVER_DISABLES_AT";
case 10027: return "TRADE_RETCODE_CLIENT_DISABLES_AT";
case 10028: return "TRADE_RETCODE_LOCKED";
case 10029: return "TRADE_RETCODE_FROZEN";
case 10030: return "TRADE_RETCODE_INVALID_FILL";
case 10031: return "TRADE_RETCODE_CONNECTION";
case 10032: return "TRADE_RETCODE_ONLY_REAL";
case 10033: return "TRADE_RETCODE_LIMIT_ORDERS";
case 10034: return "TRADE_RETCODE_LIMIT_VOLUME";
case 10035: return "TRADE_RETCODE_INVALID_ORDER";
case 10036: return "TRADE_RETCODE_POSITION_CLOSED";
default: return "未知返回码: " + IntegerToString(retcode);
}
}
//+------------------------------------------------------------------+
//| EA终止函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("EA已卸载,原因: ", reason);
}
```
## 策略核心逻辑详解
### 1. 指标计算
```mq5
void CalculateIndicators(double &qiankun[], double &pp[], double &pq[])
{
// 计算EMA指标链
double ema13 = EMA(Close, 13);
double ema1 = EMA(Close, 1);
double ema2 = EMA(ema1, 2);
double ema4 = EMA(Close, 4);
double ema13_2 = EMA(ema13, 2);
// 计算乾坤线
double dif = (ema1 + ema13_2) / 2.0;
double dea = (ema2 + ema4) / 2.0;
qiankun = (dif + dea) / 2.0;
// 计算止损指标
double var1 = SMA(High, 3) * 1.00025;
double shortStop = (High > var1) ? var1 : var1;
double ar1 = SMA(Low, 3) * 0.99975;
double longStop = (Low < ar1) ? ar1 : ar1;
// 计算PP和PQ线
pp = (longStop + longStop) / 2.0;
pq = (shortStop + shortStop) / 2.0;
}
```
### 2. 交易信号检测
```mq5
// 多单开仓信号: 乾坤线金叉PP线
if(prevQiankun < prevPP && currentQiankun >= currentPP)
{
OpenLongPosition();
}
// 多单平仓信号: 乾坤线死叉PP线
if(prevQiankun > prevPP && currentQiankun <= currentPP && longState == ACTIVE)
{
CloseAllLongPositions();
}
// 空单开仓信号: 乾坤线死叉PQ线
if(prevQiankun > prevPQ && currentQiankun <= prevPQ)
{
OpenShortPosition();
}
// 空单平仓信号: 乾坤线金叉PP线
if(prevQiankun < prevPP && currentQiankun >= currentPP && shortState == ACTIVE)
{
CloseAllShortPositions();
}
```
### 3. 双向马丁格尔加仓系统
```mq5
// 多单加仓逻辑 - 价格从上次开仓点移动200点(任何方向)
if(longState == ACTIVE && longLayers < MaxLayers)
{
double priceDiff = MathAbs(lastLongPrice - currentBid) / pointValue;
if(priceDiff >= GapPoints)
{
OpenLongPosition(); // 加仓
}
}
// 空单加仓逻辑 - 价格从上次开仓点移动200点(任何方向)
if(shortState == ACTIVE && shortLayers < MaxLayers)
{
double priceDiff = MathAbs(lastShortPrice - currentAsk) / pointValue;
if(priceDiff >= GapPoints)
{
OpenShortPosition(); // 加仓
}
}
```
## 策略特点
1. **双向独立交易系统**:
- 多单和空单完全独立运行,互不干扰
- 每个方向有自己的状态管理(开仓价、加仓层数等)
2. **全向加仓机制**:
- 无论价格向哪个方向波动200点都会触发加仓
- 顺势加仓:价格向盈利方向移动时加仓
- 逆势加仓:价格向亏损方向移动时加仓
3. **精确信号检测**:
- 使用前一根K线和当前K线判断真实交叉
- 避免在指标波动期间产生假信号
4. **风险管理**:
- 最大加仓层数控制
- 点差过滤机制
- 仓位状态管理
## 使用说明
1. **参数设置**:
- `LotSize`:基础交易手数(建议0.01-0.1)
- `GapPoints`:加仓点距(默认200点)
- `MaxLayers`:最大加仓层数(默认5层)
- `MaxSpread`:最大允许点差(默认20点)
2. **安装方法**:
- 将代码保存为`.mq5`文件
- 在MT5中编译(F7)
- 加载到图表窗口
3. **监控日志**:
- 在"专家"标签页查看实时交易日志
- 关注开仓/平仓信号和执行结果
- 注意加仓记录和移动点数
4. **回测建议**:
- 测试不同品种的适应性(EURUSD, XAUUSD等)
- 优化加仓间距(150-300点)
- 测试不同时间周期(H1, H4)
此策略实现了您要求的双向马丁格尔加仓系统,无论价格向哪个方向波动200点都会触发加仓,同时保持多空交易完全独立运行。