如何准备 MetaTrader 5 报价用于其他应用程序·进阶篇
📘

如何准备 MetaTrader 5 报价用于其他应用程序·进阶篇

第 2/3 篇

跑脚本前先卡死错误参数

写 CSV 导入或历史数据解析脚本时,最怕用户手滑把起始日期填到结束日期后面。在基础逻辑之前插一个 ValidationParameters() 做前置拦截,能在 MT5 弹窗报错并直接终止,避免后面写出一堆错位数据。 函数里第一个判断就是 start_date>=end_date 时弹「The start date should be earlier than the ending one!」,返回 true 表示参数有误。注意这里返回 true 反而代表校验不通过,调用方要用 if(ValidationParameters()) 来中止——这个反直觉写法容易埋坑。 后面两段针对表头格式做耦合检查:NSDT_5 表头(带引号的 Date Time Open… 列)只允许 dd.mm.yyyy 或 dd/mm/yyyy 配逗号分隔时间;NSDT_6 表头(Date,Open,High… 无引号)同理。若选了 SEP_POINT2 / SEP_SLASH2 之外的分隔就被拦下。全部通过才 return false,程序继续。 开 MT5 把下面代码贴进 EA 或脚本,故意把起止日期填反,能立刻看到错误框弹出并停止,验证拦截是否生效。

MQL5 / C++
class=class="str">"cmt">//____________________________________________________________________
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| CHECKING_CORRECTNESS_OF_PARAMETERS                               |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool ValidationParameters()
  {
   if(start_date>=end_date)
     {
      MessageBox("The start date should be earlier than the ending one!\n\n"
                  "Application cannot class="kw">continue. Please retry.",
                  class=class="str">"cmt">//---
                  "Parameter error!",MB_ICONERROR);
      class=class="str">"cmt">//---
      class="kw">return(true);
     }
class=class="str">"cmt">//---
   if(format_headers==NSDT_5 && 
      (format_date==SEP_POINT1 || format_date==SEP_SLASH1))
     {
      MessageBox("For the headers of the following format:\n\n"
                  "\"Date\" ""\"Time\" ""\"Open\" ""\"High\" ""\"Low\" ""\"Close\" ""\"Volume\"\n\n"
                  "Date/time format can be selected out of two versions:\n\n"
                  "dd.mm.yyyy, hh:mm\n"
                  "dd/mm/yyyy, hh:mm\n\n"
                  "Application cannot class="kw">continue. Please retry.",
                  class=class="str">"cmt">//---
                  "Header and date/time formats do not match!",MB_ICONERROR);
      class=class="str">"cmt">//---
      class="kw">return(true);
     }
class=class="str">"cmt">//---
   if(format_headers==NSDT_6 && 
      (format_date==SEP_POINT2 || format_date==SEP_SLASH2))
     {
      MessageBox("For the headers of the following format:\n\n"
                  "Date,Open,High,Low,Close,Volume\n\n"
                  "Date/time format can be selected out of two versions:\n\n"
                  "dd.mm.yyyy hh:mm\n"
                  "dd/mm/yyyy hh:mm\n\n"
                  "Application cannot class="kw">continue. Please retry.",
                  class=class="str">"cmt">//---
                  "Header and date/time formats do not match!",MB_ICONERROR);
      class=class="str">"cmt">//---
      class="kw">return(true);
     }
class=class="str">"cmt">//---
   class="kw">return(class="kw">false);
  }

◍ 脚本跑起来前先铺好的全局变量

