欢迎访问 外汇EA下载与MT4/MT5自动交易资源 - 聚合外汇EA、黄金EA、量化交易工具与自动化交易实战内容。
登录 注册

MT4虚拟马丁策略EA 只交易特定的层数

author emer | 932 人阅读 | 0 人评论 |

马丁格尔策略本质上是一种逆势加仓的交易方法,与趋势交易原则相违背。尽管该策略最终必然面临爆仓风险,但许多交易者(包括我在内)尝试通过各种方法来延缓爆仓的发生。其中最常见的是采用跟单机制来实施马丁策略,具体包括:

仅在浮亏时跟单马丁加仓

缩小倍数

设置加仓层数限制等

通过数据分析,我们发现马丁策略的前几层仓位从长期来看始终呈现亏损状态。举例说明:假设一个马丁策略按照以下6个层级加仓:

1层:0.01手

2层:0.02手

3层:0.03手

4层:0.04手

5层:0.05手

6层:0.06手

观察发现,无论最终是在第2层、第3层还是第6层平仓获利,首层的0.01手仓位始终处于亏损状态。基于这个统计,我们在跟单操作中采取了过滤首层仓位的优化方案,即不跟单0.01手的初始仓位。这样调整后,跟单账户避免了首层仓位的系统性亏损,反而比信号源账户获得了更好的收益表现。

本ea就解决这个问题,虚拟下单,然后通过参数设置,实际下单层数。

这种优化方法的本质是通过剔除统计上确定亏损的仓位层级,来改善马丁策略的整体风险收益比。

核心架构

采用双轨制仓位管理系统:

虚拟仓位:模拟马丁加仓策略,作为信号发生器

实际仓位:仅在特定虚拟层级执行真实交易

完整参数列表

基础参数

参数名类型说明
MagicNumberintEA唯一标识符
TradeDirectionenum交易方向(BUY_ONLY/SELL_ONLY/BOTH)

虚拟仓位参数

参数名类型默认值说明
BaseLotSizedouble0.01初始手数设置
VirtualLotMultiplierdouble1.06虚拟加仓倍数
VirtualStepPointsint100加仓间隔(点)
MaxVirtualLevelsint100最大加仓次数
VirtualTakeProfitint500虚拟整体盈利点数(0表示不设止盈)
VirtualStopLossint500虚拟整体止损点数(0表示不设止损)

实际仓位参数

参数名类型默认值说明
ActualTradeLevel1int1// 实际开仓层级1(0=禁用)
ActualTradeLevel2int3// 实际开仓层级2(0=禁用)
ActualTradeLevel3int5// 实际开仓层级3(0=禁用)
ActualTradeLevel4int0// 实际开仓层级4(0=禁用)
FollowVirtualTPbooltrue跟随虚拟止盈
FollowVirtualSLbooltrue跟随虚拟止损
ActualTotalTPint500实际整体盈利点数(0=禁用)
ActualTotalSLint500实际整体止损点数(0=禁用)

移动止损参数

参数名类型默认值说明
UseTrailingStopbooltrue启用移动止损
TrailingStartPointsint200启动移动止损的盈利点数
TrailingStepPointsint50移动步长(点)
TrailingStopPointsint100止损距离(点)

工作流程

虚拟仓位引擎

持续监控价格变动

在图表上显示虚拟订单

按马丁策略规则计算虚拟加仓

维护虚拟仓位状态和盈亏

实际交易触发:

当虚拟仓位达到用户预设的层级(如3/5/7层)时

执行真实交易开仓

风险控制:

独立计算虚拟和实际仓位的整体盈亏

支持固定止盈止损和移动止损

达到任一平仓条件时全部平仓

移动止损:

盈利达标后激活

按设定步长和距离跟踪价格

只向有利方向移动

初步代码

//+------------------------------------------------------------------+
//| Virtual Martingale EA                                           |
//| 虚拟马丁策略EA                                                  |
//+------------------------------------------------------------------+
#property copyright "Virtual Martingale Strategy"
#property version   "1.00"
#property strict

//+------------------------------------------------------------------+
//| 枚举定义                                                        |
//+------------------------------------------------------------------+
enum ENUM_TRADE_DIRECTION
{
    BUY_ONLY,     // 仅买入
    SELL_ONLY,    // 仅卖出
    BOTH          // 双向交易
};

