保持敬畏之心
交易是一场持久战

MQL4(60):采用函数化设计并用挂单策略的EA程序

本节展示的EA交易程序同样基于函数化设计,但采用的是挂单方式进行交易。

功能上新增动态手数计算、追踪止损、每K线执行一次控制等功能等。
// ===== 预处理指令 =====
#property copyright "Andrew Young"
#include <IncludeExample.mqh>

// ===== 外部输入参数 =====
extern bool   DynamicLotSize  = true;
extern double EquityPercent   = 2;
extern double FixedLotSize    = 0.1;
extern double StopLoss        = 50;
extern double TakeProfit      = 100;
extern int    TrailingStop    = 50;
extern int    MinimumProfit   = 50;
extern int    PendingPips     = 1;      // 挂单距离当前价格的点数 (例如,距离High/Low 1个点)
extern int    Slippage        = 5;
extern int    MagicNumber     = 123;
extern int    FastMAPeriod    = 10;
extern int    SlowMAPeriod    = 20;
extern bool   CheckOncePerBar = true;

// ===== 全局变量 =====
int      BuyTicket;
int      SellTicket;
double   UsePoint;
int      UseSlippage;
datetime CurrentTimeStamp;

// ===== 初始化函数 =====
int OnInit()
{
    UsePoint = PipPoint(Symbol());
    UseSlippage = GetSlippage(Symbol(), Slippage);
    CurrentTimeStamp = Time[0]; // 初始化时间戳,用于“每K线一次”逻辑
    return(0);
}

