English Русский 中文 Deutsch 日本語 Português
Tres aspectos de la Automatización manual del trading. Primera parte: Trading

Tres aspectos de la Automatización manual del trading. Primera parte: Trading

MetaTrader 4Ejemplos | 12 abril 2016, 14:41
996 0
Sergey Kravchuk
Sergey Kravchuk

Introducción

Con los años de trabajo en el desarrollo de la plataforma MetaTrader 4, he intentado muchos modelos y métodos para crear una estación de trabajo automatizada para un trader. La primera solución, y la más obvia, se implementó en el set de scripts de trading Trader sólo con ratón que tuvo bastante éxito en general. Cuando la mejoré con los riesgos de gestión de cálculos y las funciones de gestión monetaria, se me ocurrió una herramienta bastante útil: el Ratón de trading.

Facturada por sus desarrolladores como una manera de crear robots de trading totalmente automatizados, la terminal MetaTrader 4 y su ergonomía resultó ser completamente inadecuada para la gente que necesita un lugar de trabajo cómodo. Por lo que empecé a experimentar con una interfaz gráfica, mientras investigaba las posibilidades de utilizar un ratón y un teclado directamente en un gráfico de trading. El resultado del experimento se representó con dos productos muy bien presentados: Consola de trading y Buy/Sell.

Desgraciadamente, había un lado opuesto a todas sus buenas características y a la facilidad de uso: el Asesor Experto mostraba poca respuesta a los cambios rápidos de precio y la ejecución de las órdenes de trade. La terminal estaba más tiempo dibujando las características de la interfaz que haciendo trading. Todos los intentos de hacer trading activamente utilizando esa interfaz aparentemente fácil de usar, involucraban una cantidad justa de dificultades (especialmente haciendo pipsing y scalping).

Variantes de la interfaz

Fig. 1. Variantes de la interfaz.

Por lo tanto, cuando reconsideré las órdenes del Asesor Experto teniendo en cuenta estos hechos, creé un Scalper que pudiera ofrecer la eficiencia máxima con la mínima atracción visual. Desgraciadamente, seguía teniendo fallos en forma de proceso de peticiones del ratón, o al tener que utilizar el sensor de la pantalla de una tablet. Como resultado, terminó siendo un producto exclusivo para funcionar en tablets. Conseguí deshacerrme de casi todos los DWIMS (en inglés, Do What I Mean) en el Trader simple que funcionaban como base del Asesor Experto que voy a presentar en este artículo.

He descrito intencionadamente la evolución de mis productos para ayudarle a comprender que la implementación de todo lo establecido en este artículo, no derivaba del hecho de que el autor no pudiera hacer otra cosa. Es sólo que después de muchos intentos y errores, me he quedado con la solución más simple y fiable que me gustaría compartir.



Una imagen vale más que 1 000 palabras

Antes de empezar, miremos el funcionamiento del Asesor Experto que se considerará más adelante. El vídeo le dará una idea de los procesos que ocurren en la terminal durante el trading. Como resultado, el artículo será mucho más fácil de comprender (algo como: "Ah, ¡así se implementa!").

Para una mejor comprensión del vídeo, basta con comprender que es un Asesor Experto que funciona en la terminal y está controlado dejando los scripts de control en la ventana de la terminal. El propio Asesor Experto no hace trading. Sólo puede sacar niveles de parada (Stop Loss y Take Profit) después de recibir una petición relevante de un trader. Los nombres del script corresponden claramente a sus respectivas acciones, mientras que su uso se explica en tooltips.

Ahora que se tiene la idea general de este artículo, vamos a mirarlo más atentamente.



Principios básicos de la Automatización manual del trading.

Antes que nada, me gustaría decir que soy demasiado impaciente como para hacer trading diariamente, imagínese para los gráficos semanales o mensuales. Puedo dejar una posición abierta más de un día sólo en caso de una tendencia completamente estable y claramente fuerte. Mi periodo de trabajo es de 5 y 15 minutos. Hay mucho ruido en los gráficos de un minuto, mientras que los gráficos por horas terminan con mi paciencia. Muchos de vosotros pensaréis inmediatamente en dos maestros, Alligator, las pantallas de Elder, etc.: ¿cómo se puede hacer sin periodos de tiempo más altos? ¿No se usan para identificar las tendencias a corto plazo y los puntos de entrada del mercado? Yo no los uso para un informe específico. En lugar de eso, me va bien con una combinación de zigzag y un gráfico que trazo basado en los 5 y 15 minutos actuales. Pero ese no es el tema ahora mismo. Estamos hablando de los traders intradía. Lo que hacen es básicamente un scalping clásico. Se necesita monitorizar con cuidado el precio actual y responder inmediatamente a los impulsos del mercado.

Esta conciencia intradía me permite a simplificar drásticamente los requisitos del sistema de trading. Utiliza sólo una orden para cada símbolo. Sin retrasos: si ve que el precio va en su contra, cierre la posición con la pérdida mínima y, o bien abra en dirección opuesta, o espere a que mejoren las condiciones para una entrada en la misma dirección. Sin bloqueos ni redes. Si no está seguro de la dirección en la que debería abrir una posición, ¡no la abra! Esta afirmación puede parecer controvertida, pero es así como hago trading y este método se seguía en el Asesor Experto que se va a describir en este artículo.

La decisión de utilizar una orden por cada símbolo ha resuelto todos los problemas relacionados con la selección interactiva de una orden de trabajo para modificar o cerrar. Como resultado, el código del Asesor Experto se ha reducido, como los códigos de los errores. Entre sus características automatizadas están las de apertura/modificación/cierre rápido de una orden y la implementación del principio clásico de trading, "deja que fluyan los beneficios", en forma de una ejecución automática de Trainling Stop. Sin embargo, como contraste al Trailing Stop estándar implementado en la terminal, el Trailing Stop que aparece en este Asesor Experto, está completamente controlado por el trader y puede modificarse fácilmente en cualquier momento, según las condiciones cambiantes del mercado.

Pero la diferencia principal desde Trailing Stop estándar, es la posibilidad de configurar el precio de salida. Justo después de abrirlo, se puede especificar el precio que tiene que alcanzarse para que el Asesor Experto empiece a seguir el beneficio acumulado. Este precio será a menudo el precio al que está establecido Take Profit. Surge la duda: ¿por qué cortar el beneficio a ese nivel si continua creciendo más? Como no se puede saber con seguridad, se empezará a obtener beneficios en ese momento, mientras que sigue funcionando utilizando el Trailing Stop automático integrado.