//+------------------------------------------------------------------+
//| 输入参数                                                        |
//+------------------------------------------------------------------+
// 基础参数
input int MagicNumber = 888888;                    // EA唯一标识符
input ENUM_TRADE_DIRECTION TradeDirection = BOTH;  // 交易方向

// 虚拟仓位参数
input double BaseLotSize = 0.01;                   // 初始手数
input double VirtualLotMultiplier = 1.06;          // 虚拟加仓倍数
input int VirtualStepPoints = 100;                 // 加仓间隔(点)
input int MaxVirtualLevels = 100;                  // 最大加仓次数
input int VirtualTakeProfit = 500;                 // 虚拟整体盈利点数
input int VirtualStopLoss = 500;                   // 虚拟整体止损点数

// 实际仓位参数
input int ActualTradeLevel1 = 1;                   // 实际开仓层级1(0=禁用)
input int ActualTradeLevel2 = 3;                   // 实际开仓层级2(0=禁用)
input int ActualTradeLevel3 = 5;                   // 实际开仓层级3(0=禁用)
input int ActualTradeLevel4 = 0;                   // 实际开仓层级4(0=禁用)
input bool FollowVirtualTP = true;                 // 跟随虚拟止盈
input bool FollowVirtualSL = true;                 // 跟随虚拟止损
input int ActualTotalTP = 500;                     // 实际整体盈利点数(0=禁用)
input int ActualTotalSL = 500;                     // 实际整体止损点数(0=禁用)

// 移动止损参数
input bool UseTrailingStop = true;                // 启用移动止损
input int TrailingStartPoints = 200;              // 启动移动止损的盈利点数
input int TrailingStepPoints = 50;                // 移动步长(点)
input int TrailingStopPoints = 100;               // 止损距离(点)

// 显示参数
input bool ShowInfoPanel = true;                   // 显示信息面板
input int InfoPanelX = 20;                        // 信息面板X坐标
input int InfoPanelY = 30;                        // 信息面板Y坐标

//+------------------------------------------------------------------+
//| 虚拟订单结构                                                    |
//+------------------------------------------------------------------+
struct VirtualOrder
{
    int level;              // 层级
    int type;               // 订单类型 (OP_BUY/OP_SELL)
    double lots;            // 手数
    double openPrice;       // 开仓价格
    double profit;          // 当前盈亏
    datetime openTime;      // 开仓时间
    bool isActive;          // 是否激活
};

//+------------------------------------------------------------------+
//| 全局变量                                                        |
//+------------------------------------------------------------------+
// 虚拟仓位相关
VirtualOrder virtualOrders[100];    // 虚拟订单数组
int virtualOrderCount = 0;          // 虚拟订单数量
double virtualTotalProfit = 0;      // 虚拟总盈亏
double virtualWeightedAvgPrice = 0; // 虚拟持仓均价
double virtualTotalLots = 0;        // 虚拟总手数
bool virtualPositionActive = false; // 虚拟仓位状态
int currentVirtualLevel = 0;        // 当前虚拟层级
double lastVirtualPrice = 0;        // 上次虚拟开仓价格
int virtualDirection = 0;           // 虚拟仓位方向 (1=买入, -1=卖出)

// 实际交易相关
int actualTradeCount = 0;           // 实际交易数量
double actualTotalProfit = 0;       // 实际总盈亏
double trailingStopLevel = 0;       // 移动止损水平
bool trailingActive = false;        // 移动止损激活状态

// 触发标志
bool level1Triggered = false;      // 层级1触发标志
bool level2Triggered = false;      // 层级2触发标志
bool level3Triggered = false;      // 层级3触发标志
bool level4Triggered = false;      // 层级4触发标志

