创建和删除自定义交易品种

要使用自定义交易品种,首先需要的两个函数是 CustomSymbolCreateCustomSymbolDelete

bool CustomSymbolCreate(const string name, const string path = "", const string origin = NULL)

该函数在指定的组 (path) 中创建具有指定名称 (name) 的自定义交易品种,如果需要,还可以使其具有示例交易品种的特性 ― 示例交易品种的名称可以在 origin 参数中指定。

name 参数应该是一个简单的标识符,不包含层级结构。如有必要,应在参数 path 中指定一个或多个必需的组(子文件夹)级别,分隔符为反斜杠 '\'(此处不支持正斜杠,与文件系统不同)。在文字字符串中,必须使用双反斜杠 ("\\")。

默认情况下,如果 path 字符串为空("" 或 NULL),则交易品种直接在 Custom 文件夹中创建,该文件夹在交易品种的通用层级结构中为用户交易品种分配。如果已填充路径,则会在 Custom 文件夹按照完整深度创建该路径(如果尚不存在相应的文件夹)。

交易品种的名称以及任何级别的组名都可以包含拉丁字母和数字,不能包含标点符号、空格和特殊字符。此外,仅允许使用 '.'、'_'、'&' 和 '#'。

无论交易品种应该在哪个组中创建,其名称在整个交易品种层级结构中都必须是唯一的。如果已存在同名交易品种,该函数将返回 false,并在 _LastError 中设置错误代码 5300 (ERR_NOT_CUSTOM_SYMBOL) 或 5304 (ERR_CUSTOM_SYMBOL_EXIST)。

请注意,如果 path 字符串中层级结构的最后一个(甚至唯一一个)元素与 name 完全匹配(区分大小写),则它被视为路径一部分的交易品种名称,而不是文件夹。例如,如果名称和路径分别包含字符串 "Example" 和 "MQL5Book\Example",则交易品种 "Example" 将在 "Custom\MQL5Book\" 文件夹中创建。同时,如果我们将名称更改为 "example",我们将在 "Custom\MQL5Book\Example" 文件夹中得到 "example" 交易品种。

此特性还有另一个后果。SYMBOL_PATH 特性返回的路径末尾会包含交易品种名称。因此,如果我们将某个示例交易品种的值未经更改地传递给新创建的交易品种,我们将得到以下效果:将创建一个以旧交易品种名称命名的文件夹,其中将出现一个新的交易品种。因此,如果你想在与原始交易品种相同的组中创建自定义交易品种,则必须从 SYMBOL_PATH 特性获取的字符串中剥离原始交易品种的名称。

我们将在下一节的示例中演示复制 SYMBOL_PATH 特性的副作用。然而,这种效果也可以作为积极的一面来使用。特别是,通过基于一个原始交易品种创建多个其自定义交易品种,复制 SYMBOL_PATH 将确保所有新交易品种都放置在以原始交易品种名称命名的文件夹中,即,它将根据其原型交易品种对交易品种进行分组。

自定义交易品种的 SYMBOL_PATH 特性始终以 "Custom\" 文件夹开头(会自动添加此前缀)。

名称长度限制为 31 个字符。超过限制时,CustomSymbolCreate 将返回 false 并设置错误代码 5302 (ERR_CUSTOM_SYMBOL_NAME_LONG)。

参数 path 的最大长度为 127 个字符,包括 "Custom\\"、组分隔符 "\\" 以及交易品种名称(如果在末尾指定)。

origin 参数允许你选择性地指定一个交易品种的名称,将从该交易品种中复制所创建自定义交易品种的特性。创建自定义交易品种后,你可以使用适当的函数(请参见 CustomSymbolSet 函数)将其任何特性更改为所需的值。

如果将不存在的交易品种作为 origin 参数给出,则自定义交易品种在创建后为空白,就好像未指定 origin 参数一样。这将引发错误 4301 (ERR_MARKET_UNKNOWN_SYMBOL)。

在以空白方式创建的新交易品种中,所有特性都设置为其默认值。例如,合约大小为 100000,价格中的位数是 4,保证金计算根据外汇规则进行,图表基于 Bid 价。

当你指定 origin 时,仅从该交易品种向新交易品种传递设置,而不传递报价或分时报价,因为它们应单独生成。这将在后续各节中介绍。

交易品种在创建后不会自动添加到 Market Watch。因此,必须以明确方式(手动或以编程方式)添加。若没有报价,图表窗口将为空。

bool CustomSymbolDelete(const string name)

该函数删除具有指定名称的自定义交易品种。不仅删除设置,还删除交易品种上的所有数据(行情和分时报价)。值得注意的是,历史记录不会立即删除,而是在一段延迟之后才删除,如果你打算重新创建同名交易品种,这可能会成为问题的根源(我们将在 添加、替换和删除报价一节的示例中讨论这一点)。

只能删除自定义交易品种。此外,你不能删除Market Watch选定的交易品种或具有打开图表的交易品种。请注意,交易品种也可以 隐式选择,而无需显示在可见列表中(在这种情况下,SYMBOL_VISIBLE 特性为 false,而 SYMBOL_SELECT 特性为 true)。在尝试删除之前,此类交易品种必须首先通过调用 SymbolSelect("name", false) 来“隐藏”:否则,我们会收到 CUSTOM_SYMBOL_SELECTED (5306) 错误。

如果删除交易品种后留下空文件夹(或文件夹层级结构),空文件夹也会被删除。

例如,我们创建一个简单的脚本 CustomSymbolCreateDelete.mq5。在输入参数中,你可以指定名称、路径和示例交易品种。

input string CustomSymbol = "Dummy";         // Custom Symbol Name
input string CustomPath = "MQL5Book\\Part7"// Custom Symbol Folder
input string Origin;

OnStart 处理程序中,让我们检查是否已存在具有给定名称的交易品种。如果没有,则在用户确认后,我们将创建这样一个交易品种。如果交易品种已经存在并且是自定义交易品种,则在用户允许的情况下将其删除(这将有助于在实验结束后进行清理)。

void OnStart()
{
   bool custom = false;
   if(!PRTF(SymbolExist(CustomSymbolcustom)))
   {
      if(IDYES == MessageBox("Create new custom symbol?""Please, confirm"MB_YESNO))
      {
         PRTF(CustomSymbolCreate(CustomSymbolCustomPathOrigin));
      }
   }
   else
   {
      if(custom)
      {
         if(IDYES == MessageBox("Delete existing custom symbol?""Please, confirm"MB_YESNO))
         {
            PRTF(CustomSymbolDelete(CustomSymbol));
         }
      }
      else
      {
         Print("Can't delete non-custom symbol");
      }
   }
}

使用默认选项连续运行两次应该会生成以下日志条目。

SymbolExist(CustomSymbol,custom)=false / ok
Create new custom symbol?
CustomSymbolCreate(CustomSymbol,CustomPath,Origin)=true / ok
   
SymbolExist(CustomSymbol,custom)=true / ok
Delete existing custom symbol?
CustomSymbolDelete(CustomSymbol)=true / ok

在两次运行之间,你可以在终端中打开交易品种对话框,并检查相应的自定义交易品种是否已出现在交易品种层级结构中。