El bien conocido saber hacer

No creo que esté descubriendo nada nuevo cuando digo que la única manera de ejecutar manualmente una petición de trade es iniciando un script en concreto. Sus acciones se realizaron en el momento de soltar el script en el gráfico. Al contrario que el script, el Asesor Experto tiene que esperar a que el siguiente tick detone el inicio. Pero con cada nuevo tick, el precio puede ser algo diferente de lo que esperaba. Probablemente no sea tan importante cuando se hace trading en periodos más largos. Pero en el trading agresivo de intradía, estos retrasos son inaceptables.

Sin embargo, en una ventana puede iniciar sólo un script a la vez. En el momento en el que inicie otro script, el anterior dejará de funcionar. La funcionalidad del script en sí es mucho más pobres que las capacidades del Asesor Experto. Por lo que decidí dividir el funcionamiento del Asesor Experto en dos etapas: generación y ejecución de la orden de trade. Como resultado, tenemos un set de scripts que no realizan ninguna acción específica, sino que simplemente pasan al Asesor Experto los detalles de lo que necesita hacer.

Para unificar este mecanismo de petición, decidí no incluir ninguna acción de trading significativa en los scripts. Cada script está asociado a una orden específica (abrir una orden, modificar Stop Loss/Take Profit, cerrar una orden) que tiene un índice numérico único. Por lo que, cuando se suelta el script en la gráfica, se sabe qué petición se quiere ejecutar. El precio y, si es necesaria, la hora de la ejecución de la petición se pueden configurar utilizando las coordenadas del punto en el que se ha soltado. Sólo se necesita ver cómo se pueden pasar los datos relacionados a soltar el script en el gráfico al Asesor Experto.

Durante el desarrollo de las versiones anteriores de trades automatizados, he intentado casi todos los métodos adecuados de comunicación de programa a programa, utilizando un nivel de software de sistema operativo y Win32API:

  • escribir/leer a través de archivos de disco o a través de FileMapping en la memoria,
  • interacción utilizando protocolos http,
  • uso de mailslots, etc.

Tienen características geniales (como por ejemplo, mirror trading en varias cuentas en terminales diferentes o control remoto de un Asesor Experto que funciona en VPS) pero, desafortunadamente, todos eran muy complicados en términos de implatación y soporte, y no merecían la pena. Con la experiencia, conseguí deshacerme de todo lo innecesario, dejando sólo las elecciones correctas: el uso de las variables globales de la terminal. La interacción del script y el Asesor Experto en su forma final se redujeron a:

Cuando se suelta en el gráfico, el script crea varias variables globales y simula el nuevo tick en la terminal para hacer que el Asesor Experto ejecute inmeadiatamente la orden leyendo los valores de las variables globales.


Beneficios y características del mecanismo de petición del script global

La primera ventaja clara es el uso del mecanismo de la plataforma estándar que asegura una interacción fiable. El código fuente se reduce significantemente y el código de Asesor Experto se deshace del exceso de librerías .ex4 y .dll, haciendo más fácil su modificación y mantenimiento.

Pero la característica más importante de este mecanismo, es la posibilidad de un funcionamiento adecuado en el modo de visualización del Tester de estrategia. Permite afilar fácilmente las capacidades de trading y mejorar las tácticas en el modo acelerado de "reproducción de mercado". Puede configurar cualquier velocidad de reproducción de cotizaciones y seguir practicando... A diferencia de una cuenta demo que ofrece el funcionamiento junto en el mercado, con la velocidad del mercado real, el visualizador está disponible en cualquier momento (incluso los fines de semana cuando no hay conexión a Internet). Se puede pausar en cualquier momento (para un descanso para tomar un café o para realizar un análisis complejo de la situación actual) y determina la efectividad de sus métodos de trading, ya que recorre varios meses del historial en sólo un par de minutos utilizando el control de reproducción de velocidad.

Igual de importante es la posibilidad de hacer trading con este Asesor Experto utilizando las señales de prácticamente cualquier indicador que no puede hacer trading por sí mismo. En un gráfico, estos indicadores, por norma general, sólo muestran un objeto en concreto del gráfico, es decir, una señal para introducir el mercado o cerrar una orden. Desafortunadamente, esto es todo lo que hacen. Generalmente es imposible hacer trading o iniciar el indicador en el Tester de estrategia. Pero si tiene el código fuente del indicador, sólo necesitará modificarlo añadiendo un bloque para crear las variables globales necesarias (que son sólo un par de líneas del código fuente) y llamarla en el punto en el indicador establece su señal. No tendrá ni que preocuparse por repetir la señal en cada tick. Ya que el Asesor Experto sólo puede abrir una orden por símbolo, una petición de apertura repetida no hará que el Asesor Experto abra nuevas órdenes. Con un indicador de peticiones como este a mano, podrá probar las señales de trading del indicador fácilmente en el Tester de Estrategia: sólo tiene que iniciar el Asesor Experto, adjuntar su indicador al gráfico relevante, y observar cómo hace trading el Asesor Experto basándose en las señales del indicador.

Pero ya está bien de información técnica. Ya va siendo hora de empezar con la implementación práctica de la idea.



Parámetros de las órdenes de control