// 其他
datetime lastTickTime = 0;         // 上次tick时间
string panelObjectName = "VirtualMartingalePanel"; // 面板对象名

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    Print("虚拟马丁策略EA启动");

    // 初始化虚拟订单数组
    for(int i = 0; i < 100; i++)
    {
        virtualOrders[i].isActive = false;
        virtualOrders[i].level = 0;
        virtualOrders[i].lots = 0;
        virtualOrders[i].openPrice = 0;
        virtualOrders[i].profit = 0;
        virtualOrders[i].type = -1;
        virtualOrders[i].openTime = 0;
    }

    // 参数验证
    if(BaseLotSize <= 0)
    {
        Print("错误:基础手数必须大于0");
        return(INIT_PARAMETERS_INCORRECT);
    }

    if(VirtualLotMultiplier <= 1)
    {
        Print("错误:虚拟加仓倍数必须大于1");
        return(INIT_PARAMETERS_INCORRECT);
    }

    if(VirtualStepPoints <= 0)
    {
        Print("错误:加仓间隔必须大于0");
        return(INIT_PARAMETERS_INCORRECT);
    }

    if(MaxVirtualLevels <= 0)
    {
        Print("错误:最大加仓次数必须大于0");
        return(INIT_PARAMETERS_INCORRECT);
    }

    // 初始化变量
    virtualOrderCount = 0;
    virtualTotalProfit = 0;
    virtualWeightedAvgPrice = 0;
    virtualTotalLots = 0;
    virtualPositionActive = false;
    currentVirtualLevel = 0;
    lastVirtualPrice = 0;
    virtualDirection = 0;
    actualTradeCount = 0;
    actualTotalProfit = 0;
    trailingStopLevel = 0;
    trailingActive = false;

    // 重置触发标志
    level1Triggered = false;
    level2Triggered = false;
    level3Triggered = false;
    level4Triggered = false;

    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    Print("虚拟马丁策略EA停止,原因:", reason);

    // 删除图表对象
    if(ObjectFind(panelObjectName) >= 0)
    {
        ObjectDelete(panelObjectName);
    }

    // 清理资源
    Comment("");
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // 更新虚拟仓位状态
    UpdateVirtualPositions();

    // 检查虚拟仓位开仓条件
    CheckVirtualEntry();

    // 检查实际交易开仓条件
    CheckActualTradeEntry();

    // 检查平仓条件
    CheckCloseConditions();

    // 更新移动止损
    if(UseTrailingStop)
        UpdateTrailingStop();

    // 显示信息面板
    if(ShowInfoPanel)
        ShowInfoPanel();

    lastTickTime = TimeCurrent();
}

//+------------------------------------------------------------------+
//| 更新虚拟仓位状态                                                 |
//+------------------------------------------------------------------+
void UpdateVirtualPositions()
{
    virtualTotalProfit = 0;
    virtualTotalLots = 0;
    virtualWeightedAvgPrice = 0;
    double totalValue = 0;

    for(int i = 0; i < virtualOrderCount; i++)
    {
        if(virtualOrders[i].isActive)
        {
            double currentPrice = (virtualOrders[i].type == OP_BUY) ? Bid : Ask;
            double pointValue = MarketInfo(Symbol(), MODE_TICKVALUE);

            if(virtualOrders[i].type == OP_BUY)
            {
                virtualOrders[i].profit = (currentPrice - virtualOrders[i].openPrice) * virtualOrders[i].lots * pointValue / Point;
            }
            else
            {
                virtualOrders[i].profit = (virtualOrders[i].openPrice - currentPrice) * virtualOrders[i].lots * pointValue / Point;
            }

            virtualTotalProfit += virtualOrders[i].profit;
            virtualTotalLots += virtualOrders[i].lots;
            totalValue += virtualOrders[i].openPrice * virtualOrders[i].lots;
        }
    }

    if(virtualTotalLots > 0)
    {
        virtualWeightedAvgPrice = totalValue / virtualTotalLots;
        virtualPositionActive = true;
    }
    else
    {
        virtualPositionActive = false;
    }
}

