//+------------------------------------------------------------------+
//| TrendFollowingEA.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"
#property strict
input double LotSize = 0.01; // 基础交易手数
input double GridStep = 0.3; // 加仓间隔(点)
input int LookbackBars = 100; // 指标计算回溯周期
// 全局变量
double lastBuyPrice = 0; // 最后开仓价格
int positionCount = 0; // 持仓数量
double lastTrendLine = 0; // 上一根K线的多空线值
double prevTrendLine = 0; // 上上一根K线的多空线值
bool trendUp = false; // 当前趋势是否向上
//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
// 初始化历史数据
if(Bars(_Symbol, _Period) < LookbackBars + 10)
{
Print("Not enough historical data");
return(INIT_FAILED);
}
// 计算初始多空线值
lastTrendLine = CalculateTrendLine(1); // 上一根K线
prevTrendLine = CalculateTrendLine(2); // 上上一根K线
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| EA反初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| EA主函数 |
//+------------------------------------------------------------------+
void OnTick()
{
// 获取当前K线的多空线值
double currentTrendLine = CalculateTrendLine(0);
// 判断趋势方向变化
bool newTrendUp = false;
bool newTrendDown = false;
// 趋势转为向上(拐头向上)
if(currentTrendLine > lastTrendLine && lastTrendLine < prevTrendLine)
{
newTrendUp = true;
}
// 趋势转为向下(拐头向下)
if(currentTrendLine < lastTrendLine && lastTrendLine > prevTrendLine)
{
newTrendDown = true;
}
// 趋势转为向上 - 开首单
if(newTrendUp && !trendUp)
{
if(OpenBuyOrder())
{
trendUp = true;
lastBuyPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // 记录开仓价格
}
}
// 当前处于上涨趋势
if(trendUp)
{
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// 双向加仓逻辑:价格波动达到网格间距
if(MathAbs(currentPrice - lastBuyPrice) >= GridStep * _Point)
{
if(OpenBuyOrder())
{
lastBuyPrice = currentPrice; // 更新最后开仓价格
}
}
// 趋势转为向下 - 平掉所有多单
if(newTrendDown)
{
CloseAllBuyPositions();
trendUp = false;
positionCount = 0;
lastBuyPrice = 0;
}
}
// 更新多空线历史值
prevTrendLine = lastTrendLine;
lastTrendLine = currentTrendLine;
}
//+------------------------------------------------------------------+
//| 计算多空线指标 |
//+------------------------------------------------------------------+
double CalculateTrendLine(int barIndex)
{
// 计算TR1: 真实波幅的最大值
double high = iHigh(_Symbol, _Period, barIndex);
double low = iLow(_Symbol, _Period, barIndex);
double prevClose = iClose(_Symbol, _Period, barIndex + 1);
double tr1 = MathMax(high - low,
MathMax(MathAbs(prevClose - high),
MathAbs(prevClose - low)));
// APR: TR1的1期移动平均(实际上就是TR1本身)
double apr = tr1;
// 中价
double median = (high + low) / 2.0;
// 计算HH和LL
double HH = median + apr;
double LL = median - apr;
// 计算W值
int barsSinceHH = -1;
int barsSinceLL = -1;
// 寻找最近一次HH >= HHV(HH,10)的位置
for(int i = barIndex; i < barIndex + LookbackBars; i++)
{
// 计算当前K线的HH
double currentHigh = iHigh(_Symbol, _Period, i);
double currentLow = iLow(_Symbol, _Period, i);
double currentPrevClose = iClose(_Symbol, _Period, i + 1);
double currentTR1 = MathMax(currentHigh - currentLow,
MathMax(MathAbs(currentPrevClose - currentHigh),
MathAbs(currentPrevClose - currentLow)));
double currentMedian = (currentHigh + currentLow) / 2.0;
double currentHH = currentMedian + currentTR1;
// 计算HHV(HH,10)
double hhv = currentHH;
for(int j = i; j < MathMin(i + 10, Bars(_Symbol, _Period) - 1); j++)
{
double tempHigh = iHigh(_Symbol, _Period, j);
double tempLow = iLow(_Symbol, _Period, j);
double tempPrevClose = iClose(_Symbol, _Period, j + 1);
double tempTR1 = MathMax(tempHigh - tempLow,
MathMax(MathAbs(tempPrevClose - tempHigh),
MathAbs(tempPrevClose - tempLow)));
double tempHH = (tempHigh + tempLow) / 2.0 + tempTR1;
if(tempHH > hhv) hhv = tempHH;
}
// 检查条件
if(currentHH >= hhv)
{
barsSinceHH = i - barIndex;
break;
}
}
// 寻找最近一次LLV(LL,5) >= LL的位置
for(int i = barIndex; i < barIndex + LookbackBars; i++)
{
// 计算当前K线的LL
double currentHigh = iHigh(_Symbol, _Period, i);
double currentLow = iLow(_Symbol, _Period, i);
double currentPrevClose = iClose(_Symbol, _Period, i + 1);
double currentTR1 = MathMax(currentHigh - currentLow,
MathMax(MathAbs(currentPrevClose - currentHigh),
MathAbs(currentPrevClose - currentLow)));
double currentMedian = (currentHigh + currentLow) / 2.0;
double currentLL = currentMedian - currentTR1;
// 计算LLV(LL,5)
double llv = currentLL;
for(int j = i; j < MathMin(i + 5, Bars(_Symbol, _Period) - 1); j++)
{
double tempHigh = iHigh(_Symbol, _Period, j);
double tempLow = iLow(_Symbol, _Period, j);
double tempPrevClose = iClose(_Symbol, _Period, j + 1);
double tempTR1 = MathMax(tempHigh - tempLow,
MathMax(MathAbs(tempPrevClose - tempHigh),
MathAbs(tempPrevClose - tempLow)));
double tempLL = (tempHigh + tempLow) / 2.0 - tempTR1;
if(tempLL < llv) llv = tempLL;
}
// 检查条件
if(llv >= currentLL)
{
barsSinceLL = i - barIndex;
break;
}
}
// 如果未找到符合条件的K线,使用默认值
if(barsSinceHH == -1) barsSinceHH = LookbackBars;
if(barsSinceLL == -1) barsSinceLL = LookbackBars;
// 计算W值
int W = barsSinceHH - barsSinceLL;
// 计算BBX和SSX
double BBX = EMPTY_VALUE;
double SSX = EMPTY_VALUE;
// 计算BBX = LLV(H, BARSLAST(W<0))
if(W > 0)
{
int startBar = barIndex + barsSinceLL;
BBX = iHigh(_Symbol, _Period, startBar);
for(int i = startBar; i <= barIndex; i++)
{
double highVal = iHigh(_Symbol, _Period, i);
if(highVal < BBX) BBX = highVal;
}
}
// 计算SSX = HHV(L, BARSLAST(W>0))
else if(W < 0)
{
int startBar = barIndex + barsSinceHH;
SSX = iLow(_Symbol, _Period, startBar);
for(int i = startBar; i <= barIndex; i++)
{
double lowVal = iLow(_Symbol, _Period, i);
if(lowVal > SSX) SSX = lowVal;
}
}
// 计算多空线
double trendLine;
if(W > 0)
trendLine = BBX;
else if(W < 0)
trendLine = SSX;
else
trendLine = iClose(_Symbol, _Period, barIndex);
return trendLine;
}
//+------------------------------------------------------------------+
//| 开多单 |
//+------------------------------------------------------------------+
bool OpenBuyOrder()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = LotSize;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.deviation = 5;
request.type_filling = ORDER_FILLING_FOK;
if(OrderSend(request, result))
{
positionCount++;
Print("Buy order opened. Price: ", request.price, " Lots: ", LotSize);
return true;
}
else
{
Print("Buy order failed. Error: ", GetLastError());
return false;
}
}
//+------------------------------------------------------------------+
//| 平掉所有多单 |
//+------------------------------------------------------------------+
void CloseAllBuyPositions()
{
int total = PositionsTotal();
for(int i = total - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0 && PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.position = ticket;
request.symbol = _Symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.deviation = 5;
request.type_filling = ORDER_FILLING_FOK;
request.type = ORDER_TYPE_SELL;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(OrderSend(request, result))
{
Print("Position closed: ", ticket);
}
else
{
Print("Failed to close position ", ticket, ". Error: ", GetLastError());
}
}
}
}
}
以上代码修改一下,打开允许EA算法交易按钮就开始按照指令进行交易
最新发布