Cada script de control crea varias variables globales que se utilizan para pasar los siguientes parámetros al Asesor Experto.

  • #Trader-Chart: control de la ventana en la que se suelta el script. Se necesita para permitir el funcionamiento de varios Asesores Expertos diferentes en una terminal (es decir, para diferentes símbolos o en diferentes periodos de tiempo). Cuando se suelta en una ventana determinada, el script coge su control. Este comando se controlará por el Asesor Experto que esté adjunto en la misma ventana. Por lo tanto, los Asesores Expertos diferentes sólo controlan sus órdenes correspondientes, ignorando el resto. El control se obtiene utilizando la función WindowHandle().

  • #Trader-Command: código de comando. Desafortunadamente, la terminal permite que se almacenen los números sólo en las variables globales para que se les puedan asignar códigos numéricos en lugar de valores importantes de filas. Para asegurar la sincronización entre los valores del Asesor Experto y los scripts, se utiliza el archivo general #Trader-commands.mqh que se incluye con las siguientes definiciones:

    #define   COMMAND_NOACTION  0
    #define   COMMAND_OPEN      1
    #define   COMMAND_MODIFY    2
    #define   COMMAND_CLOSE     3
    #define   COMMAND_TRALSTART 4
    #define   COMMAND_TRALSTOP  5
    #define   COMMAND_TRALSTART0LOSS 6
    #define   COMMAND_TRALSTART50PROFIT 7

    Si necesita añadir su propio comando nuevo, sólo tiene que añadir este código "COMMAND_MYNEWCOMMAND" y asignarle un código único. Esto le permite elevar prácticamente hasta el infinito la funcionalidad de su versión del Asesor Experto.

  • #Trader-Price: precio en el punto en el que se suelta el script. Normalmente, esta es un nuevo precio de apertura de orden, el precio de modificación de Stop Loss o Take Profit o el precio de salida automático de Trailing Stop.

  • #Trader-Time: tiempo de generación de la orden de trade. Es un momento muy importante. No permitirá al Asesor Experto controlar ningún comando colgado, por cualquier motivo, que quede en la terminal. Con este propósito, hay un parámetro especial en el Asesor Experto: ExecDelaySec. El Asesor Experto comprueba la hora de la terminal actual antes de ejecutar un comando, y si la hora almacenada en el script es superior a la hora actual por segundos ExecDelaySec, la orden no se ejecutará y se eliminarán sus detalles.



Códigos fuente de los scripts de control

Según lo anterior, parece que los códigos de todos los scripts son casi iguales, con la única diferencia de la orden. Por lo tanto, toda a parte común se ordenó como un archivo .mqh diferente para incluirlo en todos los scripts de control.

Sólo proporciona funciones de control mínimas asociadas con la disponibilidad de trading. Todo lo demás se debería hacer en la terminal.

#property link      "http://forextools.com.ua"
#include <stderror.mqh>
#include <WinUser32.mqh>
 
#import "user32.dll"
 int RegisterWindowMessageA(string lpstring);
 int PostMessageA(int hWnd,int Msg,int wParam,int lParam);
#import
 
void start()
{
  if ( !IsExpertEnabled() )   
  { MessageBox("Experts disabled. Action canceled.","SimpleTrader ERROR", MB_ICONERROR); return; }
  if ( !IsTradeAllowed() )    
  { MessageBox("Trade disabled. Action canceled.","SimpleTrader ERROR", MB_ICONERROR); return; }
  if ( IsTradeContextBusy() ) 
  { MessageBox("Trade context is busy. Action canceled.","SimpleTrader ERROR", MB_ICONERROR); return; }
 
  GlobalVariableDel ( "#Trader-Chart" );
  GlobalVariableDel ( "#Trader-Command" );
  GlobalVariableDel ( "#Trader-Price" );
  GlobalVariableDel ( "#Trader-Time" );
 
  // to allow several EAs handle scripts dropped onto THE RELEVANT windows only
  GlobalVariableSet ( "#Trader-Chart", WindowHandle( Symbol(), Period()) ); 
  GlobalVariableSet ( "#Trader-Command", COMMAND_ID );
  GlobalVariableSet ( "#Trader-Price", NormalizeDouble ( WindowPriceOnDropped(), Digits ) );
  GlobalVariableSet ( "#Trader-Time", TimeCurrent() );
 
  // emulation of the incoming tick to launch the Expert Advisor
  int hwnd = WindowHandle(Symbol(), Period());
  int MT4InternalMsg = RegisterWindowMessageA("MetaTrader4_Internal_Message");
  PostMessageA(hwnd, MT4InternalMsg, 2, 1);  
}

El código del script en sí consiste en unas cuantas líneas:

#property copyright "Open buy or sell according to the dropped price of the Stop Loss level"
#include  "#Trader-commands.mqh"
int COMMAND_ID = COMMAND_OPEN;
#include  "#Trader-common.mqh"  

#property copyright se utiliza para generar el texto tooltip en la terminal. Mientras que este texto para órdenes simples puede ser obvio, con sus propias órdenes, su decisión de añadirlos al Asesor Experto puede necesitar una buena descripción además del nombre sin importancia, y ese es el lugar para eso.

Esta línea está seguida por códigos de órdenes del archivo general. El código general ejecutable proporcionó alguno de los párrafos anteriores después de configurar un código de comando para un script en concreto.

Aquí es donde dejamos de trabajar con los scripts de control y procedemos al funcionamiento del Asesor Experto.



Lógica del Asesor Experto para la automatización manual del trading

Inicialmente, quería presentar el algoritmo de funcionamiento del Asesor Experto en forma de un gráfico de flujo. Pero resultó ser tan simple y directo que servirá un simple texto.

Coja el comando -> Compruebe y calcule los parámetros -> Ejecute el comando -> Muestre los resultados

Los parámetros de entrada del Asesor Experto son tan minimalistas como la lógica subyacente. Lo que controle cada uno se describirá más adelante, conforme procedemos a la explicación de los bloques correspondientes del código fuente del Asesor Experto

#property copyright "Copyright © 2006-2013, Sergey Kravchuk. http://forextools.com.ua"
#property link      "http://forextools.com.ua"

#include <stdlib.mqh>
#include "scripts\#Trader-commands.mqh"

extern int    MaxAllowedRisk = 2// maximum permissible percentage of losses 
extern int    OpenSlippage   = 2// distance from the current price for placing an order to open a position
extern int    CloseSlippage  = 10; // maximum permissible slippage when closing an order
extern int    ExecDelaySec   = 10; // maximum permissible delay as of the START of command execution

extern int    ShowClosedCnt  = 5// number of closed market orders for the history display

extern int    TralStep       = 5// price change step in trailing
extern color  TralStartColor = BlueViolet;
extern color  Tral0LossStartColor = LimeGreen;
extern int    Tral0LossGap   = 10; // offset from the opening price to the breakeven point in trailing

// arrow colors for order opening and closing
extern color  MarkBuyColor    = Blue;
extern color  MarkSellColor   = Red;
extern color  MarkModifyColor = Magenta;
extern color  MarkCloseColor  = Gray;

