用于构建交易品种图表的价格类型

MetaTrader 5 价格图表上的柱线可以根据 BidLast 价格绘制,绘制类型在每个金融工具的规范中指明。MQL 程序可以通过对 SYMBOL_CHART_MODE 特性调用 SymbolInfoInteger 函数来找到这一特征。返回值为 ENUM_SYMBOL_CHART_MODE 枚举之一。

标识符

说明

SYMBOL_CHART_MODE_BID

柱线按买入价格构建

SYMBOL_CHART_MODE_LAST

柱线按最新价格构建

具有 Last 价格的模式用作在交易所交易的交易品种(与分散的外汇市场相反),而 市场深度 可用于这种交易品种。可依据 SYMBOL_TICKS_BOOKDEPTH 特性可以找到市场深度。

SYMBOL_CHART_MODE 的特性对于调整所构建的指标或策略的信号很有用,例如,在图表的 Last 价格;而订单将“以市价”执行,即,根据方向以 AskBid 价格执行。

此外,在计算 自定义金融工具的柱线时,价格类型也是必需的:如果价格类型取决于标准交易品种,则按价格类型考虑其设置是有意义的。若用户将 合成金融工具 的公式输入 Custom Symbol 窗口(通过选择 Symbols 对话框中的 Create Symbol 打开),可以根据所使用的各个标准交易品种的规范来选择价格类型。但是,当计算算法在 MQL 程序中形成时,精确地说,其负责正确选择价格类型。

首先,让我们收集使用 BidLast 价格的统计数据,以构建特定账户的图表。这就是脚本 SymbolStatsByPriceType.mq5 的功能。

const bool MarketWatchOnly = false;
   
void OnStart()
{
   const int n = SymbolsTotal(MarketWatchOnly);
   int k = 0;
   // loop through all available characters
   for(int i = 0i < n; ++i)
   {
      if(SymbolInfoInteger(SymbolName(iMarketWatchOnly), SYMBOL_CHART_MODE)
          == SYMBOL_CHART_MODE_LAST)
      {
         k++;
      }
   }
   PrintFormat("Symbols in total: %d"n);
   PrintFormat("Symbols using price types: Bid=%d, Last=%d"n - kk);
}

用不同账户上尝试运行该脚本(有些账户可能没有股票交易品种)。结果如下所示:

   Symbols in total: 52304
   Symbols using price types: Bid=229, Last=52075

一个更实际的示例是指标 SymbolBidAskChart.mq5,其设计用于根据指定类型的价格绘制柱线形式。这将允许你将使用 SYMBOL_CHART_MODE 特性中价格构建的蜡烛图与其他价格类型的柱线进行比较。例如,你可以在金融工具图表的 Last 价格处看到 Bid 价格的柱线或者得到 Ask 价格的柱线,而标准终端图表不支持这些功能。

作为新指标的依据,我们将采用一个现成指标 IndDeltaVolume.mq5,如 等待数据和管理可见性一节所述。在这个指标中,我们下载了一定数量柱线 BarCount 的分时报价历史,并计算了交易量的增量,即分别买入和卖出的交易量。在新指标中,我们只需要将计算算法替换为基于每根柱线内分时报价搜索 OpenHighLowClose 价格。

指标设置包括显示在主窗口中的四个缓冲区和一根柱线图 (DRAW_BARS)。

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   1
   
#property indicator_type1   DRAW_BARS
#property indicator_color1  clrDodgerBlue
#property indicator_width1  2
#property indicator_label1  "Open;High;Low;Close;"

选择显示为柱线是为了在主蜡烛图上运行时更容易阅读,同时显示每根柱线的两个版本。

新增的 ChartMode 输入参数允许用户从三种价格类型中选择一种(注意,与 ENUM_SYMBOL_CHART_MODE 中的标准元素集相比,Ask 是我们添加的元素)。

enum ENUM_SYMBOL_CHART_MODE_EXTENDED
{
   _SYMBOL_CHART_MODE_BID,  // SYMBOL_CHART_MODE_BID
   _SYMBOL_CHART_MODE_LAST// SYMBOL_CHART_MODE_LAST
   _SYMBOL_CHART_MODE_ASK,  // SYMBOL_CHART_MODE_ASK*
};
   
