如何准备 MetaTrader 5 报价用于其他应用程序·进阶篇
跑脚本前先卡死错误参数
写 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 或脚本,故意把起止日期填反,能立刻看到错误框弹出并停止,验证拦截是否生效。
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 长度试一次越界就知道数组边界多重要。
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 数组准备绘制。
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 就能直观看到右列整体右移,验证布局是否如预期贴合底板。外汇与贵金属行情高波动,面板数值仅作本地诊断,不代表任何方向暗示。
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 里肉眼确认层级。
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 与坐标就能快速复用。
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 {