带有图表交互控件的指标·综合运用
(3/3)· 前两篇铺垫了交互控件原理,本篇用完整策略把控件、事件、渲染串成可落地的指标工程
「用滚轮实时改均线周期的交互逻辑」
在 MT5 图表上做指标工具时,常需要不打开设置面板就能调参数。下面这段逻辑用鼠标滚轮直接改移动平均线的周期,省去反复点属性的麻烦。 先开图表事件:把 CHART_EVENT_MOUSE_WHEEL 和 CHART_EVENT_MOUSE_MOVE 都置 1,否则滚轮和移动事件不会触发。注意 CHART_MOUSE_SCROLL 默认是 1(允许滚动缩放),我们要在按住按钮时把它关掉,避免滚轮误触发图表缩放。 核心判断在 OnChartEvent 里:当 sparam 等于按钮名且被按下,scroll_Button 置 true 并关掉 CHART_MOUSE_SCROLL;松开则恢复。之后只要 scroll_Button 为真,滚轮事件里 delta>119 就给 period_ma 加 step(上限 period_ma_max),delta<-119 就减 step(下限 step),每次改完立刻用 iMA 重取句柄并 CopyBuffer 刷新缓冲区。 实测 delta 阈值取 119 是因为 MT5 单次滚轮刻度返回的 dparam 整数约 ±120,留一点余量防抖。把 step 设成 1、period_ma_max 设成 200,你在 EURUSD 的 H1 上滚轮滚一下,均线周期就会从 20 跳 21、22……直观看到斜率变化。外汇和贵金属波动大,这种交互只解决操作效率,不暗示任何方向。
text = name_Line; ChartSetInteger(class="num">0,CHART_EVENT_MOUSE_WHEEL,class="num">1); ChartSetInteger(class="num">0,CHART_EVENT_MOUSE_MOVE,class="num">1); 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) { class=class="str">"cmt">//--- if(!press_Button) ObjectSetString(chart_ID,name,OBJPROP_TEXT,text); if(id==CHARTEVENT_OBJECT_CLICK) { if(sparam==name) { press_Button=ObjectGetInteger(chart_ID,name,OBJPROP_STATE); if(press_Button) { scroll_Button=true; ChartSetInteger(class="num">0,CHART_MOUSE_SCROLL,class="num">0); ChartRedraw(); } else { scroll_Button=false; ChartSetInteger(class="num">0,CHART_MOUSE_SCROLL,class="num">1); ChartRedraw(); } } } } if(scroll_Button) if(id==CHARTEVENT_MOUSE_WHEEL) { class="type">int delta = (class="type">int)dparam; if(delta>class="num">119) if(period_ma<period_ma_max) { period_ma+=step; ChartRedraw(); } class=class="str">"cmt">// if(delta < -class="num">119) if(period_ma>step) { period_ma-=step; ChartRedraw(); } handle = iMA(_Symbol,_Period,period_ma,class="num">0,method_MA,price_MA); ArraySetAsSeries(Label1Buffer,true); for(class="type">int i = class="num">0; i<total; i++) { class="type">class="kw">double MA[]; CopyBuffer(handle,class="num">0,i,class="num">1,MA); Label1Buffer[i]=MA[class="num">0]; ChartRedraw();
◍ 拖拽标签与均线缓冲的衔接细节
这段逻辑紧接前面按钮事件之后,负责把可拖拽文本标签的状态锁死,并真正拉取均线数值写进缓冲数组。 先处理图表对象点击事件:当 sparam 等于标签名且对象未被选中(select==0)时,把 OBJPROP_SELECTABLE 和 OBJPROP_SELECTED 都置为 false,同时 flag_drag 清零,说明拖拽动作已结束,ChartRedraw 重绘一次即可。 计算总量时若 Limit_for_Calc 开启且 total 超过 Limit,就把 total 截断为 Limit(默认 20000 根 K 线),避免大周期回测时无谓遍历。 handle = iMA(_Symbol,_Period,period_ma,0,method_MA,price_MA) 拿到均线句柄;若返回 INVALID_HANDLE 直接 Print 并 return。之后用 while(BarsCalculated(handle)<=0) 轮询,指标没算好就 return(0) 等下一 tick。 正式填充用 for 从 prev_calculated-1 起步,CopyBuffer 取单根 MA 值,Label1Buffer[i]=MA[0]+level 把偏移水平线画在均线之上。开 MT5 把 Limit 改成 5000,能明显看到内存占用和首屏计算耗时下降。
}
ArraySetAsSeries(Label1Buffer,false);
if(press_Button)
ObjectSetString(chart_ID,name,OBJPROP_TEXT,IntegerToString(period_ma));
}
if(id==CHARTEVENT_OBJECT_CLICK)
{
if(sparam==name)
{
class="type">long select = ObjectGetInteger(chart_ID,name,OBJPROP_SELECTED);
if(select==class="num">0)
{
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,false);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,false);
flag_drag=false;
}
ChartRedraw();
}
}
total=rates_total-class="num">1;
if(Limit_for_Calc)
if(total>Limit)
total=Limit;
handle = iMA(_Symbol,_Period,period_ma,class="num">0,method_MA,price_MA);
if(handle==INVALID_HANDLE)
{
Print("invalid handle ");
class="kw">return(rates_total);
}
ResetLastError();
while(BarsCalculated(handle)<=class="num">0)
{
class=class="str">"cmt">// indicator values are not calculated yet, try next time
class="kw">return(class="num">0);
}
for(class="type">int i = prev_calculated>class="num">0?prev_calculated-class="num">1:class="num">0; i<rates_total; i++)
{
class="type">class="kw">double MA[];
CopyBuffer(handle,class="num">0,time[i],class="num">1,MA);
Label1Buffer[i]=MA[class="num">0]+level;
}
input class="type">bool Limit_for_Calc = false;
input class="type">int Limit = class="num">20000;滚轮切周期指标的实测短板
指标跑通后,滚动鼠标滚轮切周期确实顺手,按钮一键开关滚动功能也稳定。但别把它当免维护组件:我曾碰到一次性能衰退,触发点是历史数据超过 20,000 根柱线。 外汇与贵金属市场高波动、高杠杆,这类自定义指标在重历史回看时容易掉帧。日常盯盘建议限制参与计算的柱线数,比如只加载近 3000 根,能绕开大部分卡顿。 手工重命名按钮、不能多次拖拽按钮仍是硬伤,介意的话只能在源码里改 UI 逻辑。总体目标算达成——平稳切周期可用,缺陷也明确,按自己机器配置调柱线上限最实在。
「别急着下结论」
用按钮挂上周期滚动,本质是把均线的参数切换从菜单里拽到图表上。Button MA 那种悬停即换周期的做法,在 1 分钟到日线快速切看时,比右键属性改设置省下不止一半操作时间,但信号准不准仍取决于均线本身,行情跳变时滞后一样存在。 附件里的 Button_CCI.mq5 只有 28.95 KB,它连按钮改名都省了,数量随设置自动编索引,比均线版更轻。拿它开 MT5 拖进图表,先把按钮数设成 3,看看在 XAUUSD 十五分钟图上悬停切换是否跟手。 这类界面只是把重复劳动压到最低,不替你判断方向。外汇和贵金属杠杆高,面板再顺手也拦不住错单,真要验证得自己跑一段时间回测再定。