//+------------------------------------------------------------------+
//| WWJ_Short_Strategy_Pro.mq5 |
//| Copyright 2024, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property link "https://www.mql5.com"
#property version "2.00"
#property description "健壮版WWJ空单策略"
#property strict
#include <Trade/Trade.mql5>
CTrade Trade;
// 策略参数
input double LotSize = 0.1; // 交易手数
input double ATRMultiplier = 2.5; // ATR止损倍数
input int MinHoldBars = 1; // 最小持仓K线数
input int MinBars = 150; // 最小K线数量
input int SignalConfirmation = 2; // 信号确认次数
// 全局变量
double wwj_current, wwj_previous;
datetime lastBarTime = 0;
int signalCount = 0;
datetime tradeTime = 0;
ulong positionTicket = 0;
//+------------------------------------------------------------------+
//| 精确计算ATR |
//+------------------------------------------------------------------+
double CalculateATR(int period, int shift)
{
if(shift + period >= Bars(_Symbol, _Period))
return 0;
double sum = 0;
for(int i = 0; i < period; i++)
{
int barIndex = shift + i;
if(barIndex >= Bars(_Symbol, _Period) - 1)
break;
double high = iHigh(_Symbol, _Period, barIndex);
double low = iLow(_Symbol, _Period, barIndex);
double prevClose = iClose(_Symbol, _Period, barIndex + 1);
double tr1 = high - low;
double tr2 = MathAbs(high - prevClose);
double tr3 = MathAbs(low - prevClose);
sum += MathMax(tr1, MathMax(tr2, tr3));
}
return sum / period;
}
//+------------------------------------------------------------------+
//| 优化版WWJ指标计算函数 |
//+------------------------------------------------------------------+
double CalculateWWJ(int shift)
{
// 确保有足够历史数据
if(shift + 130 >= Bars(_Symbol, _Period))
return EMPTY_VALUE;
// 计算当前K线的TRJ
double high = iHigh(_Symbol, _Period, shift);
double low = iLow(_Symbol, _Period, shift);
double prevClose = iClose(_Symbol, _Period, shift + 1);
double trj = MathMax(high - low, MathMax(MathAbs(prevClose - high), MathAbs(prevClose - low)));
double ajr = trj; // MA(TRJ,1)
double medianj = (high + low) / 2.0;
// 计算HJH和LJL
double hjh = medianj + ajr;
double ljl = medianj - ajr;
// 搜索125周期内HJH最高点位置
int barsLastHJH = 0;
double highestHJH = -DBL_MAX;
int searchBars = MathMin(125, Bars(_Symbol, _Period) - shift - 1);
for(int i = 0; i < searchBars; i++)
{
int barIndex = shift + i;
double currHigh = iHigh(_Symbol, _Period, barIndex);
double currLow = iLow(_Symbol, _Period, barIndex);
double currPrevClose = iClose(_Symbol, _Period, barIndex + 1);
double currTRJ = MathMax(currHigh - currLow,
MathMax(MathAbs(currPrevClose - currHigh),
MathAbs(currPrevClose - currLow)));
double currHJH = (currHigh + currLow) / 2.0 + currTRJ;
if(currHJH > highestHJH)
{
highestHJH = currHJH;
barsLastHJH = i;
}
}
// 搜索5周期内LJL最低点位置
int barsLastLJL = 0;
double lowestLJL = DBL_MAX;
searchBars = MathMin(5, Bars(_Symbol, _Period) - shift - 1);
for(int i = 0; i < searchBars; i++)
{
int barIndex = shift + i;
double currHigh = iHigh(_Symbol, _Period, barIndex);
double currLow = iLow(_Symbol, _Period, barIndex);
double currPrevClose = iClose(_Symbol, _Period, barIndex + 1);
double currTRJ = MathMax(currHigh - currLow,
MathMax(MathAbs(currPrevClose - currHigh),
MathAbs(currPrevClose - currLow)));
double currLJL = (currHigh + currLow) / 2.0 - currTRJ;
if(currLJL < lowestLJL)
{
lowestLJL = currLJL;
barsLastLJL = i;
}
}
// 计算WJ值
int wj = barsLastHJH - barsLastLJL;
// 计算WWJ值
if(wj > 0)
{
// 寻找自WJ<0以来的最低高点
double minHigh = DBL_MAX;
int barsSinceSignal = MathMin(barsLastHJH, Bars(_Symbol, _Period) - shift - 1);
for(int i = 0; i <= barsSinceSignal; i++)
{
double barHigh = iHigh(_Symbol, _Period, shift + i);
if(barHigh < minHigh) minHigh = barHigh;
}
return minHigh;
}
else if(wj < 0)
{
// 寻找自WJ>0以来的最高低点
double maxLow = -DBL_MAX;
int barsSinceSignal = MathMin(barsLastLJL, Bars(_Symbol, _Period) - shift - 1);
for(int i = 0; i <= barsSinceSignal; i++)
{
double barLow = iLow(_Symbol, _Period, shift + i);
if(barLow > maxLow) maxLow = barLow;
}
return maxLow;
}
return iClose(_Symbol, _Period, shift);
}
//+------------------------------------------------------------------+
//| 初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
// 检查最小K线数量
if(MinBars < 130)
{
Alert("MinBars参数必须大于130!");
return(INIT_PARAMETERS_INCORRECT);
}
// 设置交易对象参数
Trade.SetExpertMagicNumber(202406);
Trade.SetMarginMode();
Trade.SetTypeFillingBySymbol(_Symbol);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 主执行函数 |
//+------------------------------------------------------------------+
void OnTick()
{
// 确保有足够的历史数据
if(Bars(_Symbol, _Period) < MinBars)
{
Comment("等待更多数据...需要", MinBars, "根K线");
return;
}
// 检查新K线
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if(currentBarTime == lastBarTime)
return;
lastBarTime = currentBarTime;
// 计算WWJ值
wwj_previous = wwj_current;
wwj_current = CalculateWWJ(0);
// 跳过无效值
if(wwj_current == EMPTY_VALUE || wwj_previous == EMPTY_VALUE)
{
Comment("指标计算中...");
return;
}
// 调试输出
Comment("WWJ值: ", DoubleToString(wwj_current, 5),
"\n信号强度: ", signalCount, "/", SignalConfirmation,
"\n当前信号: ", (wwj_current <= wwj_previous ? "空单信号" : "平仓信号"));
// 检查空单持仓
bool hasPosition = PositionSelectByTicket(positionTicket);
// ====== 信号处理逻辑 ====== //
// 空头信号
if(wwj_current <= wwj_previous)
{
signalCount++;
}
else
{
signalCount = 0; // 重置计数器
}
// ====== 开仓逻辑 ====== //
if(!hasPosition && signalCount >= SignalConfirmation)
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double atr = CalculateATR(14, 0);
double sl = price + atr * ATRMultiplier;
if(Trade.Sell(LotSize, _Symbol, price, sl, 0, "WWJ空单"))
{
positionTicket = Trade.ResultOrder();
tradeTime = iTime(_Symbol, _Period, 0);
signalCount = 0;
Print("空单开仓成功! 价格:", price, " 止损:", sl);
}
}
// ====== 平仓逻辑 ====== //
if(hasPosition)
{
// 获取持仓信息
PositionSelectByTicket(positionTicket);
datetime positionTime = (datetime)PositionGetInteger(POSITION_TIME);
// 计算持仓K线数
int barsHeld = iBarShift(_Symbol, _Period, positionTime, true);
// 平仓条件
if(wwj_current > wwj_previous && barsHeld >= MinHoldBars)
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(Trade.Buy(LotSize, _Symbol, price, 0, 0, "WWJ平仓"))
{
positionTicket = 0;
Print("空单平仓成功! 价格:", price);
}
}
}
}
以上代码不能在MT5上正常运行,检查并修复其中的错误。
最新发布