extern int    MessageShowSec  = 30; // time of displaying the last message on the screen in seconds

extern bool   ShowComment     = true;
extern bool   WriteGadgetFile = true;

El Asesor Experto consigue primero los parámetros de la terminal para los cálculos actuales del precio (dependiendo de dónde funcione en el visualizador o en una cuenta real). Si hay una orden abierta en el símbolo del gráfico que está funcionando, el operador OrderSelect() la selecciona de inmediato.

// get dynamic parameters
Spread      = MarketInfo ( Symbol(), MODE_SPREAD );
StopLevel   = MarketInfo ( Symbol(), MODE_STOPLEVEL );

// update prices (instead of Ask and Bid, the Strategy Tester uses Close[0])
if ( IsTesting() ) { CurBid = Close[0]; CurAsk = Close[0]+Spread*Point; } 
else { CurAsk = Ask; CurBid = Bid; }

// Select ANY open order (for possible modifications), including Limit orders 
// e.g. to be able to set Take Profit
SelectedOrder = 0; for ( i = 0; i < OrdersTotal() && SelectedOrder <= 0; i++ )
{
  OrderSelect ( i, SELECT_BY_POS, MODE_TRADES );
  if ( OrderSymbol() == Symbol() && OrderMagicNumber() == MAGIC ) SelectedOrder = OrderTicket();
}

En caso de que haya una orden abierta para el símbolo actual, se saca Trailing Stop. La pertinencia y funcionamiento de esta acción se definen por el proceso que obtiene el único parámetro: TralStep. Si no hay una orden abierta, los parámetros de trailing se reinician. Esto es necesario porque a orden puede cerrar antes de soltar el nivel de Stop y el Asesor Experto, en contraste con el cierre manual, no sabrá que estos parámetros tienen que reiniciarse.

//trailing trigger price exists as long as there is an open order!!!
if ( SelectedOrder <= 0 ) { ZeroLossTral = false; HalfProfitTral = false; PrevPrice = 0; TralStart = 0; } 
// trailing (checking and performing - within the TrailingStop)
else TrailingStop ( TralStep );

Más adelante se comprueba si el comando está destinado a nuestra ventana. Si esta orden es de otro script, el Asesor Experto simplemente mostrará la información actualizada en la cuenta y las órdenes abiertas. Si es un comando relevante, el Asesor Experto leerá sus parámetros y eliminará inmediatamente las variables globales de comando (es decir, múltiples órdenes abiertas no accidentalmente).

// if the script is intended for another window, only update the information.
if ( GlobalVariableGet ( "#Trader-Chart" ) != WindowHandle( Symbol(), Period()) ) { ShowInfo(); return; }
// if it is intended for the right window, execute the commands
// get the code and price of the command from the global variables and immediately delete them
if ( GlobalVariableCheck( "#Trader-Command" ) == false ) { CmdID = 0; CmdPrice = 0; ShowInfo(); return; } 
// there is a command, so we execute it
CmdTime  = GlobalVariableGet ( "#Trader-Time" );
CmdID    = GlobalVariableGet ( "#Trader-Command" );
CmdPrice = NormalizeDouble ( GlobalVariableGet ( "#Trader-Price" ), PriceDigits );
GlobalVariableDel ( "#Trader-Command" );
GlobalVariableDel ( "#Trader-Price" );
GlobalVariableDel ( "#Trader-Time" );
// if the command was generated earlier than the permissible execution delay, do not do anything!
if ( CmdTime+ExecDelaySec*60 < TimeCurrent() )
{
  SetError("Igore command from " + TimeToStr(CmdTime,TIME_DATE+TIME_SECONDS) 
         + " delayed > " + ExecDelaySec + "sec");
  ShowInfo();
  return;
}

Esto va seguido de la ejecución de la orden y muestra de los resultados de la misma. El código fuente del Asesor Experto se proporciona junto con los comentarios, cuando sea necesario, y no debería tener ninguna dificultad leyéndolos y comprendiéndolos. Sin embargo, hay algunos puntos que necesitan una aclaración.



Por favor, tenga en cuenta:

  1. No se puede hacer trading sin los niveles de Stop.

    Una orden se abre siempre con un nivel de Stop presente. El tamaño del lote se selecciona teniendo en cuenta el nivel de Stop, para que la pérdida (si salta) no exceda el porcentaje actual de los fondos disponibles para el trading. Esta regla también se comprueba cuando se modifica el nivel de Stop. Por lo que no podrá abrir a un riesgo bajo y luego establecer el nivel de Stop de modo que perderá el resto de su depósito. Esta regla lleva indirectamente a otra.

  2. Sólo se abren órdenes Limit.

    Algunos centros de operaciones no permiten abrir órdenes de mercado con Stop Loss y Take Profit predefinidas sobre la base de que se pueden abrir con un retraso, y es (teóricamente) posible que, por ejemplo, en un caso de compra, su nivel de Stop resulte ser más alto que el precio de apertura. Esta situación es, de hecho, muy probable en un mercado variable y con nivel bajo de Stop. Para evitar esta restricción, abriremos una orden Limit con una pequeña compensación del precio actual (la mencionada anteriormente). Permite colocar una orden exactamente donde se necesita, con un nivel de Stop que no exceda el porcentaje de riesgo especificado. Si el mercado se mueve en nuestra dirección, la orden se abrirá en tan sólo un par de ticks. Si el mercado está en nuestra contra, tendremos la oportunidad de cerrar la orden Limit que no se ha utilizado sin pérdidas, o moverla a un lugar mejor.



Abrir una orden

Una vez analizada la situación actual y habiendo seleccionado la dirección de trading, decida la posición del nivel de Stop para que se abra la orden y suelte el script #OPEN en ese punto de Stop Loss. Su posición también se utiliza para determinar la dirección de trading. Una Stop Loss para una orden de compra siempre debe estar por debajo del precio de apertura y si, al soltar el script, especificó el precio del nivel de Stop por debajo del precio actual, significa que va a comprar. Igualmente, una Stop Loss por encima del precio actual, sugerirá la apertura de una orden de venta. La única excepción de esta regla es una Stop Loss dentro de la extensión. Como norma general, sin embargo, la política de trading del centro de operaciones, por la que no se puede configurar Stop Loss más cerca de lo que se especifica en el parámetro de StopLevel, no permitirá esto.