//+------------------------------------------------------------------+
//| 检查虚拟仓位开仓条件                                             |
//+------------------------------------------------------------------+
void CheckVirtualEntry()
{
    if(!virtualPositionActive)
    {
        // 首次开仓
        if(TradeDirection == BUY_ONLY || TradeDirection == BOTH)
        {
            OpenVirtualOrder(OP_BUY, BaseLotSize, Ask, 1);
        }
        else if(TradeDirection == SELL_ONLY)
        {
            OpenVirtualOrder(OP_SELL, BaseLotSize, Bid, 1);
        }
    }
    else
    {
        // 检查加仓条件
        if(currentVirtualLevel < MaxVirtualLevels)
        {
            double currentPrice = (virtualDirection == 1) ? Bid : Ask;
            double priceDiff = MathAbs(currentPrice - lastVirtualPrice);

            if(priceDiff >= VirtualStepPoints * Point)
            {
                // 计算下一层级手数
                double nextLotSize = BaseLotSize * MathPow(VirtualLotMultiplier, currentVirtualLevel);

                // 确保不超过最大手数限制
                double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
                double minLot = MarketInfo(Symbol(), MODE_MINLOT);
                double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);

                if(nextLotSize > maxLot)
                    nextLotSize = maxLot;
                if(nextLotSize < minLot)
                    nextLotSize = minLot;

                // 规范化手数
                nextLotSize = NormalizeDouble(nextLotSize / lotStep, 0) * lotStep;

                // 开设虚拟加仓订单
                int orderType = (virtualDirection == 1) ? OP_BUY : OP_SELL;
                double orderPrice = (virtualDirection == 1) ? Ask : Bid;

                OpenVirtualOrder(orderType, nextLotSize, orderPrice, currentVirtualLevel + 1);
            }
        }
    }
}

//+------------------------------------------------------------------+
//| 开设虚拟订单                                                     |
//+------------------------------------------------------------------+
void OpenVirtualOrder(int type, double lots, double price, int level)
{
    if(virtualOrderCount >= 100)
    {
        Print("警告:虚拟订单数量已达上限");
        return;
    }

    virtualOrders[virtualOrderCount].level = level;
    virtualOrders[virtualOrderCount].type = type;
    virtualOrders[virtualOrderCount].lots = lots;
    virtualOrders[virtualOrderCount].openPrice = price;
    virtualOrders[virtualOrderCount].profit = 0;
    virtualOrders[virtualOrderCount].openTime = TimeCurrent();
    virtualOrders[virtualOrderCount].isActive = true;

    virtualOrderCount++;
    currentVirtualLevel = level;
    lastVirtualPrice = price;
    virtualDirection = (type == OP_BUY) ? 1 : -1;

    Print("虚拟订单开仓:层级", level, " 类型", (type == OP_BUY ? "买入" : "卖出"), 
          " 手数", DoubleToStr(lots, 2), " 价格", DoubleToStr(price, Digits));
}

//+------------------------------------------------------------------+
//| 检查实际交易开仓条件                                             |
//+------------------------------------------------------------------+
void CheckActualTradeEntry()
{
    if(!virtualPositionActive)
        return;

    // 检查层级1
    if(ActualTradeLevel1 > 0 && currentVirtualLevel >= ActualTradeLevel1 && !level1Triggered)
    {
        ExecuteActualTrade("Level1");
        level1Triggered = true;
    }

    // 检查层级2
    if(ActualTradeLevel2 > 0 && currentVirtualLevel >= ActualTradeLevel2 && !level2Triggered)
    {
        ExecuteActualTrade("Level2");
        level2Triggered = true;
    }

    // 检查层级3
    if(ActualTradeLevel3 > 0 && currentVirtualLevel >= ActualTradeLevel3 && !level3Triggered)
    {
        ExecuteActualTrade("Level3");
        level3Triggered = true;
    }

    // 检查层级4
    if(ActualTradeLevel4 > 0 && currentVirtualLevel >= ActualTradeLevel4 && !level4Triggered)
    {
        ExecuteActualTrade("Level4");
        level4Triggered = true;
    }
}

//+------------------------------------------------------------------+
//| 执行实际交易                                                     |
//+------------------------------------------------------------------+
void ExecuteActualTrade(string levelName)
{
    // 计算实际开仓手数
    double actualLots = BaseLotSize;

    // 规范化手数
    double minLot = MarketInfo(Symbol(), MODE_MINLOT);
    double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
    double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);

    if(actualLots < minLot)
        actualLots = minLot;
    if(actualLots > maxLot)
        actualLots = maxLot;

    actualLots = NormalizeDouble(actualLots / lotStep, 0) * lotStep;

    // 执行实际交易
    int orderType = (virtualDirection == 1) ? OP_BUY : OP_SELL;
    double orderPrice = (virtualDirection == 1) ? Ask : Bid;
    int slippage = 3;

    string comment = "VM_" + levelName + "_" + IntegerToString(currentVirtualLevel);

    int ticket = OrderSend(Symbol(), orderType, actualLots, orderPrice, slippage, 0, 0, 
                          comment, MagicNumber, 0, clrBlue);

    if(ticket > 0)
    {
        actualTradeCount++;
        Print("实际交易开仓:票据", ticket, " 层级", levelName, " 虚拟层级", currentVirtualLevel, 
              " 类型", (orderType == OP_BUY ? "买入" : "卖出"), 
              " 手数", DoubleToStr(actualLots, 2), " 价格", DoubleToStr(orderPrice, Digits));
    }
    else
    {
        int error = GetLastError();
        Print("实际交易开仓失败:", error, " 描述:", ErrorDescription(error));
    }
}

