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