A pesar de la cantidad de texto describiendo las reglas de apertura, el código respectivo tiene sólo tres líneas de largo:

// get dynamic parameters
Spread      = MarketInfo ( Symbol(), MODE_SPREAD );
StopLevel   = MarketInfo ( Symbol(), MODE_STOPLEVEL );
// update prices (instead of Ask and Bid, the Strategy Tester uses Close[0])
if ( IsTesting() ) { CurBid = Close[0]; CurAsk = Close[0]+Spread*Point; } 
else { CurAsk = Ask; CurBid = Bid; }
…
// determine the trading direction
if ( CurBid <= CmdPrice && CmdPrice <= CurAsk ) 
{ SetError("Stop inside spread. Undefined trade direction."); ShowInfo(); return; }
if ( CmdPrice < CurBid ) 
{ 
  Operation = OP_BUYSTOP;  
  PriceForOrder = CurAsk+(StopLevel+OpenSlippage)*Point; 
  MarkOpenColor = MarkBuyColor; 
}
if ( CmdPrice > CurAsk ) 
{ 
  Operation = OP_SELLSTOP; 
  PriceForOrder = CurBid-(StopLevel+OpenSlippage)*Point; 
  MarkOpenColor = MarkSellColor; 
}

Al abrir una orden, hay un mecanismo más que permite aumentar la velocidad del proceso de trading: la posibilidad de girar "automáticamente" una posición. Si tiene que comprar una orden y ver que el mercado se está volviendo pesimista, necesitará cerrar la orden de compra y abrir una de venta. Puede hacerlo todo simplemente soltando el script de apertura. El Asesor Experto analizará la situación y, en caso de que haya un giro de posición, primero cerrará la orden de apertura (si estuviera abierta) y luego abrir una contraria.

// if this is the opening in the opposite direction, we first close the current order (if it exists)
if ( SelectedOrder > 0 )
{
  if ( ( Operation == OP_BUYSTOP  && ( OrderType() == OP_BUY  || OrderType() == OP_BUYSTOP  ) ) ||
       ( Operation == OP_SELLSTOP && ( OrderType() == OP_SELL || OrderType() == OP_SELLSTOP ) ) )
  {
    SetError("Only one order per symbol is allowed"); 
    ShowInfo();
    return;
  }
  // if orders are differently directed, close the previous one
  {
    if ( OrderType() == OP_BUY || OrderType() == OP_SELL )
    {
      // update with the current prices. in the Strategy Tester, Close[0] is used instead of Ask and Bid
      if ( IsTesting() ) { CurBid = Close[0]; CurAsk = Close[0]+Spread*Point; }   else { CurAsk = Ask; CurBid = Bid; }
      if ( OrderType() == OP_BUY ) PriceForOrder = CurBid; else PriceForOrder = CurAsk;
      OK = OrderClose ( OrderTicket(), OrderLots(), PriceForOrder, CloseSlippage, MarkCloseColor );
    }
    else 
    {
      OK = OrderDelete ( OrderTicket(), MarkCloseColor );      
      // clear lines and arrows of deleted Limit orders (not to overload the screen with information)
      for(i = ObjectsTotal()-1; i >= 0 ; i--)   if ( StringFind(ObjectName(i),"#"+SelectedOrder) == 0 ) ObjectDelete(ObjectName(i)); 
    }
    if ( OK == false) { SetLastError("Close on reverse"); return; } // failed to delete - do not do anything else 
  } 
}


Gestión monetaria y porcentaje de riesgo permisible

Después de determinar la dirección de trading, hay que determinar su volumen. El Asesor Experto calcula el lote para una orden que se va a abrir para que no se exceda el porcentaje de pérdidas permisible. El algoritmo de cálculo es muy simple: determina el punto válido para un lote estándar que se utiliza en un futuro para calcular las pérdidas que tendrán lugar en el nivel de Stop especificado por el script. Además, siguiendo la regla de prorrateo, el tamaño del lote disminuye tanto como el valor por el que el lote estándar excede el porcentaje permisible máximo asociado con los fondos disponibles.

// calculate the required lot based on the specified losses at the given Stop level
Loss = AccountBalance() * MaxAllowedRisk / 100.0; // amount of permissible losses expressed as a percentage of the balance
PriceInPoint = MathAbs ( PriceForOrder - CmdPrice ) / Point;
SL1lot = PriceInPoint * TickValue;   // Stop level size expressed in monetary value for a single lot transaction.
Lot = Loss / SL1lot;         // permissible risk / SL1lot
Lot = NormalizeDouble ( MathFloor ( Lot / LotStep ) * LotStep, LotDigits );

Si el nivel de Stop se establece muy alto, mientras que el riesgo de porcentaje es bajo, el tamaño del lote necesario puede parecer ser menor que el valor mínimo permisible. Se puede comprobar fácilmente, teniendo en cuenta la imposibilidad de apertura y del posibles valor máximos de Stop Loss.

if ( Lot < MinLot )
{
  OnePipCost = TickValue * MinLot; // recalculate the point value for the minimum possible lot
  SetError("Stoploss "+DoubleToStr(PriceInPoint,0)
          +" > max available "+DoubleToStr(MathAbs (Loss / OnePipCost),0));
  ShowInfo();
  return;
}

Si el lote excede el tamaño máximo permisible (si establece Stop Loss muy cerca, mientras se especifica un porcentaje de riesgo bastante alto), le aparecerá un mensaje de alerta:

if ( MaxLot < Lot )
{
  OnePipCost = TickValue * MaxLot; // recalculate the point value for the maximum possible lot
  SetError("Stoploss "+DoubleToStr(PriceInPoint,0)
          +" < min available "+DoubleToStr(MathAbs (Loss / OnePipCost),0));
  ShowInfo();
  return;
}  


Modificación de la orden

Si necesita establecer Take Profit o mover Stop Loss a otro nivel de precio, suelte el script #MODIFY en el punto de precio apropiado en el gráfico. El Asesor Experto averiguará qué hay que modificar exactamente (Stop Loss o Take Profit) y modificará la orden en consecuencia. Aquí se usará la misma técnica que cuando se abre una orden: si el precio de modificación es menor que el precio actual de compra, significa la modificación de Stop Loss. Un precio de modificación más alto se asocia a la modificación de Take Profit.

