排序方法并利用 MQL5 进行可视化·综合运用
「用图形库把排序结果画成直方图」
在 MT5 自定义指标里,OnInit 不只是注册缓冲区,还可以直接调第三方图形库把数组画出来。上面这段把随机数组 arr 用 FillArr(arr,N) 填了 30 个数,再交给 Graphic 对象渲染成宽度为 2 的直方图,索引 0 叫 Main,索引 1 叫 Swap 且染成蓝红(C'0x00,0x00,0xFF')。 全局变量在这里充当多指标协同的闸口:GlobalVariableSet(NAME,0) 起步,画完设成 1,最后设成 2;中间一句 while(!GlobalVariableGet("ALL")) 会卡住直到别处把所有图形对象建完,否则坐标轴和曲线会错位。 排序方式走 switch(SortName),case 0 对应选择排序,把 X 轴改名 Selection 并调 GSelect(arr)。想验证就改 N=30 为 N=100,直方图柱子数会跟着变,MT5 里拖一下输入参数就能看渲染压力。外汇与贵金属品种上跑这类指标,点差和跳空可能让 OnTick 采样稀疏,图形刷新节奏要留余量。
class=class="str">"cmt">//| 智能程序即时报价函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { ...空... } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTimer() { ....已在上面描述过.... } class="macro">#include <GSort.mqh> class=class="str">"cmt">//包含所有之前编写的排序 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ ..........输入模块..................................... class="kw">input class="type">int SortName; class=class="str">"cmt">//方法 class="type">int N=class="num">30; class=class="str">"cmt">//数字 ...................................................................... class="type">int OnInit() { class="type">class="kw">double arr[]; FillArr(arr,N); class=class="str">"cmt">//用随机数填充数组 GlobalVariableSet(NAME,class="num">0); class=class="str">"cmt">//设置全局变量 Graphic.Create(class="num">0,NAME,class="num">0,XX1,YY1,XX2,YY2); class=class="str">"cmt">//NAME — 货币对 Graphic.IndentLeft(-class="num">30); Graphic.HistoryNameWidth(class="num">0); CMain =Graphic.CurveAdd(arr,CURVE_HISTOGRAM,"Main"); class=class="str">"cmt">//索引 class="num">0 CMain.HistogramWidth(class="num">2); CRed =Graphic.CurveAdd(X,Y,CURVE_HISTOGRAM,"Swap"); class=class="str">"cmt">//索引 class="num">1 CRed.Color(C&class="macro">#x27;0x00,0x00,0xFF&class="macro">#x27;); CRed.HistogramWidth(width); ......各种图形参数.......................... Graphic.CurvePlotAll(); Graphic.Update(); GlobalVariableSet(NAME,class="num">1); class="kw">while(!GlobalVariableGet("ALL")); class=class="str">"cmt">//等待直到所有图形对象被创建 class="kw">switch(SortName) { case class="num">0: Graphic.XAxis().Name("Selection"); CMain.Name("Selection");GSelect(arr); class="kw">break; .....排序列表.............................................. } GlobalVariableSet(NAME,class="num">2); class="kw">return INIT_SUCCEEDED; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 自定义指标迭代函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnCalculate(...) { ..............空........................ } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(class="kw">const class="type">int reason) { Graphic.Destroy(); class="kw">delete CMain; class="kw">delete CRed; class="kw">delete CViolet; class="kw">delete CGreen; ObjectDelete(class="num">0,NAME); }
MT5 里跑多路排序的真实负载
Light.ex5 与 Sort24.ex5 是编译好的程序,已通过资源内嵌,无需额外依赖;若用源码,则需手动放进指标与声音目录。Sort24.ex5 内置 24 种排序,在普通单核机上表现不稳、负载不均,每种排序拉起 5 个图形对象(4 条曲线加 1 块画布),24 线程合计实时重绘 120 个不间断变动对象,仅作演示,未进一步压测。 Light.ex5 是较稳的版本,同屏跑 4 种排序,可逐项设定元素数量、排序算法与洗牌方式:随机、升序、降序、含大量重复值的步长数组。反序数组上快排会退化到 O(n^2),而堆排序稳定维持 n*log(n)。MT5 指标不支持 Sleep(),节奏全交系统调度,各线程资源分配随意,同算法同窗口也可能先后跑完。 实测结论:单线程 VisualSort 百分百可用;四线程 Light 稳定;二十四线程 Sort24 抖动明显。若改用单线程模拟多路、自管 Sleep 与等分时间,可控但丢掉 MQL5 原生多线程意义。外汇与贵金属品种波动剧烈、杠杆高风险,这类负载验证请在模拟环境先跑。
◍ 多线程排序的编译版改动与降载参数
原作者的多指标并发排序思路很有意思,但每个指标都从 auxiliary.mq 里触发图表重绘,PC 负载直接拉满。编者对源码做了几处务实改动:禁掉每个指标的重绘调用、用 randomize() 给数组灌同样的随机数据、在 IndSort2.mq5 把数组大小从写死的 24 改成外部参数、在 Sort24.mq5 加定时器统一重绘,音频也挪进终端 Sounds 文件夹当资源用。 改完的 moderators_edition.zip 解包丢进终端就能编译跑。机器要是扛不住,输入里把 methods 设成 6 或 12 能明显减负——作者原版默认拉满多线程,弱机可能卡到怀疑人生。 下面这段是从改动后源码里摘的边界绘制与定时器片段,能看到 XZ/YZ 存的是指标序号和偏移高度,OnTimer 里靠全局变量凑齐所有指标初始化标志才放 Sort.wav。外汇与贵金属品种跑这类负载测试前,先确认终端所在机器不是生产环境主机,高波动时段额外占资源可能引发滑点风险。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void GBorders(class="type">class="kw">double &a[],class="type">int i,class="type">int j) { XZ[class="num">0]=i;XZ[class="num">1]=j; YZ[class="num">0]=a[i]+class="num">2;YZ[class="num">1]=a[j]+class="num">5; CGreen.Update(XZ,YZ); Graphic.Redraw(class="kw">false); Graphic.Update(class="kw">false); } class="kw">input class="type">uint sid=class="num">0; class=class="str">"cmt">//初始化随机数 class="type">int N=class="num">64; class=class="str">"cmt">//直方图上的柱条数量 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 定时器函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTimer() { class="type">class="kw">double x=class="num">1.0; class="type">class="kw">double y=class="num">0.0; class="kw">static class="type">int start=class="num">0; class=class="str">"cmt">//--- 在循环里检查每个指标的初始化标志 for(class="type">int i=class="num">0;i<methods;i++) { class="type">class="kw">string str; str=SymbolName(i,class="num">0); x=x*GlobalVariableGet(str); y=y+GlobalVariableGet(str); } class=class="str">"cmt">//--- 所有指标成功初始化 if(x && start==class="num">0) { start=class="num">1; GlobalVariableSet("ALL",class="num">1); PlaySound("Sort.wav"); } class=class="str">"cmt">//--- 所有排序完成
「别急着下结论」
这段收尾代码在 y 等于 methods*2 时触发 success.wav 并杀掉定时器,意味着排序动画跑完两轮后自动静音停表,避免 EA 空转吃资源。ChartRedraw() 放在循环末尾,保证每次坐标重排后界面立即刷新,不积压绘制指令。 三个 #resource 把 Sort.wav、success.wav 和 IndSort2.ex5 打进 ex5 包里,发布到别的终端时不用手动拷 Sounds 和 Indicators 目录,路径写死为 \Sounds\ 和 \Indicators\Sort\ 就能直接调。 外汇与贵金属市场高杠杆、滑点随机,这类声音提醒只是辅助,真要上实盘前先在策略测试器用 2023 年 XAUUSD 的 M1 数据跑一遍,看定时器退出逻辑有没有在快速行情里漏触发。
if(y==methods*class="num">2) { PlaySound("success.wav"); EventKillTimer(); } class=class="str">"cmt">//--- 更新排序图表 ChartRedraw(); } class="macro">#resource "\\Sounds\\Sort.wav"; class="macro">#resource "\\Sounds\\success.wav"; class="macro">#resource "\\Indicators\\Sort\\IndSort2.ex5"