文章 "开发基于订单簿的交易系统(第一部分):指标"

 

新文章 开发基于订单簿的交易系统(第一部分):指标已发布:

市场深度无疑是执行快速交易的一个非常重要的因素,特别是在高频交易(HFT)算法中。在本系列文章中,我们将探讨这种类型的交易事件,这些事件可以通过经纪商在许多可交易的交易品种上获得。我们将从一个指标开始,您可以在其中自定义直接显示在图表上的直方图的调色板、位置和大小。我们还将研究如何生成 BookEvent 事件,以在特定条件下测试指标。未来文章的其他可能主题包括如何存储价格分布数据以及如何在策略测试器中使用它。

让我们回顾一下市场深度是什么。这是一系列待执行的限价订单。这些订单代表了市场参与者的交易意图,通常不会导致实际交易。这是因为交易者有能力因各种原因取消之前下达的订单。这些原因可能包括市场状况的变化以及由此导致的失去以先前指定的价格和数量执行订单的兴趣。

函数 SymbolInfoInteger(_Symbol, SYMBOL_TICKS_BOOKDEPTH) 返回的值与订单簿的深度精确对应,并代表将填充要分析的价格水平的数组部分的一半。该数组的一半用于限价卖出订单的数量,另一半用于已下达的限价买入订单。根据文档,对于没有订单队列的资产,此属性的值为零。下图中可以看到一个示例,其中显示了深度为 10 的订单簿,其中显示了所有可用的价格水平。

示例:深度为 10 的订单簿

需要注意的是,深度可以从交易品种获得,而不一定从市场深度获得。使用 SymbolInfoInteger 函数足以获取属性值,而无需借助 OnBookEvent 处理程序或相关函数(如 MarketBookAdd )。当然,我们可以通过计算 OnBookEvent 处理函数填充的 MqlBookInfo 数组中的元素数量来得出相同的结果,我们稍后将详细探讨。

作者:Daniel Santos

 
我看不出为什么需要自定义符号。在标准符号本身上保存和重放书籍事件是完全可行的--无论是在常规图表的历史记录上(用于显示指标)还是在测试器中(用于 EA 测试)。
 

这篇文章很短,代码很少。让我们在下一部分中看看是否有必要增加第 1 部分、第 2 部分等。

SYMBOL_TICKS_BOOKDEPTH 给出了市场深度中显示的最大请求数。该属性给出的结果与计算 DOM 中的层数相同,这是不正确的。它给出的是最大数量,而不是精确数量。

您可以使用此脚本来计算:

//+------------------------------------------------------------------+
//|TestOnderBook.mq5
//|版权所有 2025 年,塞缪尔-马诺埃尔-德索萨 | |
//|https://www.mql5.com/zh/users/samuelmnl| |.
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Samuel Manoel De Souza"
#property link      "https://www.mql5.com/zh/users/samuelmnl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| 脚本程序启动功能|
//+------------------------------------------------------------------+
int OnInit(void)
  {
   MarketBookAdd(_Symbol);

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

   MarketBookRelease(_Symbol);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnTick(void)
  {

  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnBookEvent(const string& symbol)
  {
   double tick_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   MqlBookInfo book[];
   MarketBookGet(_Symbol, book);
   int total = ArraySize(book);
   if(total == 0)
     {
      Print("there is no order available on the book");
      ExpertRemove();
      return;
     }

   int buy_levels = 0, sell_levels = 0;
   int buy_gaps = 0, sell_gaps = 0, gaps = 0;
   for(int i = 0; i < total; i++)
     {
      Print("price: ", book[i].price, ", volume: ", book[i].volume, ", type: ", EnumToString(book[i].type));
      buy_levels += book[i].type == BOOK_TYPE_BUY ? 1 : 0;
      sell_levels += book[i].type == BOOK_TYPE_SELL ? 1 : 0;
      if(i > 0)
        {
         bool is_gap = fabs(book[i].price - book[i - 1].price) >= 2 * tick_size;
         gaps += is_gap ? 1 : 0;
         buy_gaps += is_gap && book[i].type == book[i - 1].type && book[i].type == BOOK_TYPE_BUY ? 1 : 0;
         sell_gaps += is_gap && book[i].type == book[i - 1].type && book[i].type == BOOK_TYPE_SELL ? 1 : 0;
        }
     }

   Print("max levels: ", SymbolInfoInteger(_Symbol, SYMBOL_TICKS_BOOKDEPTH));
   Print("levels: ", total);
   Print("buy levels: ", buy_levels);
   Print("sell levels: ", sell_levels);
   Print("gaps: ", gaps);
   Print("buy gaps: ", buy_gaps);
   Print("sell gap: ", sell_gaps);
   ExpertRemove();
  }
//+------------------------------------------------------------------+
 
本打算用该指标开发的交易系统怎么了?
 
Samuel Manoel De Souza #:

这篇文章很短,代码很少。我们将在下一部分看到是否有必要编写第 1 部分、第 2 部分等。

SYMBOL_TICKS_BOOKDEPTH 给出了市场深度中显示的最大请求数。该属性给出的结果与计算 DOM 层数的结果相同,这是不正确的。它给出的是最大数,而不是精确数。

您可以使用此脚本实现这一功能:

这篇文章太棒了!我还想写一篇关于堆栈的 TS,更准确地说,是关于引号堆栈的使用!