今天复盘一个XAUUSD网页信号流程时,我再次遇到一个工程问题:同一轮行情里,网页计算、消息传输与EA轮询可能以不同频率运行。如果EA只判断“当前条件为真”,重连、延迟或重复推送都可能造成同一结构被处理多次。
我更倾向于把“已收K线时间 + 规则版本 + 方向”组合成事件键。EA收到消息后,先校验事件是否属于上一根已完成K线,再检查是否已经处理。下面是一个最小化示例:
// MQL5
datetime last_closed_bar = 0;
bool IsNewClosedBarSignal(const ENUM_TIMEFRAMES tf)
{
datetime closed_bar = iTime(_Symbol, tf, 1);
if(closed_bar <= 0 || closed_bar == last_closed_bar)
return false;
last_closed_bar = closed_bar;
return true;
}
void OnTick()
{
if(!IsNewClosedBarSignal(PERIOD_M5))
return;
// 1. 读取并校验外部事件时间
// 2. 核对规则版本与交易品种
// 3. 再进入本地风险门;此处不直接下单
}
这个示例不解决策略是否有效,它只解决一层工程问题:避免同一根已收K线被重复消费。生产环境还需要把事件键持久化,并分别记录接收时间、校验结果、拒绝原因和本地风险门状态。
我把“消息收到”“规则成立”“允许执行”“策略有效”视为四个不同状态。前一层通过,不能替后一层背书。欢迎讨论你们在MT5重启后如何恢复幂等状态:终端全局变量、文件,还是外部数据库?
仅用于MQL5工程交流,不构成交易建议,也不代表任何策略表现。
补充一条今天的前向记录:事件模型只评估到1个事件,候选为0,同时缺少完整官方事件表和对应的历史Bid/Ask序列。因此我没有把这次空结果记为 RULE_NOT_TRIGGERED,而是记为 DATA_NOT_READY。
在EA侧我准备把“没有动作”的原因写成显式状态,而不是只写一条 No trade:
// MQL5
enum ENUM_GATE_RESULT
{
DATA_NOT_READY = 0,
RULE_NOT_TRIGGERED,
RISK_REJECTED,
DELIVERY_FAILED,
EXECUTION_READY
};
ENUM_GATE_RESULT EvaluateGate(const bool event_ok,
const bool bidask_ok,
const bool rule_ok,
const bool risk_ok)
{
if(!event_ok || !bidask_ok)
return DATA_NOT_READY;
if(!rule_ok)
return RULE_NOT_TRIGGERED;
if(!risk_ok)
return RISK_REJECTED;
return EXECUTION_READY;
}
void LogGate(const ENUM_GATE_RESULT state, const datetime event_time)
{
PrintFormat("event=%s state=%d symbol=%s bid=%.2f ask=%.2f",
TimeToString(event_time, TIME_DATE|TIME_SECONDS),
(int)state, _Symbol,
SymbolInfoDouble(_Symbol, SYMBOL_BID),
SymbolInfoDouble(_Symbol, SYMBOL_ASK));
}
关键点不是枚举本身,而是让 DATA_NOT_READY 与 RULE_NOT_TRIGGERED 永远不能合并统计。前者说明证据链不完整,后者才说明规则在完整输入下没有成立。否则统计“空信号率”时,会把数据故障误算成策略过滤能力。
这段仍只是状态分层示例,不代表策略已验证,也不直接触发订单。大家在MQL5里会把数据就绪状态放在本地EA、服务端,还是两边都校验?