从头开始开发智能交易系统(第 30 部分):CHART TRADE 当作指标?·综合运用
「用全局变量和定时器串起交易面板」
这段初始化逻辑把止损参数写进全局变量,再拉起交易视图对象,并通过 500 毫秒的毫秒级定时器维持面板响应。外汇与贵金属杠杆高,全局变量被多个 EA 共享时,误读其他程序的 def_GlobalVariableStop 可能导致仓位风控错位。 OnDeinit 里第一件事是 EventKillTimer(),否则 EA 卸载后定时器回调仍可能触发空指针。OnTimer 按编译开关分流:未集成图表交易时只跑 ChartTrade_ClickButton(),集成盘口阅读时刷新 VolumeAtPrice 并重连 TimesAndTrade。 鼠标事件里用位运算拆按键:0x01 是左键点击,0x04 是 Shift,0x08 是 Ctrl。当 Shift 与 Ctrl 状态不同(bKeyBuy != bKeySell)且未处于挂单挂载态时,非集成模式下直接读全局变量拼仓位——手数 = 杠杆全局变量 × 终端最小成交量,止盈止损取自 def_GlobalVariableTake / Stop。 让小布替你跑这套 把下面代码贴进 MT5 的 EA 模板,改 def_GlobalVariableLeverage 的值,能在 500ms 内看到手数随杠杆实时变;黄金 XAUUSD 点差跳变时建议先把定时器改 1000ms 降低开销。
GlobalVariableSet(def_GlobalVariableStop, user22); TradeView.Initilize(); GlobalVariableSet(def_GlobalVariableResult, TradeView.GetFinanceRoof()); EventSetMillisecondTimer(class="num">500); class="macro">#endif class="type">void OnDeinit(const class="type">int reason) { EventKillTimer(); class="type">void OnTimer() { class="macro">#ifndef def_INTEGRATION_CHART_TRADER ChartTrade_ClickButton(); class="macro">#endif class="macro">#ifdef def_INTEGRATION_TAPE_READING VolumeAtPrice.Update(); TimesAndTrade.Connect(); class="macro">#endif } case CHARTEVENT_MOUSE_MOVE: Mouse.GetPositionDP(dt, price); mKeys = Mouse.GetButtonStatus(); bEClick = (mKeys & 0x01) == 0x01; class=class="str">"cmt">//Left mouse button click bKeyBuy = (mKeys & 0x04) == 0x04; class=class="str">"cmt">//SHIFT pressed bKeySell= (mKeys & 0x08) == 0x08; class=class="str">"cmt">//CTRL pressed if (bKeyBuy != bKeySell) { if (!bMounting) { class="macro">#ifdef def_INTEGRATION_CHART_TRADER m_Selection.bIsDayTrade = Chart.GetBaseFinance(m_Selection.vol, valueTp, valueSl); class="macro">#else m_Selection.vol = GlobalVariableGet(def_GlobalVariableLeverage) * Terminal.GetVolumeMinimal(); valueTp = GlobalVariableGet(def_GlobalVariableTake); valueSl = GlobalVariableGet(def_GlobalVariableStop); m_Selection.bIsDayTrade = EA_user23; class="macro">#endif
◍ 切周期别把图表交易指标弄丢了
MT5 里只要动一下图表周期、改个 EA 参数,终端就会抛 OnDeinit 事件。对普通 EA 这通常无伤大雅,但如果你搭的是「EA 做服务器 + 指标做客户端」的架构,靠全局变量互相探活,原生 OnDeinit 会直接把那些变量删掉。 指标端靠 GlobalVariableCheck 轮询变量是否存在来判断 EA 是否还挂在图上。一旦 EA 触发 OnDeinit 先把变量删了,指标可能赶在 EA 重建变量前就被误判离线、自己从图表消失——这种诡异退出时有时无,复现概率随操作节奏浮动。 查官方逆初始化原因枚举后,解法很直接:在 OnDeinit 里对 reason 做 switch,仅当 reason 不是 REASON_CHARTCHANGE 时才清变量。这样切周期、重绘不会误杀,EA 和 Chart Trade 指标能稳稳共存。 不过参数层面的重新初始化仍可能拆掉指标,所以 EA 和指标都加载后,再去动 EA 输入参数意义不大,容易引发不可控卸载。外汇与贵金属品种波动剧烈,这类客户端架构的边界条件建议先在模拟盘验证。
class="type">void OnDeinit(const class="type">int reason) { EventKillTimer(); Mouse.Destroy(); TradeView.Finish(); class="macro">#ifndef def_INTEGRATION_CHART_TRADER GlobalVariableDel(def_GlobalVariableLeverage); GlobalVariableDel(def_GlobalVariableTake); GlobalVariableDel(def_GlobalVariableStop); GlobalVariableDel(def_GlobalVariableResult); GlobalVariableDel(def_GlobalVariableButton); class="macro">#endif class="macro">#ifdef def_INTEGRATION_TAPE_READING EventKillTimer(); class="macro">#endif } class="type">void OnChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam) { if (!GlobalVariableCheck(def_GlobalVariableLeverage)) OnDeinit(REASON_INITFAILED); Chart.DispatchMessage(id, lparam, dparam, sparam); } class="type">void OnDeinit(const class="type">int reason) { EventKillTimer(); Mouse.Destroy(); TradeView.Finish(); class="macro">#ifndef def_INTEGRATION_CHART_TRADER class="kw">switch (reason) { case REASON_CHARTCHANGE: break; class="kw">default: GlobalVariableDel(def_GlobalVariableLeverage); GlobalVariableDel(def_GlobalVariableTake); GlobalVariableDel(def_GlobalVariableStop); GlobalVariableDel(def_GlobalVariableResult); GlobalVariableDel(def_GlobalVariableButton); }; class="macro">#endif class="macro">#ifdef def_INTEGRATION_TAPE_READING EventKillTimer(); class="macro">#endif }
文档才是破局的底牌
做 MT5 自定义工具时,很多卡点看起来像死路——比如想让 EA 在退出前干净地卸掉声音模块,或者让平台用语音播报状态。实际上 MQL5 官方文档里大多埋着接口说明,只是没人愿意逐行读。 前面几篇拆过从 EA 里逐步抽离部件的过程,最后要移除的正是声音系统;若你没跟过系列,直接看源码会一头雾水,但对照文档里的 PlaySound / 资源释放规则就能理顺调用链。 外汇与贵金属杠杆高、滑点随机,任何自研系统都只是概率工具。下次碰到看似无解的需求,先翻文档再动手,比盲写代码省一半时间。