// ===== 主体逻辑函数 =====
void OnTick()
{
    bool NewBar;
    int  BarShift;

    // --- 实现“每K线仅执行一次”的逻辑 ---
    if(CheckOncePerBar == true)
    {
        BarShift = 1;
        if(CurrentTimeStamp != Time[0]) 
        {
            CurrentTimeStamp = Time[0];
            NewBar = true;
        }
        else
        {
            NewBar = false;
        }
    }
    else 
    {
        NewBar = true;
        BarShift = 0;
    }

    // --- 计算移动平均线 ---
    double FastMA = iMA(NULL, 0, FastMAPeriod, 0, 0, 0, BarShift);
    double SlowMA = iMA(NULL, 0, SlowMAPeriod, 0, 0, 0, BarShift);
    // 注意:此挂单版本示例中,没有使用LastFastMA/LastSlowMA进行穿越确认,
    // 而是直接用当前(或上一K线)的MA状态,并结合检查现有订单数量。

    // --- 计算交易手数 ---
    double LotSize = CalcLotSize(DynamicLotSize, EquityPercent, StopLoss, FixedLotSize);
    LotSize = VerifyLotSize(LotSize);

    // --- 主要交易逻辑块 (仅在新K线形成时执行) ---
    if(NewBar == true)
    {
        // -- 买入挂单信号判断与执行 --
        // 条件: MA金叉,且当前无本EA的买单、市价买单或买入挂单
        if(FastMA > SlowMA && BuyTicket == 0 && BuyMarketCount(Symbol(), MagicNumber) == 0 && 
           BuyStopCount(Symbol(), MagicNumber) == 0) // BuyStopCount 函数来自包含文件
        {
            // 如果存在反向的市价卖单,则先平仓
            if(SellMarketCount(Symbol(), MagicNumber) > 0)
            { 
                CloseAllSellOrders(Symbol(), MagicNumber, UseSlippage);
            }
            // 如果存在反向的卖出挂单,则先删除
            if(SellStopCount(Symbol(), MagicNumber) > 0) // SellStopCount 函数来自包含文件
            {
                CloseAllSellStopOrders(Symbol(), MagicNumber); // CloseAllSellStopOrders 函数来自包含文件
            }
            SellTicket = 0; // 重置卖单追踪号

            // 计算并调整挂单价格
            double PendingPrice = High[BarShift] + (PendingPips * UsePoint); // 挂单价设置在上一K线最高点之上
            PendingPrice = AdjustAboveStopLevel(Symbol(), PendingPrice, 5); // 调整以避开最小止损点位

            // 计算止损价和止盈价 (基于挂单价格)
            double BuyStopLoss   = CalcBuyStopLoss(Symbol(), StopLoss, PendingPrice);
            // Adjust... 函数的第三个参数 (min_dist_pips) 和第四个参数 (base_price_for_adjust) 需要与包含文件中的定义匹配
            if(BuyStopLoss > 0) BuyStopLoss = AdjustBelowStopLevel(Symbol(), BuyStopLoss, 5, PendingPrice);

            double BuyTakeProfit = CalcBuyTakeProfit(Symbol(), TakeProfit, PendingPrice);
            if(BuyTakeProfit > 0) BuyTakeProfit = AdjustAboveStopLevel(Symbol(), BuyTakeProfit, 5, PendingPrice);

            // 开立新的买入停止单 (Buy Stop Order)
            BuyTicket = OpenBuyStopOrder(Symbol(), LotSize, PendingPrice, BuyStopLoss,
                                          BuyTakeProfit, UseSlippage, MagicNumber); // OpenBuyStopOrder 函数来自包含文件
        }

        // -- 卖出挂单信号判断与执行 --
        // 条件: MA死叉,且当前无本EA的卖单、市价卖单或卖出挂单
        if(FastMA < SlowMA && SellTicket == 0 && 
           SellMarketCount(Symbol(), MagicNumber) == 0 && 
           SellStopCount(Symbol(), MagicNumber) == 0)
        {
            // 如果存在反向的市价买单,则先平仓
            if(BuyMarketCount(Symbol(), MagicNumber) > 0)
            { 
                CloseAllBuyOrders(Symbol(), MagicNumber, UseSlippage);
            }
            // 如果存在反向的买入挂单,则先删除
            if(BuyStopCount(Symbol(), MagicNumber) > 0)
            {
                CloseAllBuyStopOrders(Symbol(), MagicNumber);
            }
            BuyTicket = 0; // 重置买单追踪号

            // 计算并调整挂单价格
            double SellPendingPrice = Low[BarShift] - (PendingPips * UsePoint); // 挂单价设置在上一K线最低点之下
            SellPendingPrice = AdjustBelowStopLevel(Symbol(), SellPendingPrice, 5);

            // 计算止损价和止盈价
            double SellStopLoss   = CalcSellStopLoss(Symbol(), StopLoss, SellPendingPrice);
            if(SellStopLoss > 0) SellStopLoss = AdjustAboveStopLevel(Symbol(), SellStopLoss, 5, SellPendingPrice);

            double SellTakeProfit = CalcSellTakeProfit(Symbol(), TakeProfit, SellPendingPrice);
            if(SellTakeProfit > 0) SellTakeProfit = AdjustBelowStopLevel(Symbol(), SellTakeProfit, 5, SellPendingPrice); 

            // 开立新的卖出停止单 (Sell Stop Order)
            SellTicket = OpenSellStopOrder(Symbol(), LotSize, SellPendingPrice, SellStopLoss,
                                            SellTakeProfit, UseSlippage, MagicNumber);
        }
    } // --- 结束交易逻辑块 ---

    // --- 追踪止损逻辑 (仅对已成交的市价单生效) ---
    if(BuyMarketCount(Symbol(), MagicNumber) > 0 && TrailingStop > 0)
    {
        BuyTrailingStop(Symbol(), TrailingStop, MinimumProfit, MagicNumber);
    }
    if(SellMarketCount(Symbol(), MagicNumber) > 0 && TrailingStop > 0)
    {
        SellTrailingStop(Symbol(), TrailingStop, MinimumProfit, MagicNumber);
    }
}
赞(0)
未经允许不得转载:图道交易 » MQL4(60):采用函数化设计并用挂单策略的EA程序
分享到