点差以及订单价格与当前价格的距离

对于许多交易策略,尤其是那些基于短期交易的策略,关于当前价格的点差和偏离当前价格距离的信息,允许设置或修改订单是很重要的。所有这些特性均为 ENUM_SYMBOL_INFO_INTEGER 枚举的一部分,可通过 SymbolInfoInteger 函数获得。

标识符

说明

SYMBOL_SPREAD

点差大小(以点为单位)

SYMBOL_SPREAD_FLOAT

浮动点差的布尔符号

SYMBOL_TRADE_STOPS_LEVEL

设置止损、止盈和挂单时与当前价格的最小允许距离(以点为单位)

SYMBOL_TRADE_FREEZE_LEVEL

从当前价格(以点为单位)到冻结订单和头寸的距离

上表中,当前价格指的是 AskBid 价格,具体取决于所执行操作的特性。

保护性 Stop LossTake Profit 水平表明应执行平仓的时机。平仓通过与开仓相反的操作来执行。因此,对于 Ask 价格的买入订单,保护水平表示 Bid,对于 Bid 价格的卖出订单,保护水平表示 Ask。下达挂单时,以标准方式选择开盘价类型:买入订单 (Buy Stop, Buy Limit, Buy Stop Limit) 基于 Ask,卖出订单 (Sell Stop, Sell Limit, Sell Stop Limit) 基于 Bid。考虑到上述交易操作环境中的价格类型,应计算 SYMBOL_TRADE_STOPS_LEVEL 和SYMBOL_TRADE_FREEZE_LEVEL 特性的距离(以点数为单位)。

如果 SYMBOL_TRADE_STOPS_LEVEL 特性不为零,则在新水平比指定距离更接近当前价格时,禁止修改未结头寸的 Stop LossTake Profit 水平。同样,挂单的开盘价格与当前价格的差距也不可能小于 SYMBOL_TRADE_STOPS_LEVEL 的点数。

如果 SYMBOL_TRADE_FREEZE_LEVEL 特性不为零,则限制挂单或未结头寸在当前价格指定距离内的任何交易操作。对于挂单,若指定的开盘价格与当前价格之间的距离小于 SYMBOL_TRADE_FREEZE_LEVEL 的点数,就会触发冻结(同样,当前价格的类型为 AskBid,取决于其是买入还是卖出)。对于头寸,若 Stop LossTake Profit 水平接近当前价格就会触发冻结,因此对其测量是针对“相反的”价格类型进行的。

如果 SYMBOL_SPREAD_FLOAT 特性为 true,则 SYMBOL_SPREAD 特性不是交易品种规范的一部分,而是包含实际点差,其根据市场条件随每次调用动态变化。也可以在 MqlTick 结构中找到其作为 AskBid 之间的差额,这是通过调用 SymbolInfoTick来完成的。

脚本 SymbolFilterSpread.mq5 将允许你分析指定的特性。该脚本定义了一个自定义枚举 ENUM_SYMBOL_INFO_INTEGER_PART,该枚举仅包含ENUM_SYMBOL_INFO_INTEGER 中我们感兴趣的特性。

enum ENUM_SYMBOL_INFO_INTEGER_PART
{
   SPREAD_FIXED = SYMBOL_SPREAD,
   SPREAD_FLOAT = SYMBOL_SPREAD_FLOAT,
   STOPS_LEVEL = SYMBOL_TRADE_STOPS_LEVEL,
   FREEZE_LEVEL = SYMBOL_TRADE_FREEZE_LEVEL
};

新的枚举定义了 Property 输入参数,该参数指定将会分析四个特性中的哪一个。参数 UseMarketWatchShowPerSymbolDetails 以已知的方式控制该流程,就像前面的测试脚本一样。

input bool UseMarketWatch = true;
input ENUM_SYMBOL_INFO_INTEGER_PART Property = SPREAD_FIXED;
input bool ShowPerSymbolDetails = true;

为了使用 ArrayPrint 函数方便地显示每个交易品种的信息(每行中的特性名和值),定义了一个辅助结构体 SymbolDistance (仅在 ShowPerSymbolDetails 等于 true 时使用)。

struct SymbolDistance
{
   string name;
   int value;
};

OnStart 处理程序中,我们介绍了必要的对象和数组。

void OnStart()
{
   SymbolFilter f;                // filter object
   string symbols[];              // receiving array for names
   long values[];                 // receiving array for values
   SymbolDistance distances[];    // array to print
   MapArray<long,intstats;      // counters of specific values of the selected property
   ...

然后我们应用筛选器并用指定 Property 值填充接收数组,同时也进行排序。

   f.select(UseMarketWatch, (ENUM_SYMBOL_INFO_INTEGER)Propertysymbolsvaluestrue);
   const int n = ArraySize(symbols);
   if(ShowPerSymbolDetailsArrayResize(distancesn);
   ...

在一个循环中,如果需要的话,我们可以计算统计数据并填充 SymbolDistance 结构体。

   for(int i = 0i < n; ++i)
   {
      stats.inc(values[i]);
      if(ShowPerSymbolDetails)
      {
         distances[i].name = symbols[i];
         distances[i].value = (int)values[i];
      }
   }
   ...

最后,我们可以将结果输出到日志中。

   PrintFormat("===== Distances for %s symbols =====",
      (UseMarketWatch ? "Market Watch" : "all available"));
   PrintFormat("Total symbols: %d"n);
   
   PrintFormat("Stats per %s:"EnumToString((ENUM_SYMBOL_INFO_INTEGER)Property));
   stats.print();
   
   if(ShowPerSymbolDetails)
   {
      Print("Details per symbol:");
      ArrayPrint(distances);
   }
}

以下是使用默认设置运行脚本时得到的结果,这与点差分析一致。

===== Distances for Market Watch symbols =====
Total symbols: 13
Stats per SYMBOL_SPREAD:
    [key] [value]
[0]     0       2
[1]     2       3
[2]     3       1
[3]     6       1
[4]     7       1
[5]     9       1
[6]   151       1
[7]   319       1
[8]  3356       1
[9]  3400       1
Details per symbol:
       [name] [value]
[ 0] "USDJPY"       0
[ 1] "EURUSD"       0
[ 2] "USDCHF"       2
[ 3] "USDCAD"       2
[ 4] "GBPUSD"       2
[ 5] "AUDUSD"       3
[ 6] "XAUUSD"       6
[ 7] "SP500m"       7
[ 8] "NZDUSD"       9
[ 9] "USDCNH"     151
[10] "USDSEK"     319
[11] "BTCUSD"    3356
[12] "USDRUB"    3400

为了理解点差是浮动的(动态变化的)还是固定的,让我们使用不同的设置运行脚本:Property = SPREAD_FLOAT,ShowPerSymbolDetails = false。

===== Distances for Market Watch symbols =====
Total symbols: 13
Stats per SYMBOL_SPREAD_FLOAT:
    [key] [value]
[0]     1      13

根据该数据,市场报价中的所有交易品种均具有浮动点差(在 SYMBOL_SPREAD_FLOAT 中,key 键中的值 1 表示 true )。因此,如果我们用默认设置多次运行脚本,我们将会收到新的值(在市场开盘的情况下)。