研究PrintFormat()并应用现成的示例·综合运用
「把账户风控参数打进日志」
做账户诊断时,杠杆、挂单上限和爆仓模式这三个值必须先在 MT5 日志里看清楚。下面三个函数直接把 ACCOUNT_LEVERAGE、ACCOUNT_LIMIT_ORDERS、ACCOUNT_MARGIN_SO_MODE 读出来并按统一格式打印,省得手动去账户窗口翻。 AccountLeveragePrint 里 header 写死为 "Leverage:",header_width 传 0 时自动取字符串长度+1,所以样本输出是 "Leverage: 1:100",说明该账户杠杆为 1:100。AccountLimitOrdersPrint 同理,样本给出 "Limit orders: 200",即最多允许 200 个活跃挂单。 StopOut 模式处理稍绕:先用 AccountInfoInteger 拿枚举值,再用 EnumToString 转字符串并砍掉前 21 个字符得到 "Percent" 或 "Money",转小写后首字母大写,样本输出 "StopOut mode: Percent" 表示按百分比强平。外汇和贵金属自带高杠杆高风险,这类参数看错可能让仓位在极端波动里被秒平,上机前先跑一遍核实。
class="type">void AccountLeveragePrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Leverage:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation PrintFormat("%*s%-*s1:%-s",indent,"",w,header,(class="type">class="kw">string)AccountInfoInteger(ACCOUNT_LEVERAGE)); class=class="str">"cmt">/* Sample output: Leverage: class="num">1:class="num">100 */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the maximum allowed class=class="str">"cmt">//| number of active pending orders class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountLimitOrdersPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Limit orders:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation PrintFormat("%*s%-*s%-s",indent,"",w,header,(class="type">class="kw">string)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS)); class=class="str">"cmt">/* Sample output: Limit orders: class="num">200 */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the mode for setting a minimal class=class="str">"cmt">//| accepted level of collateral in the journal class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountMarginSOModePrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the value of the mode for setting the minimum available collateral ENUM_ACCOUNT_STOPOUT_MODE so_mode=(ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); class=class="str">"cmt">//--- "Cut out" the mode name from the line obtained from enum class="type">class="kw">string mode=StringSubstr(EnumToString(so_mode),class="num">21); class=class="str">"cmt">//--- Convert the characters of the resulting line to lower case and replace the first letter from small to capital if(mode.Lower()) mode.SetChar(class="num">0,class="type">class="kw">ushort(mode.GetChar(class="num">0)-0x20)); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="StopOut mode:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation PrintFormat("%*s%-*s%-s",indent,"",w,header,mode); class=class="str">"cmt">/* Sample output: StopOut mode: Percent */ }
把账户交易权限打进日志
在 MT5 里排查 EA 不下单,第一步往往是确认账户本身有没有被禁交易。下面两个函数直接把 ACCOUNT_TRADE_ALLOWED 和 ACCOUNT_TRADE_EXPERT 的状态按对齐格式印到专家日志,肉眼扫一眼就知道是平台锁户还是 EA 被禁。 AccountTradeAllowedPrint 与 AccountTradeExpertPrint 都接收 header_width 和 indent 两个可选参数;当 header_width 传 0 时,字段宽度自动取表头字符串长度加 1,比如 "Trade allowed:" 长 14,宽度即 15。PrintFormat 用 "%*s%-*s%-s" 做缩进与左对齐,样本输出就是「Trade allowed: Yes」这种两列结构。 Margin 模式那一段更值得留意:它从 ACCOUNT_MARGIN_MODE 枚举值里用 StringSubstr 砍掉前 20 个字符(ENUM_ACCOUNT_MARGIN_MODE 前缀),再 Lower 转小写、首字母加 0x20 还原大写、下划线换空格。这套处理让你在日志里看到的是「retail netting」而不是一堆宏名,回测多账户时区分结算规则会快很多。外汇与贵金属杠杆高,账户 margin mode 不同,强平逻辑可能倾向差异很大,开实盘前建议先跑这段确认。
class="type">void AccountTradeAllowedPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Trade allowed:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- Depending on the class="type">bool value of the class="kw">property, pass the "Yes" or "No" line as a parameter PrintFormat("%*s%-*s%-s",indent,"",w,header,((class="type">bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) ? "Yes" : "No")); class=class="str">"cmt">/* Sample output: Trade allowed: Yes */ } class="type">void AccountTradeExpertPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Trade expert:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- Depending on the class="type">bool value of the class="kw">property, pass the "Yes" or "No" line as a parameter PrintFormat("%*s%-*s%-s",indent,"",w,header,((class="type">bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) ? "Yes" : "No")); class=class="str">"cmt">/* Sample output: Trade expert: Yes */ } class="type">void AccountMarginModePrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the value of the margin calculation mode ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); class=class="str">"cmt">//--- "Cut out" the mode name from the line obtained from enum class="type">class="kw">string mode=StringSubstr(EnumToString(margin_mode),class="num">20); class=class="str">"cmt">//--- Convert the characters of the resulting line to lower case and replace the first letter from small to capital if(mode.Lower()) mode.SetChar(class="num">0,class="type">class="kw">ushort(mode.GetChar(class="num">0)-0x20)); class=class="str">"cmt">//--- Replace all underscore characters with space in the resulting line
◍ 把账户属性打印成对齐日志
在 MT5 里排查账户规则时,最怕日志里一堆长短不一的字符串。下面这组函数把保证金模式、币种小数位、FIFO 与对冲权限统一成带缩进、定宽表头的格式,直接粘进 EA 的 OnStart 就能跑。 以 AccountCurrencyDigitsPrint 为例:header 写死为 "Currency digits:",若调用时 header_width 传 0,则表头宽度自动取字符串长度 +1,也就是 16;否则用外部指定宽度。PrintFormat 用 "%*s%-*s%-s" 控制缩进与左对齐,样本输出里币种小数位显示为 2,对应大多数外汇账户报价精度。 AccountFIFOClosePrint 读取 ACCOUNT_FIFO_CLOSE,布尔值映射成 "Yes"/"No"——样本输出 "FIFO close: No" 说明该账户不强制先进先出,可自由平仓。外汇与贵金属杠杆高,账户规则因券商而异,实盘前用这类打印确认环境,可能避免下单被拒的尴尬。 别让表头宽度写死 header_width 写 0 时函数自算长度,但如果你要和多行混排,手动传一个统一宽度(比如 20)才能让多行日志竖线对齐;否则 Retail hedging 那行会比 Currency digits 短一截,肉眼对不上。
StringReplace(mode,"_"," "); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Margin mode:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation PrintFormat("%*s%-*s%-s",indent,"",w,header,mode); class=class="str">"cmt">/* Sample output: Margin mode: Retail hedging */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the number of | class=class="str">"cmt">//| decimal places for an account currency | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountCurrencyDigitsPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Currency digits:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation PrintFormat("%*s%-*s%-s",indent,"",w,header,(class="type">class="kw">string)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS)); class=class="str">"cmt">/* Sample output: Currency digits: class="num">2 */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the flag indicating | class=class="str">"cmt">//| that positions can only be closed using the FIFO rule | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountFIFOClosePrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="FIFO close:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- Depending on the class="type">bool value of the class="kw">property, pass the "Yes" or "No" line as a parameter PrintFormat("%*s%-*s%-s",indent,"",w,header,((class="type">bool)AccountInfoInteger(ACCOUNT_FIFO_CLOSE) ? "Yes" : "No")); class=class="str">"cmt">/* Sample output: FIFO close: No */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the flag indicating | class=class="str">"cmt">//| opposite positions are allowed on a single symbol | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountHedgeAllowedPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) {
「把账户基础属性打进日志的三种写法」
在 MT5 里排查账户状态,最麻烦的是手敲 Print 每次格式都飘。下面这组函数把对冲许可、余额、信用额三个属性统一成带缩进和对齐头的日志输出,直接抄进 EA 的初始化段就能用。
对冲许可走的是整数布尔属性 ACCOUNT_HEDGE_ALLOWED,命中返回 true 就打 Yes,否则 No。样例输出里看到的是 Hedge allowed: Yes,说明当前账户类型支持同品种双向持仓——外汇和贵金属账户里这属性不一定都开,开之前先在策略测试器里跑一遍确认。
余额和信用额都依赖 ACCOUNT_CURRENCY_DIGITS 决定小数位,再用 ACCOUNT_CURRENCY 补后缀。样例里 Balance: 10015.00 USD 就是 digits=2 时的结果;若你的账户币种是 JPY,digits 通常为 0,输出就会变成 10015 JPY 不带小数。
header_width 传 0 时,列宽自动取头文本长度+1,所以多属性混打也不会错位。想自己验证,把三个 Print 函数依次调用,打开 MT5 专家日志看对齐效果即可。
class="type">class="kw">string header="Hedge allowed:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); PrintFormat("%*s%-*s%-s",indent,"",w,header,((class="type">bool)AccountInfoInteger(ACCOUNT_HEDGE_ALLOWED) ? "Yes" : "No")); class="type">void AccountBalancePrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class="type">class="kw">double ballance=AccountInfoDouble(ACCOUNT_BALANCE); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class="type">class="kw">string header="Balance:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,ballance,currency); } class="type">void AccountCreditPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class="type">class="kw">double credit=AccountInfoDouble(ACCOUNT_CREDIT); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class="type">class="kw">string header="Credit:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,credit,currency);
把账户浮盈和净值打进日志
在 MT5 的 EA 或脚本里,实时把账户层面的关键数字输出到「专家日志」,比盯着终端窗口更利于复盘。下面两个函数分别打印当前浮盈(ACCOUNT_PROFIT)与净值(ACCOUNT_EQUITY),都带缩进与表头宽度参数,方便你和多品种状态混排。 函数先用 AccountInfoDouble 取数值,再用 AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) 拿存款币种的小数位,最后用 AccountInfoString(ACCOUNT_CURRENCY) 取币种名。表头宽度若传 0,则自动按表头字符串长度 +1 处理。 日志格式串 "%*s%-*s%-.*f %-s" 里,第一个 * 吃缩进,第二个 * 吃表头宽,.* 吃小数位;示例输出里 Equity 一行曾打出 10015.00 USD,说明当时账户净值较初始入金有变动,外汇与贵金属杠杆账户下这种跳动很常见,属高风险环境下的正常浮值。
class="type">void AccountProfitPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the current profit, the number of decimal places for the symbol and its name class="type">class="kw">double profit=AccountInfoDouble(ACCOUNT_PROFIT); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Profit:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,profit,currency); } class="type">void AccountEquityPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the equity, the number of decimal places for the symbol and its name class="type">class="kw">double equity=AccountInfoDouble(ACCOUNT_EQUITY); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Equity:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,equity,currency); }
◍ 把账户保证金状态打进日志
做 EA 调试时,账户层面的保证金占用、可用保证金和保证金水平这三项是排查爆仓预警的第一手数据。下面这组函数直接调 AccountInfo 系列接口,把数值按统一格式输出到 MT5 专家日志,方便你对比下单前后的资金变化。
外汇和贵金属杠杆高,保证金水平掉到经纪商强平线附近时可能瞬间砍仓,盯日志不能替代实时监控。
AccountMarginPrint 取 ACCOUNT_MARGIN 得到已用保证金,样例里输出为 Margin: 0.00 USD,说明当时无持仓占用。AccountMarginFreePrint 取 ACCOUNT_MARGIN_FREE,样例给出 Margin free: 10015.00 USD,也就是账户还有万余单位本位币可开仓。两者都靠 AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) 拿小数位,避免 USD 类货币硬编码 2 位而出错。
格式化核心在 PrintFormat 的 %*s%-*s%-.*f %-s:前两个星号吃缩进和表头宽,.*f 动态填 digits 控制金额精度。表头宽传 0 时自动取 header.Length()+1,你批量打印多项属性时对不齐的问题就解决了。
class="type">void AccountMarginPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the reserved collateral, the number of decimal places for the symbol and its name class="type">class="kw">double margin=AccountInfoDouble(ACCOUNT_MARGIN); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Margin:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin,currency); class=class="str">"cmt">/* Sample output: Margin: class="num">0.00 USD */ } class=class="str">"cmt">//+--------------------------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the free funds, | class=class="str">"cmt">//| available for opening a position on an account in a deposit currency, in the journal | class=class="str">"cmt">//+--------------------------------------------------------------------------------------+ class="type">void AccountMarginFreePrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the reserved collateral, the number of decimal places for the symbol and its name class="type">class="kw">double margin_free=AccountInfoDouble(ACCOUNT_MARGIN_FREE); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Margin free:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_free,currency); class=class="str">"cmt">/* Sample output: Margin free: class="num">10015.00 USD */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description | class=class="str">"cmt">//| of the collateral level on an account in % | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountMarginLevelPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Margin level:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width);
「把爆仓线与电话线打进日志」
MT5 账户里有两个红线数字最该被盯死:Margin Call 和 Stop Out。前者是券商要求补保证金的垫付阈值,后者是强平最亏仓位的点位,二者在账户信息里分别由 ACCOUNT_MARGIN_SO_CALL 与 ACCOUNT_MARGIN_SO_SO 给出。 下面这段函数把 Margin Call 直接打印到专家日志。先取水平值、账户币种小数位和币种名;若止损模式是百分比(ACCOUNT_STOPOUT_MODE_PERCENT),就把币种字符串改成 "%" 且小数位锁死为 2,否则沿用账户货币的小数精度。示例输出里能看到 "Margin Call: 50.00 %",说明该账户按百分比模式、阈值 50% 触发追缴。 Stop Out 函数结构完全一致,只是换成读 ACCOUNT_MARGIN_SO_SO。实盘中外汇与贵金属杠杆高,Stop Out 一旦触发便是被动砍仓,复制这两段到 EA 初始化里跑一次,能在回测或模拟盘直观看到自己账户的真实强平边界。
class="type">void AccountMarginSOCallPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the MarginCall level values, the number of decimal places for the symbol and its name class="type">class="kw">double margin_so_call=AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- If the level of collateral for MarginCall is calculated as %, class=class="str">"cmt">//--- specify &class="macro">#x27;currency&class="macro">#x27; in % rather than in account currency, while &class="macro">#x27;digits&class="macro">#x27; will be equal to class="num">2 if(AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE)==ACCOUNT_STOPOUT_MODE_PERCENT) { currency="%"; digits=class="num">2; } class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header class="type">class="kw">string + class="num">1 class="type">class="kw">string header="Margin Call:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value obtained above PrintFormat("%*s%-*s%-.*f %s",indent,"",w,header,digits,margin_so_call,currency); class=class="str">"cmt">/* Sample output: Margin Call: class="num">50.00 % */ } class="type">void AccountMarginStopOutPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the StopOut level values, the number of decimal places for the symbol and its name class="type">class="kw">double margin_so_so=AccountInfoDouble(ACCOUNT_MARGIN_SO_SO); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- If the level of collateral for StopOut is calculated as %, class=class="str">"cmt">//--- specify &class="macro">#x27;currency&class="macro">#x27; in % rather than in account currency, while &class="macro">#x27;digits&class="macro">#x27; will be equal to class="num">2 if(AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE)==ACCOUNT_STOPOUT_MODE_PERCENT) {
把账户保证金占用打进日志的对齐写法
做账户监控时,止损爆仓线(Stop Out)和挂单预留保证金是两个常被忽略的数值。下面这段函数把 ACCOUNT_MARGIN_SO_SO 取出来,按账户币种小数位格式化后输出,样例里能看到 30.00 % 这种带百分比的结果,说明该账户止损线设在 30% 保证金占比。 currency="%"; digits=2; } //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Margin Stop Out:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Print the property value in the log with a header with the required width and indentation //--- To display the value correctly, replace the asterisk in the format line with the digits value obtained above PrintFormat("%*s%-*s%-.*f %s",indent,"",w,header,digits,margin_so_so,currency); /* Sample output: Margin Stop Out: 30.00 % */ } //+------------------------------------------------------------------+
| // | Print a description of the funds |
|---|---|
| // | reserved on the account for security |
| // | of a guarantee amount for all pending orders |
//+------------------------------------------------------------------+ void AccountMarginInitialPrint(const uint header_width=0,const uint indent=0) { //--- Get the amount of the reserved funds, the number of decimal places for the symbol and its name double margin_initial=AccountInfoDouble(ACCOUNT_MARGIN_INITIAL); int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); string currency=AccountInfoString(ACCOUNT_CURRENCY); //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Margin initial:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Print the property value in the log with a header with the required width and indentation //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_initial,currency); /* Sample output: Margin initial: 0.00 USD */ } //+------------------------------------------------------------------+
| // | Print a description of the funds |
|---|---|
| // | reserved on the account for security |
| // | of the min amount of all open positions |
//+------------------------------------------------------------------+ void AccountMarginMaintenancePrint(const uint header_width=0,const uint indent=0) { //--- Get the amount of the reserved funds, the number of decimal places for the symbol and its name double margin_maintenance=AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE); int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); string currency=AccountInfoString(ACCOUNT_CURRENCY); //--- Define the header text and the width of the header field 上面三个 Print 函数分别对应止损线、挂单初始保证金、持仓维护保证金。AccountMarginInitialPrint 的样例输出是 0.00 USD,意味着当前无挂单占用;若你有未成交限价单,这里就会跳出具体预留金额。 header_width 传 0 时,列宽自动取表头字符串长度加 1,所以你换长表头也不用手动算对齐。外汇和贵金属杠杆高,维护保证金随价格波动可能快速变化,建议把这些函数接进 EA 的 OnTimer,每隔几秒打一次日志观察占用趋势。
currency="%"; digits=class="num">2; } class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Margin Stop Out:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value obtained above PrintFormat("%*s%-*s%-.*f %s",indent,"",w,header,digits,margin_so_so,currency); class=class="str">"cmt">/* Sample output: Margin Stop Out: class="num">30.00 % */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the funds | class=class="str">"cmt">//| reserved on the account for security | class=class="str">"cmt">//| of a guarantee amount for all pending orders | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountMarginInitialPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the amount of the reserved funds, the number of decimal places for the symbol and its name class="type">class="kw">double margin_initial=AccountInfoDouble(ACCOUNT_MARGIN_INITIAL); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Margin initial:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_initial,currency); class=class="str">"cmt">/* Sample output: Margin initial: class="num">0.00 USD */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the funds | class=class="str">"cmt">//| reserved on the account for security | class=class="str">"cmt">//| of the min amount of all open positions | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountMarginMaintenancePrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the amount of the reserved funds, the number of decimal places for the symbol and its name class="type">class="kw">double margin_maintenance=AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field
◍ 把账户净值结构打进日志的写法
想在 MT5 专家日志里整齐地列出账户维持保证金、总资产、总负债,核心是用 AccountInfoDouble 取数值、用 AccountInfoInteger 取币种小数位、用 AccountInfoString 取币种名,再交给 PrintFormat 统一排版。 下面三个函数分别打印 Margin maintenance、Assets、Liabilities。当 header_width 传 0 时,字段宽度自动取表头字符串长度 +1,避免手工对齐;indent 控制左侧缩进空格数。 格式串 "%*s%-*s%-.*f %-s" 里,第一个 * 吃 indent 输出空缩进,第二个 * 吃 w 控制表头列宽,.* 吃 digits 决定浮点小数位。样例中三种属性默认输出均为 "0.00 USD",说明新账户或未持仓时这些项可能倾向为零。 外汇与贵金属保证金波动剧烈,账户负债项在穿仓情形下可能变为正数,日志监控仅作辅助,不等于风险可控。
class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Margin maintenance:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_maintenance,currency); class=class="str">"cmt">/* Sample output: Margin maintenance: class="num">0.00 USD */ } class=class="str">"cmt">//+----------------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the current asset size on the account in the journal| class=class="str">"cmt">//+----------------------------------------------------------------------------+ class="type">void AccountAssetsPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the current asset size on the account, the number of decimal places for the symbol and its name class="type">class="kw">double assets=AccountInfoDouble(ACCOUNT_ASSETS); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Assets:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,assets,currency); class=class="str">"cmt">/* Sample output: Assets: class="num">0.00 USD */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description | class=class="str">"cmt">//| of the current liabilities on the account | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountLiabilitiesPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the current liabilities on the account, the number of decimal places for the symbol and its name class="type">class="kw">double liabilities=AccountInfoDouble(ACCOUNT_LIABILITIES); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Liabilities:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,liabilities,currency); /* Sample output: Liabilities: class="num">0.00 USD
「把账户冻结佣金和登录信息打进日志」
在 MT5 的 EA 调试阶段,直接把账户层面的关键属性打印到“专家”标签页,比反复切去账户总览看要快。下面这段封装了三个函数,分别输出冻结佣金、客户名、交易服务器名,且都支持缩进与表头宽度参数,方便你做多级对齐的日志树。
冻结佣金来自 ACCOUNT_COMMISSION_BLOCKED,这是券商在挂单或对冲占用保证金时可能锁住的一笔费用,外汇与贵金属品种在高波动时段出现该数值非零的概率会上升,属于高风险环境下的隐性成本。示例输出为 Comission blocked: 0.00 USD,说明当前演示账户没有冻结佣金。
客户名与服务器名分别走 ACCOUNT_NAME 和 ACCOUNT_SERVER,输出如 Name: Artem 与 Server: MetaQuotes-Demo。把这三个打印函数塞进 OnTick 或初始化里,你能在几秒内确认 EA 正连着正确的账户和服务器,而不是默默跑在另一个环境。
class="type">void AccountComissionBlockedPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Get the current blocked commissions on the account, the number of decimal places for the symbol and its name class="type">class="kw">double commission_blocked=AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED); class="type">int digits=(class="type">int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS); class="type">class="kw">string currency=AccountInfoString(ACCOUNT_CURRENCY); class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header class="type">class="kw">string + class="num">1 class="type">class="kw">string header="Comission blocked:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation class=class="str">"cmt">//--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,commission_blocked,currency); } class="type">void AccountNamePrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class="type">class="kw">string header="Name:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_NAME)); } class="type">void AccountServerPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class="type">class="kw">string header="Server:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_SERVER)); }
把账户属性整齐打进日志
做账户巡检脚本时,最烦的就是终端日志里一堆属性挤成一团,肉眼对不齐。下面两个小函数专门解决『账户币种』和『券商公司名』的格式化输出,靠 header_width 和 indent 两个参数控制列宽与缩进。
AccountCurrencyPrint 默认表头写 "Currency:",若 header_width 传 0,则列宽自动取表头字符数 +1;调用 AccountInfoString(ACCOUNT_CURRENCY) 抓取当前账户结算币种,例如样本输出就是 Currency: USD。AccountCompanyPrint 逻辑完全一致,只是换成 ACCOUNT_COMPANY,样本可能输出 Company: MetaQuotes Software Corp.。
真正把所有属性串起来的是 AccountInfoPrint:它先 Print 出 "AccountInfoInteger properties:" 分段,再依次调 Login、TradeMode、Leverage 等十余个打印子函数;随后切到 "AccountInfoDouble properties:" 段,列 Balance、Credit、Equity、Margin 等浮点属性。你在 MT5 里挂一段 EA 初始化时跑一次 AccountInfoPrint(),就能在日志里拿到一份带缩进的账户全景,比手动翻终端选项快得多。外汇与贵金属保证金交易杠杆风险高,这类巡检只帮你看清账户状态,不预示任何行情方向。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of a deposit currency name | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountCurrencyPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Currency:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_CURRENCY)); class=class="str">"cmt">/* Sample output: Currency: USD */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print a description of the company name, | class=class="str">"cmt">//| serving an account, into the journal | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountCompanyPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Define the header text and the width of the header field class=class="str">"cmt">//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + class="num">1 class="type">class="kw">string header="Company:"; class="type">uint w=(header_width==class="num">0 ? header.Length()+class="num">1 : header_width); class=class="str">"cmt">//--- Print the class="kw">property value in the log with a header with the required width and indentation PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_COMPANY)); class=class="str">"cmt">/* Sample output: Company: MetaQuotes Software Corp. */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Print account data into the journal | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void AccountInfoPrint(const class="type">uint header_width=class="num">0,const class="type">uint indent=class="num">0) { class=class="str">"cmt">//--- Display descriptions of integer properties according to their location in ENUM_ACCOUNT_INFO_INTEGER Print("AccountInfoInteger properties:"); AccountLoginPrint(header_width,indent); AccountTradeModePrint(header_width,indent); AccountLeveragePrint(header_width,indent); AccountLimitOrdersPrint(header_width,indent); AccountMarginSOModePrint(header_width,indent); AccountTradeAllowedPrint(header_width,indent); AccountTradeExpertPrint(header_width,indent); AccountMarginModePrint(header_width,indent); AccountCurrencyDigitsPrint(header_width,indent); AccountFIFOClosePrint(header_width,indent); AccountHedgeAllowedPrint(header_width,indent); class=class="str">"cmt">//--- Display descriptions of real properties according to their location in class="type">ENUM_ACCOUNT_INFO_DOUBLE Print("AccountInfoDouble properties:"); AccountBalancePrint(header_width,indent); AccountCreditPrint(header_width,indent); AccountProfitPrint(header_width,indent); AccountEquityPrint(header_width,indent); AccountMarginPrint(header_width,indent); AccountMarginFreePrint(header_width,indent); AccountMarginLevelPrint(header_width,indent); AccountMarginSOCallPrint(header_width,indent);
◍ 把账户属性一次性打印到日志
在 MT5 里排查保证金异常或核对账户状态时,逐个调 AccountInfoInteger / Double / String 太碎。上面这段把整组属性封装进一个 AccountInfoPrint 函数,OnStart 里只传两个参数就能在日志刷出全量账户档案。 调用写的是 AccountInfoPrint(20,2):第一个数 20 是字段名对齐宽度,第二个 2 是缩进空格数。改这两个值就能控制日志排版,接宽屏显示器时拉到 30 会更易读。 样例输出里有一组值得盯的数:杠杆 1:100、StopOut 模式为 Percent、Margin Call 50.00%、Margin Stop Out 30.00%。这意味着当权益 / 保证金跌破 30% 时平台会强平,外汇和贵金属波动大,这个阈值随时可能在一根大阳线里被触到。 函数内部依次跑了 StopOut、Initial、Maintenance、Assets、Liabilities、ComissionBlocked 等子打印,再切到字符串属性打印 Name / Server / Currency / Company。你直接把这段贴进 EA 的 OnStart 测一下,能立刻看到自己 demo 或实盘账号的真实配置。
AccountMarginStopOutPrint(header_width,indent); AccountMarginInitialPrint(header_width,indent); AccountMarginMaintenancePrint(header_width,indent); AccountAssetsPrint(header_width,indent); AccountLiabilitiesPrint(header_width,indent); AccountComissionBlockedPrint(header_width,indent); class=class="str">"cmt">//--- Display descriptions of class="type">class="kw">string properties according to their location in ENUM_ACCOUNT_INFO_STRING Print("AccountInfoString properties:"); AccountNamePrint(header_width,indent); AccountServerPrint(header_width,indent); AccountCurrencyPrint(header_width,indent); AccountCompanyPrint(header_width,indent); } class="type">void OnStart() { class=class="str">"cmt">//--- Print trading account properties in the journal AccountInfoPrint(class="num">20,class="num">2); class=class="str">"cmt">/* Sample output: AccountInfoInteger properties: Login: class="num">68008618 Trade mode: Demo Leverage: class="num">1:class="num">100 Limit orders: class="num">200 StopOut mode: Percent Trade allowed: Yes Trade expert: Yes Margin mode: Retail hedging Currency digits: class="num">2 FIFO close: No Hedge allowed: Yes AccountInfoDouble properties: Balance: class="num">10015.00 USD Credit: class="num">0.00 USD Profit: class="num">2.11 USD Equity: class="num">10017.11 USD Margin: class="num">25.61 USD Margin free: class="num">9991.50 USD Margin level: class="num">39114.06 % Margin Call: class="num">50.00 % Margin Stop Out: class="num">30.00 % Margin initial: class="num">0.00 USD Margin maintenance: class="num">0.00 USD Assets: class="num">0.00 USD Liabilities: class="num">0.00 USD Comission blocked: class="num">0.00 USD AccountInfoString properties: Name: Artem Server: MetaQuotes-Demo Currency: USD Company: MetaQuotes Software Corp. */ }
「从分时属性开始的时间(以毫秒为单位)」
MqlTick 结构旨在及时获得当前价格的最需要数据。 MqlTick类型的变量允许在 SymbolInfoTick() 函数的一次调用中获得Ask、Bid、Last和Volume值。此外,该结构还包含以毫秒为单位的分时时间。时间值在<s1>long</s1>类型的变量中给定。换句话说,当在日志中打印这些数据时,我们只会得到一个特定的数字——自1970年1月1日以来经过的毫秒数。要以人类可读的时间格式显示这些数据,您需要将此数字转换为日期,并在生成的日期上添加毫秒。 要获得带秒的日期,需要将毫秒数除以1000,要获得毫秒的时间,需要将日期的毫秒数的余数除以1000。 一般来说,它看起来是这样的: 让我们编写一个函数,它以毫秒为单位接收时间,并以“日期 时间.毫秒”格式显示: 要直接获取以毫秒为单位的日期和时间并将其显示在日记账中,可以使用以下函数: [CODE] <span class="keyword">void</span> <span class="functions">OnStart</span>() { <span class="comment">//---</span> <span class="predefines">MqlTick</span> tick; <span class="keyword">if</span>(<span class="functions">SymbolInfoTick</span>(<span class="functions">Symbol</span>(),tick)) { <span class="keyword">string</span> time_str=<span class="keyword">string</span>((<span class="keyword">datetime</span>)tick.time_msc / <span class="number">1000</span>)+<span class="string">"."</span>+<span class="keyword">string</span>(tick.time_msc % <span class="number">1000</span>); <span class="functions">Print</span>(<span class="string">"time_str="</span>,time_str); } <span class="comment">/* Sample output: time_str=2023.07.10 18:49:36.463 */</span> } <span class="comment">//+------------------------------------------------------------------+</span> <span class="comme
别急着下结论
PrintFormat() 适合直接把账户属性按格式打到日志,但文本若要在程序多个位置复用,它就不够用了。StringFormat() 与之不同,返回的是格式化后的字符串,不强制输出到日志,可在 EA 不同模块拼装使用。 下一篇会专门拆 StringFormat() 的调用特征与坑点,当前先记住:需要“一次性看日志”用 PrintFormat,需要“到处拼字符串”留好 StringFormat 的接口。 外汇与贵金属自动化涉及高杠杆与滑点风险,任何输出函数只解决可读性问题,不替代策略本身的胜率验证。