// determine what needs to be modified
if ( ( (OrderType() == OP_BUY  || OrderType() == OP_BUYSTOP)  && CmdPrice >= CurAsk ) ||
     ( (OrderType() == OP_SELL || OrderType() == OP_SELLSTOP) && CmdPrice <= CurBid ) ) TP = CmdPrice;
else // modify the Stop Loss
{
  SL = CmdPrice;

Como las pérdidas están controladas estrictamente, no podrá configurar Stop Loss más alta que cuando abrió la orden, por lo que se evitarán riesgos irracionales.

  // Stop Loss and risk percentage control! 
  Loss = AccountBalance() * MaxAllowedRisk / 100.0; // losses set as a percentage of the balance
  OnePipCost = TickValue * OrderLots(); // recalculate the point value for the order lot
  if ( OrderType() == OP_BUY  ) NewLoss = ( OrderOpenPrice() - SL ) / Point * OnePipCost;
  if ( OrderType() == OP_SELL ) NewLoss = ( SL - OrderOpenPrice() ) / Point * OnePipCost;
  if ( NewLoss > Loss ) 
  { 
    SetError("Stoploss "+DoubleToStr(NewLoss/OnePipCost,0)
            +" > max available "+DoubleToStr(Loss/OnePipCost,0)); 
    ShowInfo(); return; 
  }
}


Cerrar una orden

Cuando decide cerrar la orden actual, suelte el script #CLOSE en cualquier punto de precio en el gráfico como si no fuera importante de cerrar. Después de esto, la orden se cerrará.



Trailing Stop

Igual que el mecanismo estándar de Trailing Stop, el algoritmo de Trailing Stop construido en el Asesor Experto también sigue el precio a una distancia que especifique usted (si el precio va en la dirección "correcta"). Pero a diferencia del mecanismo estándar, tiene un control de funcionamiento más flexible.

Primero de todo, le permite establecer el precio en el que quiere empezar el seguimiento. Puede hacerlo justo después de abrir una orden soltando el script #TRAL-START en el precio en el que hay que activar el seguimiento. El Asesor Experto "recordará" ese valor y tan pronto como el precio pase por el nivel correspondiente, el mecanismo de Trailing Stop aparecerá, con el Asesor Experto sacando Trailing Stop después del movimiento del precio. Para evitar modificar la orden demasiado a menudo, el Asesor Experto tiene un parámetro de discreción de paso de Trailing Stop: TralStep. Sólo se configurará un nuevo Trailing Stop si el precio se mueve una distancia de, al menos, los puntos TralStep en la dirección "correcta".

La segunda diferencia con el Trailing Stop estándar es que puede establecer el tamaño de Trailing Stop al mismo tiempo que establece su punto inicial. El script #TRIAL-STRART0LOSS indicará el punto inicial de trailing y una vez que se ejecute, moverá automáticamente Stop Loss hacia el punto de rentabilidad a la distancia de los puntos Tral0LossGap desde el precio de apertura de orden. Otra modificación del mismo script, #TRAL-START50PROFIT, moverá el nivel de Stop al principio del proceso de trailing hacia la línea del medio entre el precio de salida del trailing y el precio de apertura de la orden, que guardará automáticamente al menos el 50% del beneficio acumulado en el inicio del trailing.

Las órdenes de configuración de Stop Trailing pasan los parámetros del futuro Trailing Stop al Asesor Experto.

//——— TRALSTART

// set the trailing trigger price. 
// before the triggering TralStart < 0 as a sign that it is still inactive
if ( CmdID == COMMAND_TRALSTART && CmdPrice > 0) 
{ 
  ZeroLossTral = false; HalfProfitTral = false; TralStart = CmdPrice; PrevPrice = 0; ShowInfo();   return; 
}
//——— TRALSTART0LOSS
// set the trailing trigger price. and simultaneously move the Stop level to the breakeven point
if ( CmdID == COMMAND_TRALSTART0LOSS && CmdPrice > 0) 
{ 
  ZeroLossTral = true; HalfProfitTral = false; TralStart = CmdPrice; PrevPrice = 0; ShowInfo();   return; 
}
//——— TRALSTART50PROFIT
// set the trailing trigger price. and simultaneously move the Stop level to 50% of the earned profit
if ( CmdID == COMMAND_TRALSTART50PROFIT && CmdPrice > 0) 
{ 
  ZeroLossTral = false; HalfProfitTral = true; TralStart = CmdPrice; PrevPrice = 0; ShowInfo();   return; 
}
//——— TRALSTOP
// zero out, which means that trailing stops
if ( CmdID == COMMAND_TRALSTOP ) 
{ 
  ZeroLossTral = false; HalfProfitTral = false; PrevPrice = 0; TralStart = 0; ShowInfo();   return; 
} 

Este mecanismo le permitirá reducir el estrés del trading de intradía y puede garantizar que el trading sea, por lo menos, sin pérdidas si el precio alcanza el punto de salida del trailing. Como todo lo de arriba lo hará el Asesor Experto automáticamente, no tendrá que estar monitorizando continuamente los precios actuales, esperando que Trailing Stop aparezca.

Durante el funcionamiento del Asesor Experto en el modo de trailing, la posición de Trailing Stop puede modificarse en cualquier momento con un comando de modificación estándar utilizando el script #MODIFY. Tras mover el nivel de Stop a otro nivel, el mecanismo activo de Stop Trailing mantendrá esa distancia más adelante. Como todo se hace en el gráfico y se puede visualizar, es mucho más cómodo que el mecanismo estándar de trailing, que necesita valores en los puntos. Igual que con la modificación del Stop Loss estándar, el Traling Strop también proporciona el control de las pérdidas permisibles que no le permitirán perder más de lo especificado:

