//±-----------------------------------------------------------------+
//| 马丁加仓EA.mq5 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//±-----------------------------------------------------------------+
#property copyright "Copyright 2023"
#property version "1.00"
#property script_show_inputs
input double BaseVolume = 0.01; // 基础手数 [由0.1改为0.01]
input int GapPoints = 30; // 加仓点数间隔
#include <Trade/Trade.mqh>
CTrade trade;
//— 全局变量
enum ENUM_MODE {MODE_NONE, MODE_BUY, MODE_SELL};
ENUM_MODE currentMode = MODE_NONE; // 当前模式:无/做多/做空
double lastBuyPrice = 0.0; // 上一次做多开仓价
double lastSellPrice = 0.0; // 上一次做空开仓价
//±-----------------------------------------------------------------+
//| EA初始化函数 |
//±-----------------------------------------------------------------+
int OnInit()
{
// 创建交易按钮
CreateButton("一键做多", 10, 50, 100, 30, clrGreen, "StartBuy");
CreateButton("一键做空", 120, 50, 100, 30, clrRed, "StartSell");
CreateButton("一键清仓", 230, 50, 100, 30, clrGray, "CloseAll");
CreateButton("一键锁仓", 340, 50, 100, 30, clrBlue, "LockPos");
CreateButton("平盈利单", 10, 90, 100, 30, clrGold, "CloseProfit");
CreateButton("平亏损单", 120, 90, 100, 30, clrOrange, "CloseLoss");
CreateButton("平多单盈利", 230, 90, 100, 30, clrGreen, "CloseBuyProfit");
CreateButton("平空单盈利", 340, 90, 100, 30, clrRed, "CloseSellProfit");
// 创建手数和间距输入框
CreateLabel("开仓手数:", 10, 130, 80, 20, clrWhite, "LabelVolume");
CreateEditBox("0.01", 90, 130, 80, 20, clrWhite, "InputVolume");
CreateLabel("加仓间距(点):", 180, 130, 100, 20, clrWhite, "LabelGap");
CreateEditBox("30", 280, 130, 80, 20, clrWhite, "InputGap");
// 设置初始值
ObjectSetString(0, "InputVolume", OBJPROP_TEXT, DoubleToString(BaseVolume, 2));
ObjectSetString(0, "InputGap", OBJPROP_TEXT, IntegerToString(GapPoints));
// 设置异步交易模式
trade.SetAsyncMode(true);
return(INIT_SUCCEEDED);
}
//±-----------------------------------------------------------------+
//| EA订单逻辑处理函数 |
//±-----------------------------------------------------------------+
void OnTick()
{
// 马丁加仓逻辑
if(currentMode == MODE_BUY)
{
double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double pointValue = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// 获取当前加仓间距
int currentGapPoints = GetGapPoints();
// 检查是否需要加仓(价格下跌指定点数)
if(lastBuyPrice - currentBid >= currentGapPoints * pointValue)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
trade.Buy(GetBaseVolume(), _Symbol, ask, 0, 0);
lastBuyPrice = ask;
}
}
else if(currentMode == MODE_SELL)
{
double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double pointValue = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// 获取当前加仓间距
int currentGapPoints = GetGapPoints();
// 检查是否需要加仓(价格上涨指定点数)
if(currentAsk - lastSellPrice >= currentGapPoints * pointValue)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
trade.Sell(GetBaseVolume(), _Symbol, bid, 0, 0);
lastSellPrice = bid;
}
}
}
//±-----------------------------------------------------------------+
//| 创建按钮函数 |
//±-----------------------------------------------------------------+
void CreateButton(string text, int x, int y, int width, int height, color bgColor, string name)
{
if(!ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0)) return;
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_XSIZE, width);
ObjectSetInteger(0, name, OBJPROP_YSIZE, height);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bgColor);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
}
//±-----------------------------------------------------------------+
//| 创建标签函数 |
//±-----------------------------------------------------------------+
void CreateLabel(string text, int x, int y, int width, int height, color textColor, string name)
{
if(!ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0)) return;
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_XSIZE, width);
ObjectSetInteger(0, name, OBJPROP_YSIZE, height);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_COLOR, textColor);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
}
//±-----------------------------------------------------------------+
//| 创建编辑框函数 |
//±-----------------------------------------------------------------+
void CreateEditBox(string text, int x, int y, int width, int height, color textColor, string name)
{
if(!ObjectCreate(0, name, OBJ_EDIT, 0, 0, 0)) return;
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_XSIZE, width);
ObjectSetInteger(0, name, OBJPROP_YSIZE, height);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_COLOR, textColor);
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrSilver);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
ObjectSetInteger(0, name, OBJPROP_ALIGN, ALIGN_CENTER);
}
//±-----------------------------------------------------------------+
//| 获取当前基础手数 |
//±-----------------------------------------------------------------+
double GetBaseVolume()
{
string text = ObjectGetString(0, "InputVolume", OBJPROP_TEXT);
double volume = StringToDouble(text);
return(volume > 0 ? volume : BaseVolume);
}
//±-----------------------------------------------------------------+
//| 获取当前加仓间距 |
//±-----------------------------------------------------------------+
int GetGapPoints()
{
string text = ObjectGetString(0, "InputGap", OBJPROP_TEXT);
int gap = (int)StringToInteger(text);
return(gap > 0 ? gap : GapPoints);
}
//±-----------------------------------------------------------------+
//| 图表事件处理函数 |
//±-----------------------------------------------------------------+
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
// 处理按钮点击事件
if(id == CHARTEVENT_OBJECT_CLICK)
{
//— 一键做多
if(sparam == "StartBuy")
{
currentMode = MODE_BUY;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
trade.Buy(GetBaseVolume(), _Symbol, ask, 0, 0);
lastBuyPrice = ask;
}
//— 一键做空
else if(sparam == "StartSell")
{
currentMode = MODE_SELL;
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
trade.Sell(GetBaseVolume(), _Symbol, bid, 0, 0);
lastSellPrice = bid;
}
//— 一键清仓 [优化为批量平仓]
else if(sparam == "CloseAll")
{
currentMode = MODE_NONE;
CloseAllPositionsFast();
}
//— 一键锁仓
else if(sparam == "LockPos")
{
LockPositions();
}
//— 平止盈单
else if(sparam == "CloseProfit")
{
CloseProfitPositions();
}
//— 平亏损单
else if(sparam == "CloseLoss")
{
CloseLossPositions();
}
//— 平多单盈利单
else if(sparam == "CloseBuyProfit")
{
ClosePositionsByTypeAndProfit(POSITION_TYPE_BUY, true);
}
//— 平空单盈利单
else if(sparam == "CloseSellProfit")
{
ClosePositionsByTypeAndProfit(POSITION_TYPE_SELL, true);
}
}
}
//±-----------------------------------------------------------------+
//| 快速关闭所有持仓(批量平仓优化) |
//±-----------------------------------------------------------------+
void CloseAllPositionsFast()
{
// 收集所有仓位的ticket
ulong tickets[];
int total = PositionsTotal();
if(total > 0)
{
ArrayResize(tickets, total);
for(int i = 0; i < total; i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == _Symbol)
{
tickets[i] = ticket;
}
}
// 批量平仓所有仓位
for(int i = 0; i < total; i++)
{
if(tickets[i] > 0)
{
trade.PositionClose(tickets[i]);
}
}
}
}
//±-----------------------------------------------------------------+
//| 锁仓函数(批量优化) |
//±-----------------------------------------------------------------+
void LockPositions()
{
double buyVolume = 0.0;
double sellVolume = 0.0;
// 计算多空总手数
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == _Symbol)
{
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
buyVolume += PositionGetDouble(POSITION_VOLUME);
else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
sellVolume += PositionGetDouble(POSITION_VOLUME);
}
}
// 批量开对冲单
if(buyVolume > sellVolume)
{
double volume = buyVolume - sellVolume;
trade.Sell(volume, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_BID));
}
else if(sellVolume > buyVolume)
{
double volume = sellVolume - buyVolume;
trade.Buy(volume, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_ASK));
}
}
//±-----------------------------------------------------------------+
//| 平盈利单(批量优化) |
//±-----------------------------------------------------------------+
void CloseProfitPositions()
{
// 收集所有盈利仓位的ticket
ulong tickets[];
int count = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == _Symbol)
{
double profit = PositionGetDouble(POSITION_PROFIT);
if(profit > 0)
{
ArrayResize(tickets, count + 1);
tickets[count] = ticket;
count++;
}
}
}
// 批量平仓所有盈利单
for(int i = 0; i < count; i++)
{
trade.PositionClose(tickets[i]);
}
}
//±-----------------------------------------------------------------+
//| 平亏损单(批量优化) |
//±-----------------------------------------------------------------+
void CloseLossPositions()
{
// 收集所有亏损仓位的ticket
ulong tickets[];
int count = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == _Symbol)
{
double profit = PositionGetDouble(POSITION_PROFIT);
if(profit < 0)
{
ArrayResize(tickets, count + 1);
tickets[count] = ticket;
count++;
}
}
}
// 批量平仓所有亏损单
for(int i = 0; i < count; i++)
{
trade.PositionClose(tickets[i]);
}
}
//±-----------------------------------------------------------------+
//| 按类型和平仓条件关闭订单(批量优化) |
//±-----------------------------------------------------------------+
void ClosePositionsByTypeAndProfit(ENUM_POSITION_TYPE type, bool closeProfit)
{
// 收集符合条件的ticket
ulong tickets[];
int count = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0 &&
PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_TYPE) == type)
{
double profit = PositionGetDouble(POSITION_PROFIT);
if((closeProfit && profit > 0) || (!closeProfit && profit < 0))
{
ArrayResize(tickets, count + 1);
tickets[count] = ticket;
count++;
}
}
}
// 批量平仓
for(int i = 0; i < count; i++)
{
trade.PositionClose(tickets[i]);
}
}
//±-----------------------------------------------------------------+
//| EA终止函数 |
//±-----------------------------------------------------------------+
void OnDeinit(const int reason)
{
// 删除所有图形对象
ObjectsDeleteAll(0, -1, OBJ_BUTTON);
ObjectsDeleteAll(0, -1, OBJ_LABEL);
ObjectsDeleteAll(0, -1, OBJ_EDIT);
}
以上代码中,加仓限制取消,改为无限加仓模式。按照设定的加仓间距,加仓根据资金状况而定,只要资金足够,就连续无限加仓