写 MT5 脚本时,先把所有跨函数要用的状态和容器在文件头部一次性声明,能省掉后面反复传参的麻烦。上面这段声明里,图形对象名数组 arr_nmobj 写死长度为 22,实际放了 "fon"、"hd01" 加 nm01~nm20 共 22 个字符串,而对应的文本数组 arr_txtobj 长度是 21——这种差一个的配对,多半是背景框 fon 不需要独立文本槽,调试时若越界会直接报数组错误。 日期类变量拆成了 sdt、dd、mm、yyyy、tm、sep 六个字符串,看得出作者想把 K 线时间自己拼成固定格式再写文件,而不是依赖 MqlRates 自带的 time 字段直接输出。三个 datetime 变量 first_date、first_termnl_date、first_server_date 把「品种本地数据 / 终端数据库 / 服务器数据库」的起始点分开存,后面校验数据缺口时就能知道该从哪拉历史。 进度与句柄也在这里定了:pgs_pcnt 记写盘百分比,hFl 初始给 INVALID_HANDLE,没打开文件前任何 Write 操作都应该先判它。外汇和贵金属行情缺口常见,max_bars 读终端设置上限,配合 copied_bars 和 bars 能算出实际能落盘多少根,开 MT5 把这段贴进脚本头部编译,改 arr_nmobj 长度试一次越界就知道数组边界多重要。

MQL5 / C++
class=class="str">"cmt">//____________________________________________________________________
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| GLOBAL_VARIABLES_AND_ARRAYS                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">MqlRates rates[]; class=class="str">"cmt">// Array for copying data
class=class="str">"cmt">//---
class="type">class="kw">string symbols[]; class=class="str">"cmt">// Symbol array
class=class="str">"cmt">//---
class=class="str">"cmt">// Array of graphic object names
class="type">class="kw">string arr_nmobj[class="num">22]=
  {
   "fon","hd01",
   "nm01","nm02","nm03","nm04","nm05","nm06","nm07","nm08","nm09","nm10",
   "nm11","nm12","nm13","nm14","nm15","nm16","nm17","nm18","nm19","nm20"
  };
class=class="str">"cmt">//---
class=class="str">"cmt">// Array of displayed text containing graphic objects
class="type">class="kw">string arr_txtobj[class="num">21];
class=class="str">"cmt">//---
class="type">class="kw">string path="";           class=class="str">"cmt">// File path
class="type">int cnt_symb=class="num">0;           class=class="str">"cmt">// Number of symbols
class="type">int sz_arr_symb=class="num">0;        class=class="str">"cmt">// Symbol array size
class="type">int bars=class="num">0;               class=class="str">"cmt">// Number of bars according to the specified TF
class="type">int copied_bars=class="num">0;        class=class="str">"cmt">// Number of bars copied for writing
class="type">class="kw">double pgs_pcnt=class="num">0;        class=class="str">"cmt">// Writing progress
class="type">int hFl=INVALID_HANDLE;   class=class="str">"cmt">// File handle
class=class="str">"cmt">//---
class="type">class="kw">string  class=class="str">"cmt">// Variables for data formatting
sdt="",  class=class="str">"cmt">// Date line
dd="",   class=class="str">"cmt">// Day
mm="",   class=class="str">"cmt">// Month
yyyy="", class=class="str">"cmt">// Year
tm="",   class=class="str">"cmt">// Time
sep="";  class=class="str">"cmt">// Separator
class=class="str">"cmt">//---
class="type">int max_bars=class="num">0; class=class="str">"cmt">// Maximum number of bars in the terminal settings
class=class="str">"cmt">//---
class="type">class="kw">datetime
first_date=class="num">0,            class=class="str">"cmt">// First available data in a specified period
first_termnl_date=class="num">0,     class=class="str">"cmt">// First available data in the terminal&class="macro">#x27;s database
first_server_date=class="num">0,     class=class="str">"cmt">// First available data in the server&class="macro">#x27;s database
check_start_date=class="num">0;      class=class="str">"cmt">// Checked correct date value

「信息面板的三类背景与可视化测试坑」