//+------------------------------------------------------------------+
//| 检查是否存在实际交易                                             |
//+------------------------------------------------------------------+
bool IsActualTradeOpen()
{
    for(int i = 0; i < OrdersTotal(); i++)
    {
        if(OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == Symbol() && 
           OrderMagicNumber() == MagicNumber)
        {
            return(true);
        }
    }
    return(false);
}

//+------------------------------------------------------------------+
//| 计算实际交易总盈亏                                               |
//+------------------------------------------------------------------+
double GetActualTotalProfit()
{
    double totalProfit = 0;

    for(int i = 0; i < OrdersTotal(); i++)
    {
        if(OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == Symbol() && 
           OrderMagicNumber() == MagicNumber)
        {
            totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
        }
    }

    return(totalProfit);
}

//+------------------------------------------------------------------+
//| 检查平仓条件                                                     |
//+------------------------------------------------------------------+
void CheckCloseConditions()
{
    if(!virtualPositionActive)
        return;

    actualTotalProfit = GetActualTotalProfit();

    bool shouldClose = false;
    string closeReason = "";

    // 检查虚拟止盈
    if(VirtualTakeProfit > 0)
    {
        double virtualTPValue = VirtualTakeProfit * Point * MarketInfo(Symbol(), MODE_TICKVALUE);
        if(virtualTotalProfit >= virtualTPValue)
        {
            shouldClose = true;
            closeReason = "虚拟止盈";
        }
    }

    // 检查虚拟止损
    if(VirtualStopLoss > 0)
    {
        double virtualSLValue = -VirtualStopLoss * Point * MarketInfo(Symbol(), MODE_TICKVALUE);
        if(virtualTotalProfit <= virtualSLValue)
        {
            shouldClose = true;
            closeReason = "虚拟止损";
        }
    }

    // 检查实际止盈
    if(ActualTotalTP > 0 && !FollowVirtualTP)
    {
        double actualTPValue = ActualTotalTP * Point * MarketInfo(Symbol(), MODE_TICKVALUE);
        if(actualTotalProfit >= actualTPValue)
        {
            shouldClose = true;
            closeReason = "实际止盈";
        }
    }

    // 检查实际止损
    if(ActualTotalSL > 0 && !FollowVirtualSL)
    {
        double actualSLValue = -ActualTotalSL * Point * MarketInfo(Symbol(), MODE_TICKVALUE);
        if(actualTotalProfit <= actualSLValue)
        {
            shouldClose = true;
            closeReason = "实际止损";
        }
    }

    if(shouldClose)
    {
        CloseAllPositions(closeReason);
    }
}

//+------------------------------------------------------------------+
//| 关闭所有仓位                                                     |
//+------------------------------------------------------------------+
void CloseAllPositions(string reason)
{
    Print("开始平仓:", reason);

    // 关闭所有实际交易
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == Symbol() && 
           OrderMagicNumber() == MagicNumber)
        {
            double closePrice = (OrderType() == OP_BUY) ? Bid : Ask;
            bool result = OrderClose(OrderTicket(), OrderLots(), closePrice, 3, clrRed);

            if(result)
            {
                Print("实际交易平仓:票据", OrderTicket(), " 盈亏", DoubleToStr(OrderProfit(), 2));
            }
            else
            {
                int error = GetLastError();
                Print("实际交易平仓失败:", error, " 描述:", ErrorDescription(error));
            }
        }
    }

    // 清除虚拟仓位
    ClearVirtualPositions();

    Print("平仓完成:", reason, " 虚拟盈亏", DoubleToStr(virtualTotalProfit, 2), 
          " 实际盈亏", DoubleToStr(actualTotalProfit, 2));
}

