市场轮廓指标·综合运用
📊

市场轮廓指标·综合运用

(3/3)·前 two 篇讲清概念与终端画法,这期用主算法把轮廓真正跑起来

案例拆解新手友好 第 3/3 篇
很多人把市场轮廓当成普通指标等信号,结果在 M30 上盯着 POC 线盲目抄底摸顶。轮廓不发声,它只陈列买卖双方在某价停留多久,误读价值区往往比不看更糟。

「日内分时段轮廓怎么堆出来」

指标按图表周期把目标日期的日内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 按已画前序时段长度顺延,保证三段横向不重叠。

MQL5 / C++
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 上看到每日美洲波动带自动铺开;外汇与贵金属杠杆高,这种时段带只标示概率区域,不构成方向判断。

MQL5 / C++
  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%——看分布重心怎么移,比读十篇概述都来得直接。

让小布替你画每日轮廓
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到当日的初始平衡、价值区与 POC,你只管判断谁在控盘。

常见问题

首日一小时奠定全天多空共识基础,两个 30 分钟柱构成的区间最能反映日内与其他时段交易者的 early 博弈,后续扩展都以此为锚。
小布盯盘自动按品种聚合 tick 成轮廓块,价值区 70% 边界和买/卖尾直接标在图上,省去手动量柱高的重复劳动。
POC 贴近区间中部时,该价位接受度最高,倾向成为强支撑或阻力;若偏向上沿,可能暗示买方急于追价。
短尾代表其他时段资金进攻干脆,方向延续概率大;长尾说明试探后仍被拒,边界有效性反而更强。