想在 MT5 图表上挂一块实时信息面板,背景对象有三条路:矩形标签(OBJ_RECTANGLE_LABEL)最直白,位图(OBJ_BITMAP)能给界面换肤,编辑框(OBJ_EDIT)设成只读后也能当底板。前两者在普通图表没问题,但一旦进策略测试器的可视化模式就完全不显示——这是实盘和回测界面割裂的老坑。 目前唯一能在测试器可视化模式下正常露脸的背景类型就是 OBJ_EDIT 只读框。即便你只是写个脚本而非 EA,用编辑框做底板也能顺带把测试时的显示逻辑一并验证,省得实盘长这样、回测变空白。 面板要呈现的关键字段包括:当前/总品种数、品种路径、启动周期、用户输入的起始日期、当前周期首根可用柱日期、终端 M1 首日期、服务器 M1 首日期、最大显示柱数、已复制柱数,以及当前品种写入进度百分比。下图示例里面板宽度固定 300 像素,进度开时高 138、关时高 126,这种硬编码尺寸你复制后大概率要按自己显示器改。 脚本结束或被手动删掉时,所有自建图形对象必须清掉,否则图表会留垃圾对象。下面这段 InfoTable 函数就是建面板的核心:先定 8 号 Calibri 字、白烟色,再用 SeriesInfoInteger 抓三类首日期,抓不到就打问号,最后把字段塞进 arr_txtobj 数组准备绘制。

