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

MQL4(59):采用函数化设计的EA交易程序

本节展示的EA交易程序是基于之前介绍的函数化编程理念构建的。在此基础上,我们进一步集成了“一键平掉所有订单”功能和追踪止损机制,以及“每根K线仅执行一次交易逻辑”的特性。 EA核心交易所依赖的各类函数均在名为 IncludeExample.mqh 的包含文件中给自定义了,该文件的具体源码内容会在下一篇文章里附上。

这段代码的逻辑以及健壮性可能没那么完美,更多的意义是展示如何引用包含文件来开发EA程序,仅作为教学演示,距离实盘运行还有一段距离。
// ===== 预处理指令 =====
#property copyright "tudaojiaoyi" // 版权声明
#include <IncludeExample.mqh>      // 引入包含自定义函数的头文件

// ===== 外部输入参数 =====
extern bool   DynamicLotSize    = true;   // 是否启用动态手数计算 (true/false)
extern double EquityPercent     = 2;      // 动态手数:基于账户净值的百分比 (例如 2% 的风险)
extern double FixedLotSize      = 0.1;    // 固定手数:若不启用动态手数,则使用此设定值
extern double StopLoss          = 50;     // 止损距离 (单位:点)
extern double TakeProfit        = 100;    // 止盈距离 (单位:点)
extern int    TrailingStop      = 50;     // 追踪止损激活距离 (单位:点)
extern int    MinimumProfit     = 50;     // 启动追踪止损所需的最小盈利 (单位:点)
extern int    Slippage          = 5;      // 允许的滑点大小
extern int    MagicNumber       = 123;    // EA的魔术数字,用于区分不同EA的订单
extern int    FastMAPeriod      = 10;     // 快速移动平均线的周期
extern int    SlowMAPeriod      = 20;     // 慢速移动平均线的周期
extern bool   CheckOncePerBar   = true;   // 是否设置为每根K线只执行一次主要交易逻辑

// ===== 全局变量 =====
int      BuyTicket;         // 用于存储当前买单的订单号
int      SellTicket;        // 用于存储当前卖单的订单号
double   UsePoint;          // 当前交易品种1个标准点的价格小数 (例如0.0001)
int      UseSlippage;       // 根据品种调整后的滑点值
datetime CurrentTimeStamp;  // 用于记录上一K线的时间戳,实现“每K线一次”逻辑

// ===== 初始化函数 (EA加载时执行一次) =====
int OnInit()
{
    // 假设 PipPoint 和 GetSlippage 函数已在 IncludeExample.mqh 中定义
    UsePoint = PipPoint(Symbol());           // 获取并存储当前品种的点值
    UseSlippage = GetSlippage(Symbol(), Slippage); // 获取并存储调整后的滑点
    return(0); // 返回0表示初始化成功
}