//+------------------------------------------------------------------+
//| 清除虚拟仓位                                                     |
//+------------------------------------------------------------------+
void ClearVirtualPositions()
{
    for(int i = 0; i < virtualOrderCount; i++)
    {
        virtualOrders[i].isActive = false;
        virtualOrders[i].level = 0;
        virtualOrders[i].lots = 0;
        virtualOrders[i].openPrice = 0;
        virtualOrders[i].profit = 0;
        virtualOrders[i].type = -1;
        virtualOrders[i].openTime = 0;
    }

    virtualOrderCount = 0;
    virtualTotalProfit = 0;
    virtualWeightedAvgPrice = 0;
    virtualTotalLots = 0;
    virtualPositionActive = false;
    currentVirtualLevel = 0;
    lastVirtualPrice = 0;
    virtualDirection = 0;
    actualTradeCount = 0;
    actualTotalProfit = 0;
    trailingStopLevel = 0;
    trailingActive = false;

    // 重置触发标志
    level1Triggered = false;
    level2Triggered = false;
    level3Triggered = false;
    level4Triggered = false;
}

//+------------------------------------------------------------------+
//| 更新移动止损                                                     |
//+------------------------------------------------------------------+
void UpdateTrailingStop()
{
    if(!virtualPositionActive || actualTradeCount == 0)
        return;

    double currentProfit = (FollowVirtualTP && FollowVirtualSL) ? virtualTotalProfit : actualTotalProfit;
    double startValue = TrailingStartPoints * Point * MarketInfo(Symbol(), MODE_TICKVALUE);

    // 检查是否达到启动移动止损的条件
    if(currentProfit >= startValue)
    {
        if(!trailingActive)
        {
            trailingActive = true;
            trailingStopLevel = currentProfit - TrailingStopPoints * Point * MarketInfo(Symbol(), MODE_TICKVALUE);
            Print("移动止损激活:当前盈利", DoubleToStr(currentProfit, 2), 
                  " 止损水平", DoubleToStr(trailingStopLevel, 2));
        }
        else
        {
            // 更新移动止损水平
            double newStopLevel = currentProfit - TrailingStopPoints * Point * MarketInfo(Symbol(), MODE_TICKVALUE);

            if(newStopLevel > trailingStopLevel + TrailingStepPoints * Point * MarketInfo(Symbol(), MODE_TICKVALUE))
            {
                trailingStopLevel = newStopLevel;
                Print("移动止损更新:新止损水平", DoubleToStr(trailingStopLevel, 2));
            }
        }

        // 检查是否触发移动止损
        if(currentProfit <= trailingStopLevel)
        {
            CloseAllPositions("移动止损触发");
        }
    }
}

//+------------------------------------------------------------------+
//| 显示信息面板                                                     |
//+------------------------------------------------------------------+
void ShowInfoPanel()
{
    string info = "";
    info += "==== 虚拟马丁策略EA ====\n";
    info += "交易品种:" + Symbol() + "\n";
    info += "账户余额:" + DoubleToStr(AccountBalance(), 2) + "\n";
    info += "账户净值:" + DoubleToStr(AccountEquity(), 2) + "\n";
    info += "------------------------\n";
    info += "虚拟仓位状态:" + (virtualPositionActive ? "激活" : "未激活") + "\n";
    info += "当前虚拟层级:" + IntegerToString(currentVirtualLevel) + "\n";
    info += "虚拟订单数量:" + IntegerToString(virtualOrderCount) + "\n";
    info += "虚拟总手数:" + DoubleToStr(virtualTotalLots, 2) + "\n";

    if(virtualPositionActive)
    {
        info += "虚拟均价:" + DoubleToStr(virtualWeightedAvgPrice, Digits) + "\n";
        info += "虚拟方向:" + (virtualDirection == 1 ? "买入" : "卖出") + "\n";
    }

    info += "虚拟总盈亏:" + DoubleToStr(virtualTotalProfit, 2) + "\n";
    info += "------------------------\n";
    info += "实际交易数量:" + IntegerToString(actualTradeCount) + "\n";
    info += "实际总盈亏:" + DoubleToStr(actualTotalProfit, 2) + "\n";
    info += "移动止损:" + (trailingActive ? "激活" : "未激活") + "\n";

    if(trailingActive)
    {
        info += "止损水平:" + DoubleToStr(trailingStopLevel, 2) + "\n";
    }

    info += "------------------------\n";
    info += "触发状态:\n";
    info += "Level1(" + IntegerToString(ActualTradeLevel1) + "):" + (level1Triggered ? "已触发" : "未触发") + "\n";
    info += "Level2(" + IntegerToString(ActualTradeLevel2) + "):" + (level2Triggered ? "已触发" : "未触发") + "\n";
    info += "Level3(" + IntegerToString(ActualTradeLevel3) + "):" + (level3Triggered ? "已触发" : "未触发") + "\n";
    info += "Level4(" + IntegerToString(ActualTradeLevel4) + "):" + (level4Triggered ? "已触发" : "未触发") + "\n";
    info += "------------------------\n";
    info += "最后更新:" + TimeToStr(TimeCurrent(), TIME_SECONDS) + "\n";

    Comment(info);
}