MQL5 / C++
class=class="str">"cmt">//____________________________________________________________________
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| INFORMATION_PANEL                                                                |
class=class="str">"cmt">//|------------------------------------------------------------------+
class="type">void InfoTable(class="type">int s)
  {
   class="type">int fnt_sz=class="num">8;           class=class="str">"cmt">// Font size
   class="type">class="kw">string fnt="Calibri";   class=class="str">"cmt">// Header font
   class="type">class="kw">color clr=clrWhiteSmoke;  class=class="str">"cmt">// Color
class=class="str">"cmt">//---
   class="type">int xH=class="num">300;
   class="type">int height_pnl=class="num">0;
   class="type">int yV1=class="num">1,yV2=class="num">12,xV1=class="num">165,xV2=class="num">335,xV3=class="num">1;
class=class="str">"cmt">//---
   class="type">class="kw">string sf="",stf="",ssf="";
   class="type">bool flg_sf=class="kw">false,flg_stf=class="kw">false,flg_ssf=class="kw">false;
class=class="str">"cmt">//---
   if(show_progress) { height_pnl=class="num">138; } else { height_pnl=class="num">126; }
class=class="str">"cmt">//---
   flg_sf=SeriesInfoInteger(symbols[s],_Period,SERIES_FIRSTDATE,first_date);
   flg_stf=SeriesInfoInteger(symbols[s],PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_termnl_date);
   flg_ssf=SeriesInfoInteger(symbols[s],PERIOD_M1,SERIES_SERVER_FIRSTDATE,first_server_date);
class=class="str">"cmt">//---
   if(flg_sf) { sf=TSdm(first_date); } else { sf="?"; }
   if(flg_stf) { stf=TSdm(first_termnl_date); } else { stf="?"; }
   if(flg_ssf) { ssf=TSdm(first_server_date); } else { ssf="?"; }
class=class="str">"cmt">//---
   if(cnt_symb==class="num">0) { cnt_symb=class="num">1; }
class=class="str">"cmt">//---
   class="type">int anchor1=ANCHOR_LEFT_UPPER,anchor2=ANCHOR_RIGHT_UPPER,corner=CORNER_LEFT_UPPER;
class=class="str">"cmt">//---
   class="type">class="kw">string path_symbol=SymbolInfoString(symbols[s],SYMBOL_PATH);
   path_symbol=StringSubstr(path_symbol,class="num">0,StringLen(path_symbol)-StringLen(symbols[s]));
class=class="str">"cmt">//---
   arr_txtobj[class="num">0]="INFO TABLE";
   arr_txtobj[class="num">1]="Symbol(current / total) : ";
   arr_txtobj[class="num">2]=""+symbols[s]+" ("+IS(s+class="num">1)+"/"+IS(cnt_symb)+")";
   arr_txtobj[class="num">3]="Path Symbol : ";
   arr_txtobj[class="num">4]=path_symbol;
   arr_txtobj[class="num">5]="Timeframe : ";

面板文本与坐标的批量落位

这段逻辑把监控面板要用到的字符串先塞进 arr_txtobj 数组,索引 6 到 20 分别对应周期、输入起始日、H1 首根时间、M1 终端首根、M1 服务器首根、最大 Bars 限制、已复制 Bars 数以及当前品种进度百分比。注意进度那行用了 DS(pgs_pcnt,2)+"%",意味着面板显示两位小数精度,例如回测时若复制了 1234 根而上限 5000,会直接显示 24.68%。 后面紧接的是 Create_Edit 与 Create_Label 的成批调用。Create_Edit(0,0,arr_nmobj[0],"",corner,fnt,fnt_sz,clrDimGray,clrDimGray,345,height_pnl,xV3,yV1,2,C'15,15,15') 先画底板,345 是宽度、height_pnl 控制高度,背景近黑;下一句给 arr_nmobj[1] 赋标题文本并用了 clrFireBrick 做边框提示。 标签类则用 Create_Label 按 yV1+yV2*n 的纵向步进排布,n 从 1 到 7,xV1 与 xV2 分两列错开。你打开 MT5 把 xV2 改成 xV1+170 就能直观看到右列整体右移,验证布局是否如预期贴合底板。外汇与贵金属行情高波动,面板数值仅作本地诊断,不代表任何方向暗示。

MQL5 / C++
  arr_txtobj[class="num">6]=gStrTF(_Period);
  arr_txtobj[class="num">7]="Input Start Date : ";
  arr_txtobj[class="num">8]=TSdm(start_date);
  arr_txtobj[class="num">9]="First Date(H1) : ";
  arr_txtobj[class="num">10]=sf;
  arr_txtobj[class="num">11]="First Terminal Date(M1) : ";
  arr_txtobj[class="num">12]=stf;
  arr_txtobj[class="num">13]="First Server Date(M1) : ";
  arr_txtobj[class="num">14]=ssf;
  arr_txtobj[class="num">15]="Max. Bars In Options Terminal : ";
  arr_txtobj[class="num">16]=IS(max_bars);
  arr_txtobj[class="num">17]="Copied Bars : ";
  arr_txtobj[class="num">18]=IS(copied_bars);
  arr_txtobj[class="num">19]="Progress Value Current Symbol : ";
  arr_txtobj[class="num">20]=DS(pgs_pcnt,class="num">2)+"%";
class=class="str">"cmt">//---
  Create_Edit(class="num">0,class="num">0,arr_nmobj[class="num">0],"",corner,fnt,fnt_sz,clrDimGray,clrDimGray,class="num">345,height_pnl,xV3,yV1,class="num">2,C&class="macro">#x27;class="num">15,class="num">15,class="num">15&class="macro">#x27;);
class=class="str">"cmt">//---
  Create_Edit(class="num">0,class="num">0,arr_nmobj[class="num">1],arr_txtobj[class="num">0],corner,fnt,class="num">8,clrWhite,C&class="macro">#x27;class="num">64,class="num">0,class="num">0&class="macro">#x27;,class="num">345,class="num">12,xV3,yV1,class="num">2,clrFireBrick);
class=class="str">"cmt">//---
  Create_Label(class="num">0,arr_nmobj[class="num">2],arr_txtobj[class="num">1],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">3],arr_txtobj[class="num">2],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2,class="num">0);
class=class="str">"cmt">//---
  Create_Label(class="num">0,arr_nmobj[class="num">4],arr_txtobj[class="num">3],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">2,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">5],arr_txtobj[class="num">4],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">2,class="num">0);
class=class="str">"cmt">//---
  Create_Label(class="num">0,arr_nmobj[class="num">6],arr_txtobj[class="num">5],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">3,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">7],arr_txtobj[class="num">6],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">3,class="num">0);
class=class="str">"cmt">//---
  Create_Label(class="num">0,arr_nmobj[class="num">8],arr_txtobj[class="num">7],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">4,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">9],arr_txtobj[class="num">8],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">4,class="num">0);
class=class="str">"cmt">//---
  Create_Label(class="num">0,arr_nmobj[class="num">10],arr_txtobj[class="num">9],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">5,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">11],arr_txtobj[class="num">10],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">5,class="num">0);
class=class="str">"cmt">//---
  Create_Label(class="num">0,arr_nmobj[class="num">12],arr_txtobj[class="num">11],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">6,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">13],arr_txtobj[class="num">12],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">6,class="num">0);
class=class="str">"cmt">//---
  Create_Label(class="num">0,arr_nmobj[class="num">14],arr_txtobj[class="num">13],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">7,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">15],arr_txtobj[class="num">14],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">7,class="num">0);
class=class="str">"cmt">//---

◍ 用 OBJ_LABEL 把面板文字钉死在图表上

上面那段循环调用,本质是在图表左上角(或指定 corner)逐行铺文字标签:arr_nmobj 存对象名、arr_txtobj 存显示文本,y 坐标用 yV1+yV2*N 做行距,N 从 8 到 10 代表第 9~11 行;show_progress 为真时才补画两行进度提示,避免无谓对象开销。 真正干活的在 Create_Label 这个函数。它先 ObjectCreate 建 OBJ_LABEL,图表 ID 传 0 即当前图,后两个 0 是占位的时空坐标(标签不走时间轴)。建成功后才用 ObjectSetString / ObjectSetInteger 把文字、字体、颜色、锚点依次写进去。 锚点 anchor 和 corner 的配合决定标签贴哪:corner 选左上,anchor 用左上角对齐,x_dist/y_dist 就是离那个角的像素偏移。外汇和贵金属波动快,这类浮层若 zorder 设错,容易被蜡烛图盖住,调参时建议先写死 zorder=0 在 MT5 里肉眼确认层级。

MQL5 / C++
  Create_Label(class="num">0,arr_nmobj[class="num">16],arr_txtobj[class="num">15],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">8,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">17],arr_txtobj[class="num">16],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">8,class="num">0);
class=class="str">"cmt">//---
  Create_Label(class="num">0,arr_nmobj[class="num">18],arr_txtobj[class="num">17],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">9,class="num">0);
  Create_Label(class="num">0,arr_nmobj[class="num">19],arr_txtobj[class="num">18],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">9,class="num">0);
class=class="str">"cmt">//---
  if(show_progress)
    {
      Create_Label(class="num">0,arr_nmobj[class="num">20],arr_txtobj[class="num">19],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*class="num">10,class="num">0);
      Create_Label(class="num">0,arr_nmobj[class="num">21],arr_txtobj[class="num">20],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*class="num">10,class="num">0);
    }
}
class=class="str">"cmt">//____________________________________________________________________
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| CREATING_LABEL_OBJECT                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Create_Label(class="type">long   chrt_id,   class=class="str">"cmt">// chart id
                  class="type">class="kw">string lable_nm,  class=class="str">"cmt">// object name
                  class="type">class="kw">string rename,    class=class="str">"cmt">// displayed name
                  class="type">long   anchor,    class=class="str">"cmt">// anchor point
                  class="type">long   corner,    class=class="str">"cmt">// attachment corner
                  class="type">class="kw">string font_bsc,  class=class="str">"cmt">// font
                  class="type">int    font_size, class=class="str">"cmt">// font size
                  class="type">class="kw">color  font_clr,  class=class="str">"cmt">// font class="type">class="kw">color
                  class="type">int    x_dist,    class=class="str">"cmt">// X scale coordinate
                  class="type">int    y_dist,    class=class="str">"cmt">// Y scale coordinate
                  class="type">long   zorder)    class=class="str">"cmt">// priority
  {
  if(ObjectCreate(chrt_id,lable_nm,OBJ_LABEL,class="num">0,class="num">0,class="num">0)) class=class="str">"cmt">// creating object
    {
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TEXT,rename);            class=class="str">"cmt">// set name
      ObjectSetString(chrt_id,lable_nm,OBJPROP_FONT,font_bsc);          class=class="str">"cmt">// set font
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_COLOR,font_clr);        class=class="str">"cmt">// set font class="type">class="kw">color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ANCHOR,anchor);         class=class="str">"cmt">// set anchor point

「给可编辑文本对象定好锚点与层级」

在 MT5 里用 OBJ_EDIT 做面板输入框时,位置与交互属性得靠 ObjectSetInteger 一行行钉死。下面这段是标签对象收尾的属性设置,顺带给出了创建可编辑框的函数骨架。 OBJPROP_CORNER 决定控件贴哪个角(0=左上,1=左下,2=右上,3=右下);OBJPROP_XDISTANCE / YDISTANCE 是相对该角的像素偏移。把 OBJPROP_SELECTABLE 设 false,鼠标就不会误选中它,适合纯展示型标签。 OBJPROP_ZORDER 控制叠放优先级,数值大的盖在前面;OBJPROP_TOOLTIP 传 "\n" 可屏蔽悬停提示,避免干扰盯盘。外汇与贵金属波动剧烈、杠杆风险高,这类 UI 只辅助观察,不替代风控。 Create_Edit 的参数表覆盖了图表 ID、子窗口序号、宽高、字体与背景色等 16 个字段,复制进 EA 后改 lable_nm 与坐标就能快速复用。

MQL5 / C++
ObjectSetInteger(chrt_id,lable_nm,OBJPROP_CORNER,corner);      class=class="str">"cmt">// set attachment corner
ObjectSetInteger(chrt_id,lable_nm,OBJPROP_FONTSIZE,font_size);   class=class="str">"cmt">// set font size
ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XDISTANCE,x_dist);     class=class="str">"cmt">// set X coordinates
ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YDISTANCE,y_dist);     class=class="str">"cmt">// set Y coordinates
ObjectSetInteger(chrt_id,lable_nm,OBJPROP_SELECTABLE,class="kw">false);     class=class="str">"cmt">// unable to highlight the object, if FALSE
ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ZORDER,zorder);        class=class="str">"cmt">// Higher/lower priority
ObjectSetString(chrt_id,lable_nm,OBJPROP_TOOLTIP,"\n");          class=class="str">"cmt">// no tooltip, if "\n"
}
}
class=class="str">"cmt">//____________________________________________________________________
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| CREATING_EDIT_OBJECT                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Create_Edit(class="type">long   chrt_id,           class=class="str">"cmt">// chart id
                 class="type">int    nmb_win,           class=class="str">"cmt">// window(subwindow) index
                 class="type">class="kw">string lable_nm,          class=class="str">"cmt">// object name
                 class="type">class="kw">string text,              class=class="str">"cmt">// displayed text
                 class="type">long   corner,            class=class="str">"cmt">// attachment corner
                 class="type">class="kw">string font_bsc,          class=class="str">"cmt">// font
                 class="type">int    font_size,         class=class="str">"cmt">// font size
                 class="type">class="kw">color  font_clr,          class=class="str">"cmt">// font class="type">class="kw">color
                 class="type">class="kw">color  font_clr_brd,      class=class="str">"cmt">// font class="type">class="kw">color
                 class="type">int    xsize,             class=class="str">"cmt">// width
                 class="type">int    ysize,             class=class="str">"cmt">// height
                 class="type">int    x_dist,            class=class="str">"cmt">// X scale coordinate
                 class="type">int    y_dist,            class=class="str">"cmt">// Y scale coordinate
                 class="type">long   zorder,            class=class="str">"cmt">// priority
                 class="type">class="kw">color  clr)               class=class="str">"cmt">// background class="type">class="kw">color
{

常见问题

先在脚本入口做参数合法性校验,把空值、越界、非法品种名挡在跑数之前,避免中途断流。
把输出路径、刷新频率、品种列表、错误计数等放到全局变量,后续函数直接读,少传参更稳。
可以,小布能按你给的面板规则批量扫图表上的文本对象,标出背景冲突和坐标溢出并提示修正。
层级没设对,给对象设高 z-order 并锁锚点,就能压在蜡烛和指标线上方不被挡。
用相对坐标加固定锚点常量,并锁对象层级,缩放和翻页时位置都稳住。