void TrailingStop(int Step)
{
  double OnePipCost, NewLoss, SL=0;
  
  if ( OrderSelect ( SelectedOrder, SELECT_BY_TICKET ) == false ) return; 
  if ( OrderCloseTime() > 0 ) return; // the order has already been closed - there is nothing to trail
  
  // check if the data is valid
  if ( TralStart <= 0 || Step < 1 ) return(-1); 

  // Get the data for the Stop level size and risk percentage control!  
  Loss = AccountBalance() * MaxAllowedRisk / 100.0; // losses are set as a percentage of the balance
  OnePipCost = TickValue * OrderLots(); // recalculate the point value for the order lot

  if ( OrderType() == OP_BUY && CurBid >= TralStart ) 
  {
    if ( PrevPrice <= 0 ) 
    { 
      if ( ZeroLossTral   ) SL = NormalizeDouble(OrderOpenPrice() + Tral0LossGap*Point, Digits); 
      if ( HalfProfitTral ) SL = NormalizeDouble(OrderOpenPrice() + (CurBid - OrderOpenPrice())/2.0, Digits); 
      else                  SL = NormalizeDouble(OrderStopLoss(), Digits);
    }
    else SL = NormalizeDouble(OrderStopLoss() + (CurBid - PrevPrice), Digits);
    if ( SL < OrderStopLoss() ) return;
    NewLoss = ( OrderOpenPrice() - SL ) / Point * OnePipCost;
  }
  if ( OrderType() == OP_SELL && CurAsk <= TralStart )  
  {
    if ( PrevPrice <= 0 ) 
    { 
      if ( ZeroLossTral   ) SL = NormalizeDouble(OrderOpenPrice() - Tral0LossGap*Point, Digits); 
      if ( HalfProfitTral ) SL = NormalizeDouble(OrderOpenPrice() - (OrderOpenPrice() - CurAsk)/2.0, Digits); 
      else                  SL = NormalizeDouble(OrderStopLoss(), Digits);
    }
    else SL = NormalizeDouble(OrderStopLoss() - (PrevPrice - CurAsk), Digits);
    if ( SL > OrderStopLoss() ) return;
    NewLoss = ( SL - OrderOpenPrice() ) / Point * OnePipCost;
  }
  if ( SL <= 0 ) return; // the price has not yet crossed the trailing trigger level
  
  if ( NewLoss > Loss ) 
  { 
    SetError("Trailing Stoploss "+DoubleToStr(NewLoss/OnePipCost,0)
            +" > max available "+DoubleToStr(Loss/OnePipCost,0)); 
    ShowInfo(); 

return; 
  }

  if ( ( OrderType() == OP_BUY && SL - OrderStopLoss() >= Step*Point ) || 
      ( OrderType() == OP_SELL && OrderStopLoss() - SL >= Step*Point ) )
  {
    TXT = "• Tralingstop order. Please wait..."; 
    bool OK = OrderModify(OrderTicket(),OrderOpenPrice(),SL,OrderTakeProfit(),OrderExpiration(),Blue);
    if ( OK ) SetWarning("Traling stop moved to " + DoubleToStr(SL, Digits) 
                        +" at " + TimeToStr(TimeLocal(),TIME_SECONDS)); 
    else SetLastError("Tralingstop");
  }
  if ( PrevPrice <= 0 || OK )
  {  
    // only if we have moved the Trailing Stop, store the prices for the Trailing Stop on the next tick
    if ( OrderType() == OP_BUY  ) PrevPrice = CurBid;
    if ( OrderType() == OP_SELL ) PrevPrice = CurAsk;
  }
}


Mostrar información en la situación actual

Con el alcance de este artículo, hemos considerado sólo el problema relacionado con el trading en sí. Durante el funcionamiento del Asesor Experto, el código proporcionado en este artículo simplemente muestra un comentario corto con datos sobre el estado actual de las órdenes y del estado de la cuenta de trading. Todo puede hacerse de forma más precisa e informativa. De hecho, así lo hice. Mi versión válida de las salidas del sistema es información visual muy detallada sobre su funcionamiento con la ventana del widget estándar del sistema operativo Windows 7. Este será el tema de mi segundo artículo, ya que pretendo hablar de cosas que no se relacionan directamente con el trading. Pero sus usuarios hacen que el proceso de monitorización de un trade sea más cómodo. Suponga que tiene una orden abierta, con la posición de Trailing Stop calculada, y ahora sólo está esperando a que salte. Mientras espera, no tiene que tener la ventana de la terminal abierta. Siempre se queda por encima una pequeña ventana del widget que monitoriza la situación actual mientras usted puede hacer otras cosas, comprobándolo cada cierto tiempo.

Pero incluso sin el widget, el Asesor Experto está completamente preparado para funcionar. Sea lo que sea que falte, se puede añadir fácilmente a código para mostrar la información actual.

Lo único que merece la pena destacar al hablar de este bloque del Asesor Experto, es el mecanismo subyacente de la interfaz de los mensajes de error y el funcionamiento normal del Asesor Experto. Cada caso de excepción y cada mensaje de error se almacena en la línea variable especial: LastMsgTxt. Este texto se muestra en la pantalla durante MessageShowSec los segundos establecidos en los parámetros del indicador.



Trading basado en señales externas

El Asesor Experto hace trades basados en órdenes externas. Y la fuente de esas órdenes no tiene ninguna importancia para el Asesor Experto. Todo lo dicho anteriormente se puede aplicar al caso en el que una persona controla el Asesor Experto. Pero no sólo una persona puede configurar las variables globales en la terminal. Puede hacerlo cualquier indicador adjunto a la misma ventana. Veamos cómo se puede mejorar esto utilizando el indicador estándar RSI como ejemplo.

Se modificará el código fuente del cálculo del indicador añadiendo un "bloque analítico" que controle el Asesor Experto, al final del código, después de que todos los datos del buffer del indicador se hayan calculado. Este ejemplo implementa las siguientes reglas de apertura de una orden: una nueva orden se abre si el RSI cruza el nivel 52 en dirección de retroceso, o el nivel 48 en dirección ascendente.

Mostrará que no hay que preocuparse por haber cerrado una orden a la fuerza por el mecanismo de bloqueo incrustado, que previene aperturas múltiples y cierres automáticos de las órdenes en caso de que una posición se invierta. El mecanismo de trailing automático respetará al 50% la salida de beneficios en la intersección del nivel 45 y 55. No se puede decir que este sistema sea rentable. Se utiliza sólo con propósitos de demostración, muestra qué se necesita hacer en el código del indicador para prepararlo para controlar el funcionamiento del Asesor Experto, y cómo se hace.

// addition to #Trader ======================================================================
double DefaultStop = 150 * Point; // shifting the Stop level when opening an order