input int BarCount = 100;
input COPY_TICKS TickType = INFO_TICKS;
input ENUM_SYMBOL_CHART_MODE_EXTENDED ChartMode = _SYMBOL_CHART_MODE_BID;

以前的 CalcDeltaVolume 类将其名称改为 CalcCustomBars,但几乎保持不变。不同之处包括一组新的四个缓冲区和 chartMode 字段,该字段在构造函数中由输入变量 ChartMode 初始化。

class CalcCustomBars
{
   const int limit;
   const COPY_TICKS tickType;
   const ENUM_SYMBOL_CHART_MODE_EXTENDED chartMode;
   
   double open[];
   double high[];
   double low[];
   double close[];
   ...
public:
   CalcCustomBars(
      const int bars,
      const COPY_TICKS type,
      const ENUM_SYMBOL_CHART_MODE_EXTENDED mode)
      : limit(bars), tickType(type), chartMode(mode) ...
   {
      // register arrays as indicator buffers
      SetIndexBuffer(0open);
      SetIndexBuffer(1high);
      SetIndexBuffer(2low);
      SetIndexBuffer(3close);
      const static string defTitle[] = {"Open;High;Low;Close;"};
      const static string types[] = {"Bid""Last""Ask"};
      string name = defTitle[0];
      StringReplace(name";"types[chartMode] + ";");
      PlotIndexSetString(0PLOT_LABELname);
      IndicatorSetInteger(INDICATOR_DIGITS_Digits);
   }
   ...

根据 chartMode 的模式,辅助方法 price 可从每条分时报价返回特定的价格类型。

protected:
   double price(const MqlTick &tconst
   {
      switch(chartMode)
      {
      case _SYMBOL_CHART_MODE_BID:
         return t.bid;
      case _SYMBOL_CHART_MODE_LAST:
         return t.last;
      case _SYMBOL_CHART_MODE_ASK:
         return t.ask;
      }
      return 0// error
   }
   ...

使用 price 方法,我们可以很容易地实现对主计算方法calc 的修改,该方法用于根据该柱线的 ticks 数组来填充第 i 根柱线的缓冲区。

   void calc(const int iconst MqlTick &ticks[], const int skip = 0)
   {
      const int n = ArraySize(ticks);
      for(int j = skipj < n; ++j)
      {
         const double p = price(ticks[j]);
         if(open[i] == EMPTY_VALUE)
         {
            open[i] = p;
         }
         
         if(p > high[i] || high[i] == EMPTY_VALUE)
         {
            high[i] = p;
         }
         
         if(p < low[i])
         {
            low[i] = p;
         }
         
         close[i] = p;
      }
   }

其余的源代码片段及其工作原理对应于 IndDeltaVolume.mq5 的说明。

OnInit 处理程序中,我们还显示了图表的当前价格类型,如果用户决定在缺少 Last的情况下基于该金融工具的 Last 价格类型构建一个指标,系统将会返回警告。

int OnInit()
{
   ...
   ENUM_SYMBOL_CHART_MODE mode =
      (ENUM_SYMBOL_CHART_MODE)SymbolInfoInteger(_SymbolSYMBOL_CHART_MODE);
   Print("Chart mode: "EnumToString(mode));
   
   if(mode == SYMBOL_CHART_MODE_BID
      && ChartMode == _SYMBOL_CHART_MODE_LAST)
   {
      Alert("Last price is not available for "_Symbol);
   }
   
   return INIT_SUCCEEDED;
}

下面是基于 Last 价格图表绘图模式的工具屏幕截图;价格类型 Bid 的指标位于图表上方。

最新价格图表上带有买入价柱线的指标
最新价格图表上带有买入价柱线的指标

观察普通 Bid 价格图表上叠加的 Ask 价格柱线也很有趣。

在买入价格图表上叠加卖出价格柱线的指标
在买入价格图表上叠加卖出价格柱线的指标

在低流动性时段,当点差扩大时,你可以看到 BidAsk 价格图表之间的巨大差异。