Crear y eliminar símbolos personalizados

Las dos primeras funciones que necesita para trabajar con símbolos personalizados son CustomSymbolCreate y CustomSymbolDelete.

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

La función crea un símbolo personalizado con el nombre especificado (name) en el grupo especificado (path) y, si es necesario, con las propiedades de un símbolo ejemplar: su nombre puede especificarse en el parámetro origin.

El parámetro name debe ser un identificador simple, sin jerarquía. Si es necesario, uno o más niveles requeridos de grupos (subcarpetas) deben especificarse en el parámetro path, donde el carácter delimitador debe ser una barra invertida '\' (aquí la barra diagonal no se admite, a diferencia del sistema de archivos). La barra invertida debe duplicarse en las cadenas literales («\\»).

De manera predeterminada, si la cadena path está vacía («» o NULL), el símbolo se crea directamente en la carpeta Custom, que se asigna en la jerarquía general de símbolos para los símbolos de usuario. Si la ruta está llena, se crea dentro de la carpeta Custom hasta el fondo (si aún no hay carpetas correspondientes).

El nombre de un símbolo, así como el de un grupo de cualquier nivel, puede contener letras y números latinos, sin signos de puntuación, espacios ni caracteres especiales. Además, sólo se permiten '.', '_', '&' y '#'.

El nombre debe ser único en toda la jerarquía de símbolos, con independencia del grupo en el que se supone que se crea el símbolo. Si ya existe un símbolo con el mismo nombre, la función devolverá false y establecerá el código de error 5300 (ERR_NOT_CUSTOM_SYMBOL) o 5304 (ERR_CUSTOM_SYMBOL_EXIST) en _LastError.

Tenga en cuenta que si el último (o incluso el único) elemento de la jerarquía en la cadena path coincide exactamente con name (distingue mayúsculas de minúsculas), entonces se trata como un nombre de símbolo que forma parte de la ruta y no como una carpeta. Por ejemplo, si el nombre y la ruta contienen las cadenas «Ejemplo» y «MQL5Book\\Example», respectivamente, entonces el símbolo «Ejemplo» se creará en la carpeta «Custom\MQL5Book\». Al mismo tiempo, si cambiamos el nombre a «ejemplo», obtendremos el símbolo «ejemplo» en la carpeta «Custom\MQL5Book\\Example».

Esta característica tiene otra consecuencia. La propiedad SYMBOL_PATH devuelve la ruta junto con el nombre del símbolo al final. Por lo tanto, si transferimos su valor sin cambios de algún símbolo ejemplar a otro recién creado, obtendremos el siguiente efecto: se creará una carpeta con el nombre del símbolo antiguo, dentro de la cual aparecerá un símbolo nuevo. Así, si desea crear un símbolo personalizado en el mismo grupo que el símbolo original, debe eliminar el nombre del símbolo original de la cadena obtenida de la propiedad SYMBOL_PATH.

Demostraremos el efecto secundario de copiar la propiedad SYMBOL_PATH en un ejemplo en la siguiente sección. No obstante, este efecto también puede utilizarse como positivo. En concreto, al crear varios de sus símbolos basándose en un símbolo original, la copia de SYMBOL_PATH garantizará que todos los símbolos nuevos se coloquen en la carpeta con el nombre del original, es decir, agrupará los símbolos según su símbolo prototipo.

La propiedad SYMBOL_PATH para símbolos personalizados comienza siempre por la carpeta «Custom\\» (este prefijo se añade automáticamente).

La longitud del nombre está limitada a 31 caracteres. Cuando se supera el límite, CustomSymbolCreate devuelve false y establece el código de error 5302 (ERR_CUSTOM_SYMBOL_NAME_LONG).

La longitud máxima de la ruta del parámetro es de 127 caracteres, incluyendo «Custom\\», los separadores de grupo «\\» y el nombre del símbolo, si se especifica al final.

El parámetro origin permite especificar opcionalmente el nombre del símbolo del que se copiarán las propiedades del símbolo personalizado creado. Después de crear un símbolo personalizado, puede cambiar cualquiera de sus propiedades al valor deseado utilizando las funciones apropiadas (véanse las funciones CustomSymbolSet).

Si se proporciona un símbolo inexistente como parámetro origin, el símbolo personalizado se creará «vacío», como si no se hubiera especificado el parámetro origin. Esto provocará el error 4301 (ERR_MARKET_UNKNOWN_SYMBOL).

En un nuevo símbolo creado «en blanco», todas las propiedades se establecen en sus valores por defecto. Por ejemplo, el tamaño del contrato es 100000, el número de dígitos del precio es 4, el cálculo del margen se realiza de acuerdo con las reglas de Forex y los gráficos se basan en los precios de Bid.

Si especifica origin, solo se transfieren las configuraciones de este símbolo al nuevo, pero no las cotizaciones ni los ticks, ya que deben generarse por separado. Esto se tratará en las secciones siguientes.

La creación de un símbolo no lo añade automáticamente a Observación de Mercado. Por lo tanto, esto debe hacerse explícitamente (de forma manual o mediante programación). Sin cotizaciones, la ventana del gráfico estará vacía.

bool CustomSymbolDelete(const string name)

La función borra un símbolo personalizado con el nombre especificado. No solo se borran los ajustes, sino también todos los datos del símbolo (cotizaciones y ticks). Cabe señalar que el historial no se borra inmediatamente, sino solo después de un cierto retraso, lo que puede ser una fuente de problemas si tiene la intención de volver a crear un símbolo con el mismo nombre (vamos a tocar este punto en el ejemplo de la sección Añadir, sustituir y suprimir cotizaciones).

Solo se puede borrar un símbolo personalizado. Tampoco se puede eliminar un símbolo seleccionado en Observación de Mercado o un símbolo que tenga un gráfico abierto. Tenga en cuenta que también se puede seleccionar un símbolo implícitamente, sin mostrarlo en la lista visible (en estos casos, la propiedad SYMBOL_VISIBLE es false, y la propiedad SYMBOL_SELECT es true). Un símbolo de este tipo debe «ocultarse» primero llamando a SymbolSelect("name", false) antes de intentar borrarlo: de lo contrario, obtendremos un error CUSTOM_SYMBOL_SELECTED (5306).

Si al borrar un símbolo queda una carpeta (o jerarquía de carpetas) vacía, también se borra.

Por ejemplo, vamos a crear un sencillo script CustomSymbolCreateDelete.mq5. En los parámetros de entrada, puede especificar un nombre, una ruta y un símbolo de ejemplo.

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

En el manejador OnStart, vamos a comprobar si ya existe un símbolo con el nombre dado. Si no es así, tras la confirmación del usuario, crearemos dicho símbolo. Si el símbolo ya está ahí y es un símbolo personalizado, lo borraremos con el permiso del usuario (esto facilitará la limpieza una vez finalizado el experimento).

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");
      }
   }
}

Dos ejecuciones consecutivas con las opciones por defecto deberían dar como resultado las siguientes entradas de registro:

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

Entre una ejecución y otra puede abrir el cuadro de diálogo de símbolos en el terminal y comprobar que el símbolo personalizado correspondiente ha aparecido en la jerarquía de símbolos.