// the Buy condition
if( RSIBuffer[3] <= 50 && RSIBuffer[2] <= 52 && RSIBuffer[1] > 52 )
{
   GlobalVariableSet ( "#Trader-Chart", WindowHandle( Symbol(), Period()) ); 
   GlobalVariableSet ( "#Trader-Command", 1 );
   GlobalVariableSet ( "#Trader-Price", NormalizeDouble ( Close[0] - DefaultStop, Digits ) );
   GlobalVariableSet ( "#Trader-Time", TimeCurrent() );
}

// the Sell condition
if( RSIBuffer[3] >= 50 && RSIBuffer[2] >= 48 && RSIBuffer[1] < 48 ) 
{
   GlobalVariableSet ( "#Trader-Chart", WindowHandle( Symbol(), Period()) ); 
   GlobalVariableSet ( "#Trader-Command", 1 );
   GlobalVariableSet ( "#Trader-Price", NormalizeDouble ( Close[0] + DefaultStop, Digits ) );
   GlobalVariableSet ( "#Trader-Time", TimeCurrent() );
}

// 50% trailing start
if( ( RSIBuffer[2] >= 45 && RSIBuffer[1] < 45 ) || ( RSIBuffer[2] <= 55 && RSIBuffer[1] > 55 ) ) 
{
   GlobalVariableSet ( "#Trader-Chart", WindowHandle( Symbol(), Period()) );
   GlobalVariableSet ( "#Trader-Command", 7 );
   GlobalVariableSet ( "#Trader-Price", NormalizeDouble ( Close[0], Digits ) );
   GlobalVariableSet ( "#Trader-Time", TimeCurrent() );
}
// addition to #Trader ======================================================================

Importante: estos indicadores sólo se pueden probar en el modo de visualización y no se pueden optimizar. A continuación hay un fragmento de la prueba del indicador RSI, en el que se realizan aperturas y cierres en respuesta a las órdenes del indicador.

Otra posibilidad interesante que aparece cuando se hace trading basado en señales externas, es la de implementar un mirror trading en varias terminales en diferentes cuentas. Los problemas de la interacción de cruce de programas va más allá del ámbito de esta serie de artículos. Sin embargo, la idea detrás de una implementación así es bastante obvia: sobre manejar la orden o generarla en el script, una de as terminales que está involucrada actualmente en el trading, debería pasar los parámetros obtenidos a otra terminal donde los recibirá otro Asesor Experto o indicador. El mismo control de las variables globales se creará entonces en otra terminal y el Asesor Experto correspondiente de la segunda terminal las ejecutará, de la misma manera que las ejecuta el Asesor Experto de a primera terminal.



Resumen

Vamos a resumir los puntos claves implementados en el método propuesto de automatización manual de trading:

  • Los componentes de orden y ejecución del sistema de trading están divididos en dos partes: los scripts de control dan órdenes y configuran sus parámetros basados en los del funcionamiento del Asesor Experto. Permite expandir fácilmente la funcionalidad añadiendo nuevas características. Para ello, hay que añadir un nuevo código de funcionamiento, un script que pasará este código al Asesor Experto y ordenará el control apropiado en el Asesor Experto.
  • Se utiliza la misma orden para configurar los parámetros del control de órdenes y para determinar el tipo de acción a realizar.El nivel de precio de Stop en la apertura define la dirección del trading, y en los casos en los que se necesita la modificación, determina si se debe aplicar a Stop Loss o a Take Profit.
  • El mecanismo responsable para la apertura y la modificación de las órdenes, así como los procedimientos de gestión monetaria construidos en el Asesor Experto, evitarán que pierda más del valor inicial especificado del riesgo expresado como porcentaje del balance disponible.
  • En lugar del mecanismo estándar de Take Profit que corta el beneficio, el Asesor Experto emplea el algoritmo "dejar que los beneficios fluyan" que, en lugar de cerrar una orden con beneficios en el nivel de Take Profit, sigue de cerca el crecimiento de los beneficios.
  • El uso de las variables globales de la terminal para el intercambio de datos entre scripts y Asesores Expertos le permite utilizar fácilmente un mismo código para trabajar con cuentas en directo y en el modo de visualización del Tester de estrategias.
  • Las órdenes de trade se pueden pasar al Asesor Experto no sólo por la orden del script, sino también por cualquier indicador cuyo código fuente se pueda modificar añadiendo un bloque para la creación de una orden de variables globales en los puntos de generación de señal del indicador. El trading basando en estas señales del indicador se pueden probar en el tester estándar de la terminal. Esto puede ser muy útil en la identificación de a recomposición de los indicadores casi rentables.

El archivo adjunto contiene los códigos fuente del Asesor Experto #Trader, junto con todos los scripts de control y el ejemplo del indicador RSI con el mecanismo responsable de paso del control al Asesor Experto.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/1363

Archivos adjuntos |
experts.zip (40.86 KB)
Sistema de trading mecánico "Triángulo de Chuvashov" Sistema de trading mecánico "Triángulo de Chuvashov"
Les voy a dar un resumen y el código de programa del sistema de trading mecánico basado en las ideas de Stanislav Chuvashov. La construcción del triángulo se basa en la intersección de dos líneas de tendencias construidas por los fractales más altos y los más bajos.
El Asesor Experto MetaTrader 4 intercambia información con el mundo exterior El Asesor Experto MetaTrader 4 intercambia información con el mundo exterior
Una solución de intercambio de información simple, universal y fiable entre el Asesor Experto MetaTrader 4 y el mundo exterior. Los proveedores y los consumidores de la información pueden estar en diferentes ordenadores, la conexión se realiza a través de direcciones IP globales.
LibMatrix: Librería de Álgebra Matrix (Parte uno) LibMatrix: Librería de Álgebra Matrix (Parte uno)
El autor familiariza a los lectores con una librería de álgebra matrix simple y ofrece descripciones y peculiaridades de las funciones principales.
La sandbox aleatoria La sandbox aleatoria
El artículo incluye una "sandbox" interactiva como archivo Excel que simula datos de backtest de un Asesor Experto aleatorio. Los lectores pueden utilizar esto para ayudarse a explorar y comprender mejor el funcionamiento de los parámetros del AE por defecto con MetaTrader. El texto del artículo está diseñado para guiar al usuario a través de esta experiencia.