让图表更有趣:添加背景(基础篇)
「给MT5图表铺一层自定义背景」
MT5默认图表背景是单调的深色或白色,长期盯盘容易视觉疲劳。其实终端允许通过对象函数直接给图表区域绘制位图背景,而不是靠改皮肤设置。 核心思路是用 Resource 把图片编译进ex5,再用 OBJ_BITMAP_LABEL 或 OBJ_BITMAP 画到图表。下面这段最小可用代码在 OnInit 里加载一张名为 background.bmp 的资源并铺满主图区域。 需要注意:背景图会覆盖默认网格与背景色,若图片不透明,K线仍绘制在其上方,但部分指标文字可能被遮挡。外汇与贵金属杠杆高,视觉干扰可能放大误判,实盘前先在模拟盘验证显示层级。
resource "background.bmp"; class="type">int OnInit() { ObjectCreate(class="num">0,"bg",OBJ_BITMAP_LABEL,class="num">0,class="num">0,class="num">0); ObjectSetString(class="num">0,"bg",OBJPROP_BMPFILE,"::background.bmp"); ObjectSetInteger(class="num">0,"bg",OBJPROP_XSIZE,ChartGetInteger(class="num">0,CHART_WIDTH_IN_PIXELS)); ObjectSetInteger(class="num">0,"bg",OBJPROP_YSIZE,ChartGetInteger(class="num">0,CHART_HEIGHT_IN_PIXELS)); ObjectSetInteger(class="num">0,"bg",OBJPROP_BACK,class="num">1); class="kw">return(INIT_SUCCEEDED); }
给报价图表加背景图的动机
MT5 默认界面只有数字与 K 线的图形化呈现,缺少视觉缓冲。实测中,连续盯裸图几分钟就容易出现视觉疲劳,而看风景照或人物图几十分钟也不易疲倦。 把一张心仪图片设为图表背景,不改变任何报价数据,只是让视野里多一层柔和参照。对贵金属、外汇这类高波动品种,长时间手动复盘本就伴随高风险,背景图能降低枯燥感,让交易者更愿意把小时级走势看完整。 做法上不碰指标逻辑,纯属工作环境优化:图只是衬底,提醒你盘面之外还有别的东西,避免陷在分时跳动里。
◍ 把壁纸和徽标分槽存放
做图表背景改造前先定两件事:图片是全局共用一张,还是按资产类型各挂各的。我倾向后者——不同品种配不同图,能直观提示交易标的或该找什么形态,所以编译文件里不内嵌图,运行时再按需加载。 MT5 的目录树不能越界访问,根目录是 MQL5。我们在 Files 下建一个 WALLPAPERS 文件夹,背景图和徽标图分开摆,背景放大图、徽标放 LOGOS 子目录。不塞进系统自带的 IMAGES,是为了少写一层遍历逻辑,保持程序简单。 图像格式有硬要求:必须是 BITMAP,24 位或 32 位。这两种 MT5 默认可读,不用自己写解码。若你硬要用别的格式,得先转成位图再喂给程序——用编辑器转比写读取函数省事。LOGOS 里的文件同理,后面会提到少数例外。 规则定完就进入编码。下面这段按 OOP 组织,后续想移植到脚本或指标里都方便。
「图表背景类的缩放与填充取舍」
把背景图塞进 MT5 图表,最麻烦的不是加载,而是图表尺寸一变图像就糊。类里给了两个 Init 重载:带透明度参数的会把 user01 从 100 减掉再传进去,因为内部渲染用的是「不透明度」而非「透明度」,比如设 30 就是 70% 不透明。 Resize 挂在 OnChartEvent 的 CHARTEVENT_CHART_CHANGE 里,图表一拉伸就重算。核心数学是 f(x)=f(y) 保纵横比;一旦放大(f(x) 或 f(y) > 1.0)就会出现空白带,下图里 f(x)=f(y)=2.0 时空白直接翻倍。 插值能填空白,但 1920x1080 全高清图在 4k 屏上实时跑插值,处理时间明显拉长却对观感没多少增益。作者选了更糙的办法:把上一像素直接拖到空位,32 位(ARGB)整块拷贝,成本和显存拷贝几乎一样快。 嵌套循环里内循环修 f(x) 差异、外循环修 f(y) 差异,都是复制最后一值防空白。想要平滑只改那两行做颜色过渡即可,但别指望 GPU 通过 OpenCL 帮上忙——数据进出延迟会吃掉算力优势。外汇贵金属图表叠加这类背景属高风险界面改造,实盘前先在策略测试器外的小周期图手动拖几次窗口验证渲染。
class=class="str">"cmt">//+------------------------------------------------------------------+ enum eType {IMAGEM, LOGO, COR}; class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">input class="type">char user01 = class="num">30; class=class="str">"cmt">//Transparency( class="num">0 a class="num">100 ) class="kw">input class="type">class="kw">string user02 = "WallPaper_01"; class=class="str">"cmt">//File name class="kw">input eType user03 = IMAGEM; class=class="str">"cmt">//Chart background type class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { if(user03 != COR) WallPaper.Init(user03 == IMAGE ? "WallPapers\" + user02 : "WallPapers\Logos\" + _Symbol, (class="type">char)(class="num">100 - user01)); class="kw">return INIT_SUCCEEDED; } class="type">void OnChartEvent(class="kw">const class="type">int id, class="kw">const class="type">long &lparam, class="kw">const class="type">class="kw">double &dparam, class="kw">const class="type">class="kw">string &sparam) { if(id == CHARTEVENT_CHART_CHANGE) WallPaper.Resize(); }