// ===== 主体逻辑函数 (每个报价tick执行一次) =====
void OnTick()
{
    bool NewBar;   // 标记是否为新K线
    int  BarShift; // K线偏移量 (0代表当前K线,1代表前一根K线)

    // --- 实现“每K线仅执行一次”的逻辑 ---
    if(CheckOncePerBar == true) // 如果启用了此功能
    {
        BarShift = 1; // 交易信号和计算将基于已经形成的上一根K线
        if(CurrentTimeStamp != Time[0]) // 如果当前时间戳与记录的不符 (Time[0]是当前K线开盘时间)
        {
            CurrentTimeStamp = Time[0]; // 更新时间戳
            NewBar = true;             // 标记为新K线形成,可以执行交易逻辑
        }
        else
        {
            NewBar = false;            // 仍是同一根K线,不执行交易逻辑
        }
    }
    else // 如果未启用“每K线一次”,则每次报价都执行
    {
        NewBar = true;
        BarShift = 0; // 基于当前实时数据进行计算
    }

    // --- 计算移动平均线 ---
    double FastMA     = iMA(NULL, 0, FastMAPeriod, 0, 0, 0, BarShift);     // 当前(或上一)K线的快速MA值
    double SlowMA     = iMA(NULL, 0, SlowMAPeriod, 0, 0, 0, BarShift);     // 当前(或上一)K线的慢速MA值
    double LastFastMA = iMA(NULL, 0, FastMAPeriod, 0, 0, 0, BarShift + 1); // 更前一根K线的快速MA值 (用于判断穿越)
    double LastSlowMA = iMA(NULL, 0, SlowMAPeriod, 0, 0, 0, BarShift + 1); // 更前一根K线的慢速MA值

    // --- 计算交易手数 ---
    // CalcLotSize 和 VerifyLotSize 函数应在 IncludeExample.mqh 中定义
    double LotSize = CalcLotSize(DynamicLotSize, EquityPercent, StopLoss, FixedLotSize);
    LotSize = VerifyLotSize(LotSize); // 验证并规范化手数

    // --- 主要交易逻辑块 (仅在新K线形成时执行) ---
    if(NewBar == true)
    { 
        // -- 买入信号判断与执行 --
        // 条件: 快速MA上穿慢速MA (金叉),且当前没有本EA的市价买单
        if(FastMA > SlowMA && LastFastMA <= LastSlowMA &&
           BuyMarketCount(Symbol(), MagicNumber) == 0) // BuyMarketCount 函数来自包含文件
        {
            // 如果存在反向的市价卖单,则先平仓
            if(SellMarketCount(Symbol(), MagicNumber) > 0) // SellMarketCount 函数来自包含文件
            { 
                CloseAllSellOrders(Symbol(), MagicNumber, UseSlippage); // CloseAllSellOrders 函数来自包含文件
            }
            // 开立新的买入市价单
            BuyTicket = OpenBuyOrder(Symbol(), LotSize, UseSlippage, MagicNumber); // OpenBuyOrder 函数来自包含文件

            // 如果订单成功开立,并且设置了止损或止盈,则修改订单添加它们
            if(BuyTicket > 0 && (StopLoss > 0 || TakeProfit > 0))
            {
                if(OrderSelect(BuyTicket, SELECT_BY_TICKET)) // 选中刚开立的订单
                {
                    double OpenPrice = OrderOpenPrice();
                    // 计算止损价和止盈价 (相关函数来自包含文件)
                    double BuyStopLoss   = CalcBuyStopLoss(Symbol(), StopLoss, OpenPrice);
                    if(BuyStopLoss > 0) BuyStopLoss = AdjustBelowStopLevel(Symbol(), BuyStopLoss, 5); // 调整以避开最小止损点位

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

                    // 为订单添加止损和止盈 (AddStopProfit 函数来自包含文件)
                    AddStopProfit(BuyTicket, BuyStopLoss, BuyTakeProfit);
                }
            } 
        }

        // -- 卖出信号判断与执行 --
        // 条件: 快速MA下穿慢速MA (死叉),且当前没有本EA的市价卖单
        if(FastMA < SlowMA && LastFastMA >= LastSlowMA && 
           SellMarketCount(Symbol(), MagicNumber) == 0)
        {
            // 如果存在反向的市价买单,则先平仓
            if(BuyMarketCount(Symbol(), MagicNumber) > 0)
            { 
                CloseAllBuyOrders(Symbol(), MagicNumber, UseSlippage); // CloseAllBuyOrders 函数来自包含文件
            }
            // 开立新的卖出市价单
            SellTicket = OpenSellOrder(Symbol(), LotSize, UseSlippage, MagicNumber); // OpenSellOrder 函数来自包含文件

            // 如果订单成功开立,并且设置了止损或止盈
            if(SellTicket > 0 && (StopLoss > 0 || TakeProfit > 0)) 
            {
                if(OrderSelect(SellTicket, SELECT_BY_TICKET))
                {
                    double SellOpenPrice = OrderOpenPrice();
                    double SellStopLoss   = CalcSellStopLoss(Symbol(), StopLoss, SellOpenPrice);
                    if(SellStopLoss > 0) SellStopLoss = AdjustAboveStopLevel(Symbol(), SellStopLoss, 5);

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

                    AddStopProfit(SellTicket, SellStopLoss, SellTakeProfit);
                }
            } 
        }
    } // --- 结束交易逻辑块 ---

    // --- 追踪止损逻辑 (每次tick都可能执行) ---
    // BuyTrailingStop 和 SellTrailingStop 函数应在 IncludeExample.mqh 中定义
    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(59):采用函数化设计的EA交易程序
分享到