//+------------------------------------------------------------------+
//| 获取错误描述                                                     |
//+------------------------------------------------------------------+
string ErrorDescription(int error)
{
    switch(error)
    {
        case 0: return("无错误");
        case 1: return("无错误,但结果未知");
        case 2: return("一般错误");
        case 3: return("无效的参数");
        case 4: return("交易服务器繁忙");
        case 5: return("旧版本的客户端");
        case 6: return("没有连接到交易服务器");
        case 7: return("没有足够的权限");
        case 8: return("频繁的请求");
        case 9: return("不兼容的操作");
        case 64: return("账户被禁用");
        case 65: return("无效的账户");
        case 128: return("交易超时");
        case 129: return("无效的价格");
        case 130: return("无效的停止");
        case 131: return("无效的交易量");
        case 132: return("市场关闭");
        case 133: return("交易被禁用");
        case 134: return("没有足够的资金");
        case 135: return("价格改变");
        case 136: return("离线报价");
        case 137: return("经纪商繁忙");
        case 138: return("重新报价");
        case 139: return("订单被锁定");
        case 140: return("只允许买入");
        case 141: return("允许的订单数量已达上限");
        case 145: return("修改被禁用");
        case 146: return("上下文繁忙");
        case 147: return("到期时间被禁用");
        case 148: return("订单数量已达上限");
        default: return("未知错误 " + IntegerToString(error));
    }
}

//+------------------------------------------------------------------+
//| 计算点值                                                        |
//+------------------------------------------------------------------+
double GetPointValue()
{
    double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
    double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
    return(tickValue * Point / tickSize);
}

//+------------------------------------------------------------------+
//| 获取虚拟仓位详细信息                                             |
//+------------------------------------------------------------------+
string GetVirtualPositionDetails()
{
    string details = "";

    if(!virtualPositionActive)
    {
        return("无虚拟仓位");
    }

    details += "虚拟仓位详情:\n";
    details += "层级\t手数\t\t开仓价\t\t盈亏\n";

    for(int i = 0; i < virtualOrderCount; i++)
    {
        if(virtualOrders[i].isActive)
        {
            details += IntegerToString(virtualOrders[i].level) + "\t";
            details += DoubleToStr(virtualOrders[i].lots, 2) + "\t\t";
            details += DoubleToStr(virtualOrders[i].openPrice, Digits) + "\t\t";
            details += DoubleToStr(virtualOrders[i].profit, 2) + "\n";
        }
    }

    return(details);
}

//+------------------------------------------------------------------+
//| 重置EA状态                                                      |
//+------------------------------------------------------------------+
void ResetEAState()
{
    Print("重置EA状态");
    ClearVirtualPositions();
}

//+------------------------------------------------------------------+
//| 检查账户状态                                                     |
//+------------------------------------------------------------------+
bool CheckAccountStatus()
{
    if(!IsConnected())
    {
        Print("警告:与交易服务器连接中断");
        return(false);
    }

    if(!IsTradeAllowed())
    {
        Print("警告:交易被禁用");
        return(false);
    }

    if(AccountFreeMargin() < BaseLotSize * MarketInfo(Symbol(), MODE_MARGINREQUIRED))
    {
        Print("警告:可用保证金不足");
        return(false);
    }

    return(true);
}

//+------------------------------------------------------------------+
//| 程序结束                                                        |
//+------------------------------------------------------------------+
🔐
请登录后参与评论
注册满12小时后评论,即可解锁附件下载
立即登录