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

MQL4(55):基础版EA交易程序源码

MQL4系列教学结束了。

从这篇文章开始,我们温习下整个系列教学里EA开发的过程。从最简单的基础版EA源码到进阶版,来感受一下我是如何给一个EA添砖加瓦、完善其功能的。这款EA是否盈利不重要,它的作用是来给大家演示一个EA的成型过程。

#property copyright "tudaojiaoyi" // 版权声明

// ===== 外部输入参数 =====
extern double LotSize      = 0.1;  // 交易手数
extern double StopLoss     = 50;   // 止损点数 (50点)
extern double TakeProfit   = 100;  // 止盈点数 (100点)
extern int    Slippage     = 5;    // 允许滑点 (5个常规点)
extern int    MagicNumber  = 123;  // EA魔术数字 (订单标识)
extern int    FastMAPeriod = 10;   // 快速移动平均线周期
extern int    SlowMAPeriod = 20;   // 慢速移动平均线周期

// ===== 全局变量 =====
int    BuyTicket;     // 保存买单订单号
int    SellTicket;    // 保存卖单订单号
double UsePoint;      // 当前品种1个标准点的价格小数 (例如 0.0001)
int    UseSlippage;   // 根据当前品种调整后的滑点值

// ===== 初始化函数 (EA加载时执行一次) =====
int OnInit()
{
    // 获取当前交易品种的点值信息
    UsePoint = PipPoint(Symbol());
    // 根据当前交易品种的点位精度,调整滑点设置
    UseSlippage = GetSlippage(Symbol(), Slippage);
    return(INIT_SUCCEEDED); // 表示初始化成功
}

// ===== 主体逻辑函数 (每个报价tick执行一次) =====
void OnTick()
{
    // --- 计算移动平均线 ---
    // 计算快速MA当前值 (参数:品种,周期,MA周期,MA位移,MA方法,应用价格,柱索引)
    double FastMA = iMA(NULL, 0, FastMAPeriod, 0, 0, 0, 0); // 0=SMA, 0=PRICE_CLOSE, 0=当前柱
    // 计算慢速MA当前值
    double SlowMA = iMA(NULL, 0, SlowMAPeriod, 0, 0, 0, 0);

    // --- 买入条件判断与执行 ---
    if(FastMA > SlowMA && BuyTicket == 0) // 如果快速MA上穿慢速MA,并且当前没有持有的买单
    {
        // 尝试选择并关闭可能存在的反向卖单
        if(SellTicket > 0) // 检查是否有活动的卖单号
        {
            if(OrderSelect(SellTicket, SELECT_BY_TICKET)) // 选择该卖单
            {
                if(OrderCloseTime() == 0) // 确认订单是开仓状态 (平仓时间为0)
                {
                    double CloseLots  = OrderLots();  // 获取订单手数
                    double ClosePrice = Ask;          // 以当前卖价平掉空单
                    bool   Closed     = OrderClose(SellTicket, CloseLots, ClosePrice, UseSlippage, Red); // 执行平仓
                }
            }
        }

        // 准备开立新买单
        double OpenPrice     = Ask;    // 买单开仓价为当前卖方报价(Ask)
        double BuyStopLoss   = 0;      // 初始化买单止损价
        double BuyTakeProfit = 0;      // 初始化买单止盈价

        // 计算止损和止盈价格
        if(StopLoss > 0) // 如果设置了止损点数
        {
            BuyStopLoss = OpenPrice - (StopLoss * UsePoint); // 买单止损价 = 开仓价 - 止损点数对应价格
        }
        if(TakeProfit > 0) // 如果设置了止盈点数
        {
            BuyTakeProfit = OpenPrice + (TakeProfit * UsePoint); // 买单止盈价 = 开仓价 + 止盈点数对应价格
        }

        // 发送买入市价单
        BuyTicket = OrderSend(Symbol(), OP_BUY, LotSize, OpenPrice, UseSlippage,
                              BuyStopLoss, BuyTakeProfit, "Buy Order", MagicNumber, 0, Green);
        SellTicket = 0; // 重置卖单追踪号码,因为已建立买单或尝试建立买单
    }

    // --- 卖出条件判断与执行 ---
    if(FastMA < SlowMA && SellTicket == 0) // 如果快速MA下穿慢速MA,并且当前没有持有的卖单
    {
        // 尝试选择并关闭可能存在的反向买单
        if(BuyTicket > 0) // 检查是否有活动的买单号
        {
            if(OrderSelect(BuyTicket, SELECT_BY_TICKET)) // 选择该买单
            {
                if(OrderCloseTime() == 0) // 确认订单是开仓状态
                {
                    double SellCloseLots  = OrderLots();
                    double SellClosePrice = Bid;          // 以当前买价平掉多单
                    bool   SellClosed     = OrderClose(BuyTicket, SellCloseLots, SellClosePrice, UseSlippage, Red);
                }
            }
        }

        // 准备开立新卖单
        double SellOpenPrice      = Bid;    // 卖单开仓价为当前买方报价(Bid)
        double SellStopLoss   = 0;
        double SellTakeProfit = 0;

        // 计算止损和止盈价格
        if(StopLoss > 0)
        {
            SellStopLoss = SellOpenPrice + (StopLoss * UsePoint); // 卖单止损价 = 开仓价 + 止损点数对应价格
        }
        if(TakeProfit > 0)
        {
            SellTakeProfit = SellOpenPrice - (TakeProfit * UsePoint); // 卖单止盈价 = 开仓价 - 止盈点数对应价格
        }

        // 发送卖出市价单
        SellTicket = OrderSend(Symbol(), OP_SELL, LotSize, SellOpenPrice, UseSlippage,
                                SellStopLoss, SellTakeProfit, "Sell Order", MagicNumber, 0, Red);
        BuyTicket = 0; // 重置买单追踪号码
    }
}

// ===== 辅助函数:计算点值 =====
// 根据货币对的小数位数确定1个标准点的价格单位
double PipPoint(string Currency)
{
    int    CalcDigits = MarketInfo(Currency, MODE_DIGITS); // 获取小数位数
    double CalcPoint  = 0.0; // 初始化点值

    if(CalcDigits == 2 || CalcDigits == 3) // 例如 JPY 对 (2位小数) 或某些特殊品种 (3位小数)
    {
        CalcPoint = 0.01;
    }
    else if(CalcDigits == 4 || CalcDigits == 5) // 例如 EURUSD (4位或5位小数)
    {
        CalcPoint = 0.0001;
    }
    return(CalcPoint);
}

// ===== 辅助函数:获取滑点 =====
// 根据货币对小数位数和输入的常规点数,计算实际传递给服务器的滑点值
int GetSlippage(string Currency, int SlippagePips)
{
    int CalcDigits   = MarketInfo(Currency, MODE_DIGITS);
    int CalcSlippage = 0; // 初始化调整后的滑点值

    if(CalcDigits == 2 || CalcDigits == 4) // 2位或4位报价的品种 (例如 JPY对, EURUSD的4位报价)
    {
        CalcSlippage = SlippagePips;       // 滑点值不变
    }
    else if(CalcDigits == 3 || CalcDigits == 5) // 3位或5位报价的品种 (例如 EURUSD的5位报价)
    {
        CalcSlippage = SlippagePips * 10;  // 滑点值需要乘以10 (因为1个常规点包含10个微点)
    }
    return(CalcSlippage);
}

 

赞(0)
未经允许不得转载:图道交易 » MQL4(55):基础版EA交易程序源码
分享到