开发回放系统(第 46 部分):Chart Trade 项目(五)·综合运用
📘

开发回放系统(第 46 部分):Chart Trade 项目(五)·综合运用

第 3/3 篇

用位图按钮在图表上挂买卖信号

这段逻辑干的事很直接:把外部 bmp 资源编译进 EX5,再在 OnInit 里用 OBJ_BITMAP_LABEL 把 BUY 图标贴到图表左上角 (0,0)。SELL 图标则通过 ResourceSave 落盘成 BTN_SELL.bmp,方便别处动态调用。 代码第 11 行用 ChartID() 拿当前图表句柄,ObjectsTotal(id) 做对象计数并转成字符串当名字,避免重名覆盖。第 12 行把编译进程序的 "::Images\\Market Replay\\Chart Trade\\BUY.bmp" 绑定到标签,前缀 "::" 表示读内嵌资源而非硬盘路径。 外汇与贵金属杠杆高,这类按钮只解决下单入口可视化,不替你判断方向,信号误触可能造成真实亏损。开 MT5 把两段 #define 路径换成你自己的图标,编译后看图表是否出现按钮即可验证。

MQL5 / C++
class="macro">#define def_BTN_BUY  "Images\\Market Replay\\Chart Trade\\BUY.bmp"
class="macro">#define def_BTN_SELL "Images\\Market Replay\\Chart Trade\\SELL.bmp"
class="macro">#resource "\\" + def_BTN_BUY
class="macro">#resource "\\" + def_BTN_SELL
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
{
  class="type">long id;
  class="type">class="kw">string sz;
  
  ObjectCreate(id = ChartID(), sz = IntegerToString(ObjectsTotal(id)), OBJ_BITMAP_LABEL, class="num">0, class="num">0, class="num">0);
  ObjectSetString(id, sz, OBJPROP_BMPFILE, class="num">0, "::" + def_BTN_BUY);
  ResourceSave("::" + def_BTN_SELL, "BTN_SELL.bmp");

「把库内图标塞进图表位图标签」

想在 MT5 图表上挂一个可点击的买卖按钮,最省事的办法是用 OBJ_BITMAP_LABEL 对象直接吃 bmp 资源。资源可以来自编译进 ex5 的库文件,也可以从 \Files 目录临时读,两条路在 OnInit 里都能跑通。 下面这段用宏把路径拆开,先 ObjectCreate 一个位图标签,主图用 Icons.Lib 里的 BUY.bmp,副图用 ResourceSave 落地的 SELL.bmp。注意 OBJPROP_BMPFILE 的索引 0 是常态图、1 是鼠标悬停或按下态,漏了索引 1 按钮就不会换肤。 [CODE] #define def_BTN_BUY "Images\\Market Replay\\Chart Trade\\BUY.bmp" #define def_BTN_SELL "Images\\Market Replay\\Chart Trade\\SELL.bmp" #define def_LIB "\\Indicators\\Icons.Lib" int OnInit() { long id; string sz; ObjectCreate(id = ChartID(), sz = IntegerToString(ObjectsTotal(id)), OBJ_BITMAP_LABEL, 0, 0, 0); ObjectSetString(id, sz, OBJPROP_BMPFILE, 0, def_LIB + "::" + def_BTN_BUY); ResourceSave(def_LIB + "::" + def_BTN_SELL, "BTN_SELL.bmp"); ObjectSetString(id, sz, OBJPROP_BMPFILE, 1, "\\Files\\BTN_SELL.bmp"); return INIT_SUCCEEDED; } [/CODE] 逐行拆解:第 2–4 行是路径宏,把库前缀和图片名分开好维护;第 8 行把当前图表 id 和自增对象名绑给位图标签;第 9 行主图加载 BUY 图标,走库内资源双冒号语法;第 10 行把 SELL 图标从库导出到 \Files;第 11 行把悬停态指向落地文件。 如果懒得拆宏,硬编码也行,效果等价: [CODE] int OnInit() { long id; string sz; ObjectCreate(id = ChartID(), sz = IntegerToString(ObjectsTotal(id)), OBJ_BITMAP_LABEL, 0, 0, 0); ObjectSetString(id, sz, OBJPROP_BMPFILE, 0, "\\Indicators\\Icons.Lib::Images\\Market Replay\\Chart Trade\\BUY.bmp"); ResourceSave("\\Indicators\\Icons.Lib::Images\\Market Replay\\Chart Trade\\SELL.bmp", "\\Files\\BTN_SELL.bmp"); ObjectSetString(id, sz, OBJPROP_BMPFILE, 1, "\\Files\\BTN_SELL.bmp"); return INIT_SUCCEEDED; } [/CODE] 开 MT5 把 Icons.Lib 丢进 \Indicators,编译这段到 EA 里,图表左上角就会冒出按钮。外汇和贵金属波动剧烈,这类按钮只解决下单入口,不替你管风控,实盘前先在策略测试器里点一遍确认坐标和换图正常。

MQL5 / C++
class="macro">#define def_BTN_BUY  "Images\\Market Replay\\Chart Trade\\BUY.bmp"
class="macro">#define def_BTN_SELL "Images\\Market Replay\\Chart Trade\\SELL.bmp"
class="macro">#define def_LIB      "\\Indicators\\Icons.Lib"

class="type">int OnInit()
{
   class="type">long id;
   class="type">class="kw">string sz;
   ObjectCreate(id = ChartID(), sz = IntegerToString(ObjectsTotal(id)), OBJ_BITMAP_LABEL, class="num">0, class="num">0, class="num">0);
   ObjectSetString(id, sz, OBJPROP_BMPFILE, class="num">0, def_LIB + "::" + def_BTN_BUY);
   ResourceSave(def_LIB + "::" + def_BTN_SELL, "BTN_SELL.bmp");
   ObjectSetString(id, sz, OBJPROP_BMPFILE, class="num">1, "\\Files\\BTN_SELL.bmp");
   class="kw">return INIT_SUCCEEDED;
}

class="type">int OnInit()
{
   class="type">long id;
   class="type">class="kw">string sz;
   ObjectCreate(id = ChartID(), sz = IntegerToString(ObjectsTotal(id)), OBJ_BITMAP_LABEL, class="num">0, class="num">0, class="num">0);
   ObjectSetString(id, sz, OBJPROP_BMPFILE, class="num">0, "\\Indicators\\Icons.Lib::Images\\Market Replay\\Chart Trade\\BUY.bmp");
   ResourceSave("\\Indicators\\Icons.Lib::Images\\Market Replay\\Chart Trade\\SELL.bmp", "\\Files\\BTN_SELL.bmp");
   ObjectSetString(id, sz, OBJPROP_BMPFILE, class="num">1, "\\Files\\BTN_SELL.bmp");
   class="kw">return INIT_SUCCEEDED;
}

◍ 在图表上拼出欧元美元图标组

MT5 的 #resource 能把 bmp 图片编译进 exe,用 as bitmap 还可把图片读成二维数组直接改像素。上面那段把 euro.bmp 读进 euro[][],再在中间行刷一道 0xFFFF0000(不透明红),相当于给原图加了一条红色扫描线。 ResourceCreate 用改完的数组生成名为 euro_icon 的运行时资源,ArrayRange(euro,1) 是宽、ArrayRange(euro,0) 是高;之后 Image() 函数用 OBJ_BITMAP_LABEL 把图片按 X/Y 像素距离贴到图表。三次调用分别放在 x=10、15+宽、20+宽*2 的位置,y 都是 40,图标间距由图片宽度决定。 想验证就开 MT5 把 euro.bmp、dollar.bmp 丢进 MQL5/Images,跑这段 OnStart,图表左上就能看到红条欧元 + 美元 + 原版欧元横向排开。外汇贵金属图表叠加自绘素材时需注意:这类对象只是视觉辅助,不改报价逻辑,实盘前先在模拟盘确认遮挡不影响下单点击。 最后一行展示了另一种路径——直接从 Indicators\Icons.Lib 这个编译库里按完整路径取 BUY.bmp,省去 ResourceCreate,适合复用别人封装好的图标集。

MQL5 / C++
class="macro">#resource "\Images\euro.bmp" as bitmap euro[][]
class="macro">#resource "\Images\dollar.bmp"
class=class="str">"cmt">//+------------------------------------------------------------------+ 
class="type">void Image(class="type">class="kw">string name,class="type">class="kw">string rc,class="type">int x,class="type">int y)
{
   ObjectCreate(class="num">0, name, OBJ_BITMAP_LABEL, class="num">0, class="num">0, class="num">0);
   ObjectSetInteger(class="num">0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(class="num">0, name, OBJPROP_YDISTANCE, y);
   ObjectSetString(class="num">0, name, OBJPROP_BMPFILE, rc);
}
class=class="str">"cmt">//+------------------------------------------------------------------+ 
class="type">void OnStart()
{
   for(class="type">int x = class="num">0; x < ArrayRange(euro, class="num">1); x++)
      euro[ArrayRange(euro, class="num">1) / class="num">2][x] = 0xFFFF0000;
   ResourceCreate("euro_icon", euro, ArrayRange(euro, class="num">1), ArrayRange(euro, class="num">0), class="num">0, class="num">0, ArrayRange(euro, class="num">1), COLOR_FORMAT_ARGB_NORMALIZE);
   Image("Euro" , "::euro_icon", class="num">10, class="num">40);
   Image("USD", "::Images\\dollar.bmp", class="num">15 + ArrayRange(euro,class="num">1), class="num">40);
   Image("E2", "::Images\\euro.bmp", class="num">20 + ArrayRange(euro, class="num">1) * class="num">2, class="num">40);
}
class=class="str">"cmt">//+------------------------------------------------------------------+ 
ObjectSetString(id, sz, OBJPROP_BMPFILE, class="num">0, "\Indicators\Icons.Lib::Images\Market Replay\Chart Trade\BUY.bmp");

记住这一条就够了

把模板塞进 MT5 可执行文件这件事,核心不在于语法多绕,而在于绕开 MQL5 编译期限制、用 DLL 把运行时泛型能力补回来。前面三篇拆的整套字符串化与重载手法,在 149.64 KB 的 Indicators.zip 示例里都能直接翻出来对照。 评论区 Daniel Jose 自己点过:任意文件都能转字符串传,但 MQL5 字符串遇 NULL 字符即截断,这是硬限制,别拿含 0x00 的二进制直接硬转。 外汇与贵金属杠杆品种波动剧烈,这类底层技巧只解决「能不能」,不解决「赚不赔」,实盘前务必在策略测试器跑通再上真金。 真正的专业交易者不会停在「官方说做不到」那一步——下次遇到 MT5 看似封死的能力,先想 DLL 与字符串桥接,再谈放弃。

常见问题

可在图表上创建位图标签对象,把买卖箭头图标画在K线旁,点击按钮触发下单逻辑,省去切换窗口的操作。
先把图标资源编译进库,再用图表位图标签按坐标逐个绘制,注意控制像素尺寸避免遮挡价格。
小布可基于策略识别关键位,直接在对应品种页生成买卖图标组,你只需核对信号强弱,不用手动拼图。
过量位图会占用渲染资源,建议单图不超过20个标签,并复用同一图标资源降低开销。
位图标签未设跨周期保存属性,需在创建时指定持久化参数,否则重启或换周期即丢失。