市场轮廓指标·综合运用
(3/3)·前 two 篇讲清概念与终端画法,这期用主算法把轮廓真正跑起来
「日内分时段轮廓怎么堆出来」
指标按图表周期把目标日期的日内K线全部取回,再逐根计算它在当日高低区间里的价格格子索引。每根K线先判定属于亚/欧/美哪个时段,对应数组里从 Low 到 High 覆盖的单元格计数器各加一,遍历完所有K线后,三个时段数组就各自记下了「该价格水平出现过多少根K线」。 所有时段数组长度一致,都等于当日最低价到最高价之间的价格点数,但只有实际触及的价位才会被填充。随后按计算出的时间坐标,用矩形对象把每个非空单元格画成等长线段——矩形两侧价格相同、时间跨度由 K线数×box_length×InpMultiplier 决定,线段颜色由输入参数指定。 在 EURUSD M30 上加载后,单日市场轮廓会直接铺在图上。若从前一日 POC(控制点)拉水平参考线,往往能看出「公允价」落在哪;这些位置可能充当支撑阻力或价格吸引点,当日缺口后续有概率回补到前日 POC 附近。外汇与贵金属波动剧烈,此类轮廓仅作概率参考,实盘须自担高风险。 下面这段是取数与时区归类的核心循环,逐行拆一下逻辑: MqlRates day_rate[]; —— 声明日线结构数组,存目标日 OHLC if(CopyRates(Symbol(), PERIOD_D1, day, 1, day_rate)==-1) return(prev_calculated); —— 取1根日线,失败则退出不重算 MqlRates bars_in_day[]; —— 存当日所有日内K线 datetime start_time=day_rate[0].time+PeriodSeconds(PERIOD_D1)-1; —— 日线结束时刻(含当日) datetime stop_time=day_rate[0].time; —— 日线开盘时刻 if(CopyRates(Symbol(), PERIOD_CURRENT, start_time, stop_time, bars_in_day)==-1) return(prev_calculated); —— 按当前周期取日内K线,失败退出 int size=ArraySize(bars_in_day); —— 日内K线总数 for(int i=0; i<size; i++) —— 逐根处理 int start_box=(int)((bars_in_day[i].low-low_day)/point); // 当前K线低价对应价格数组起始格 int stop_box =(int)((bars_in_day[i].high-low_day)/point); // 当前K线高价对应价格数组结束格 MqlDateTime bar_time; TimeToStruct(bars_in_day[i].time, bar_time); —— 拆出K线小时 uint hour=bar_time.hour; —— 当前小时 if(hour>=InpAmericaStartHour){ for(int ind=start_box; ind<stop_box; ind++) boxes_america[ind]++; } —— 美盘时段计数 else { if(hour>=InpEuropeStartHour && hour<InpAmericaStartHour) for(...) boxes_europe[ind]++; else for(...) boxes_asia[ind]++; } —— 欧盘或亚盘归类计数 后续三个 for 分别把亚/欧/美数组里计数>0 的格子画成矩形,time1/time2 按已画前序时段长度顺延,保证三段横向不重叠。
class="type">MqlRates day_rate[]; if(CopyRates(Symbol(), PERIOD_D1, day, class="num">1, day_rate)==-class="num">1) class="kw">return(prev_calculated); class="type">MqlRates bars_in_day[]; class="type">class="kw">datetime start_time=day_rate[class="num">0].time+PeriodSeconds(PERIOD_D1)-class="num">1; class="type">class="kw">datetime stop_time=day_rate[class="num">0].time; if(CopyRates(Symbol(), PERIOD_CURRENT, start_time, stop_time, bars_in_day)==-class="num">1) class="kw">return(prev_calculated); class="type">int size=ArraySize(bars_in_day); for(class="type">int i=class="num">0; i<size; i++) class="type">int start_box=(class="type">int)((bars_in_day[i].low-low_day)/point); class=class="str">"cmt">// index of the first cell of the price array corresponding to the Low price of the current i bar class="type">int stop_box =(class="type">int)((bars_in_day[i].high-low_day)/point); class=class="str">"cmt">// index of the last cell of the price array corresponding to the High price of the current i bar class="type">MqlDateTime bar_time; TimeToStruct(bars_in_day[i].time, bar_time); class="type">uint hour=bar_time.hour; if(hour>=InpAmericaStartHour) { for(class="type">int ind=start_box; ind<stop_box; ind++) boxes_america[ind]++; } else { if(hour>=InpEuropeStartHour && hour<InpAmericaStartHour) for(class="type">int ind=start_box; ind<stop_box; ind++) boxes_europe[ind]++; else for(class="type">int ind=start_box; ind<stop_box; ind++) boxes_asia[ind]++; } for(class="type">int ind=class="num">0; ind<day_size; ind++) { if(boxes_asia[ind]>class="num">0) { class="type">class="kw">double price=low_day+ind*point; class="type">class="kw">datetime time1=day_rate[class="num">0].time; class="type">class="kw">datetime time2=time1+boxes_asia[ind]*box_length*InpMultiplier; class="type">class="kw">string prefix=ExtPrefixUniq+"_"+day_prefix+"_Asia_"+StringFormat("%.5f", price); DrawBox(prefix, price, time1, time2, InpAsiaSession); } } for(class="type">int ind=class="num">0; ind<day_size; ind++) { if(boxes_europe[ind]>class="num">0) { class="type">class="kw">double price=low_day+ind*point; class="type">class="kw">datetime time1=day_rate[class="num">0].time+boxes_asia[ind]*box_length*InpMultiplier; class="type">class="kw">datetime time2=time1+boxes_europe[ind]*box_length*InpMultiplier; class="type">class="kw">string prefix=ExtPrefixUniq+"_"+day_prefix+"_Europe_"+StringFormat("%.5f", price); DrawBox(prefix, price, time1, time2, InpEuropeSession); } } for(class="type">int ind=class="num">0; ind<day_size; ind++) { if(boxes_america[ind]>class="num">0) {
美洲时段矩形是怎么画出来的
这段逻辑干的事很直接:在日低基础上按 ind 档位叠加 point 算出水平价 price,再把亚洲与欧洲已统计的箱数加上美洲箱数,乘上 box_length 和 InpMultiplier 换算出时间跨度,得到 time1 到 time2 的美洲时段区间。 prefix 用唯一前缀拼上日前缀和价格小数位(StringFormat 保留 5 位),保证每根水平带在图上不重名;随后调用 DrawBox 把矩形塞进图表背景层。 DrawBox 内部全是 MT5 图形对象的标准写法:OBJ_RECTANGLE 以 time1/price 为左上、time2/price 为右下,颜色由外部传入,线宽锁 1,STYLE_SOLID,OBJPROP_BACK 设 true 让它沉到 K 线底下不挡视线。tooltip 置空换行,避免悬停出脏字。 实盘里把 InpAmericaSession 换成你经纪商的美洲时段主色,加载后能在 H1 上看到每日美洲波动带自动铺开;外汇与贵金属杠杆高,这种时段带只标示概率区域,不构成方向判断。
class="type">class="kw">double price=low_day+ind*point; class="type">class="kw">datetime time1=day_rate[class="num">0].time+(boxes_asia[ind]+boxes_europe[ind])*box_length*InpMultiplier; class="type">class="kw">datetime time2=time1+boxes_america[ind]*box_length*InpMultiplier; class="type">class="kw">string prefix=ExtPrefixUniq+"_"+day_prefix+"_America_"+StringFormat("%.5f", price); DrawBox(prefix, price, time1, time2, InpAmericaSession); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Draw class="type">class="kw">color box | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void DrawBox(class="type">class="kw">string bar_prefix, class="type">class="kw">double price, class="type">class="kw">datetime time1, class="type">class="kw">datetime time2, class="type">class="kw">color clr) { ObjectCreate(class="num">0, bar_prefix, OBJ_RECTANGLE, class="num">0, time1, price, time2, price); ObjectSetInteger(class="num">0, bar_prefix, OBJPROP_COLOR, clr); ObjectSetInteger(class="num">0, bar_prefix, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(class="num">0, bar_prefix, OBJPROP_WIDTH, class="num">1); ObjectSetString(class="num">0, bar_prefix, OBJPROP_TOOLTIP, "\n"); ObjectSetInteger(class="num">0, bar_prefix, OBJPROP_BACK, true); }
◍ 把市场轮廓接进自己的交易回路
市场轮廓和 Tick 图的根本差异在于:它把价格、成交量、时间压进同一张分布里,让你直接读出公允价值区和主导方。MT5 自带的市场轮廓指标逻辑不复杂,熟悉之后可以拿它做底,再往上叠自定义过滤条件。 附件里的 MarketProfile.mq5 约 25.87 KB,编译无报错,但社区里有用户反馈在 MT5 图表加载后客户端会假死;作者复测称两个变体均正常,问题可能出在运行环境或周期选择上。外汇与贵金属波动剧烈、杠杆风险高,实盘前务必先在策略测试器跑不同周期验证稳定性。 真要落地,就下载这份代码,改一个参数——比如价值区占比从 70% 调到 80%——看分布重心怎么移,比读十篇概述都来得直接。