Discusión sobre el artículo "Cálculo de expresiones matemáticas (Parte 2). Parsers de Pratt y shunting yard"

 

Artículo publicado Cálculo de expresiones matemáticas (Parte 2). Parsers de Pratt y shunting yard:

En el presente artículo, estudiaremos los principios de análisis y cálculo de expresiones matemáticas con ayuda de parsers basados en la prioridad de los operadores; implementaremos los parsers de Pratt y shunting yard, y la generación de código de bytes y el cálculo según este. Además, mostraremos el uso de los indicadores como funciones en las expresiones, y también el ajuste de las señales comerciales en los expertos con la ayuda de dichos indicadores.

Si iniciamos un experto en el simulador, seguramente obtengamos un informe con valores por debajo de la media, pero lo que importa es otra cosa: el comercio se estará realizando, y serán los parsers quienes se encargarán de él. Aunque no ofrecen sistemas comerciales rentables ya preparados, sí que constituyen una herramienta para buscar estos.

Ejemplo de comercio según la señales calculadas con las expresiones

Ejemplo de comercio según la señales calculadas con las expresiones

Autor: Stanislav Korotky

 
Cuando compare el rendimiento, compárelo con MQL puro.
 

La comparación del rendimiento teniendo en cuenta el MQL5 nativo es la siguiente:

ExpresSParserS (EURUSD,D1)      Evaluation: 105109
ExpresSParserS (EURUSD,D1)      Compilation: 26090
ExpresSParserS (EURUSD,D1)      Pratt bytecode: 24030
ExpresSParserS (EURUSD,D1)      Pratt: 26567
ExpresSParserS (EURUSD,D1)      ShuntingYard: 23884
ExpresSParserS (EURUSD,D1)      MQL5: 12901

MQL5 es unas 2 veces más rápido que los analizadores sintácticos más rápidos presentados.

Añadido código de prueba:

class FuncCalc
{
  private:
    double a;
    double b;
    double c;
  public:
    void setup(double _a, double _b, double _c)
    {
      a = _a;
      b = _b;
      c = _c;
    }
    double execute()
    {
      return (a + b) * (c > 10000 ? c / 4 : c * 4);
    }
};

ulong testMQL5(const int n)
{
  ulong ul = 0, total = 0;
  double r;
  FuncCalc f;

  for(int i = 0; i < n; i++)
  {
    f.setup(rand(), rand(), rand());
    ul = GetMicrosecondCount();
    r = f.execute();
    total += GetMicrosecondCount() - ul;
  }
  return total;
}

Esta es una estimación aproximada. Aún queda mucho por investigar (por ejemplo, con diferentes tipos de expresiones) y optimizar el analizador sintáctico.

 

ahora sólo puedo elogiar.

Por supuesto que debería haber mencionado a Dijkstra, ya que históricamente el Patio de Tiro se asocia más con él.

Tuve la idea de hacer un artículo similar, incluso estaba mecanografiando el material para mí, me ganaste (sobre la parte 2), pero tenía la costumbre de rodar todo en máquinas de fuerte y pila.

¡te las arreglaste para no enrollar el artículo en ella (o ceceo) !

La guinda del pastel sería el combinador Y.

PD: Pero los bytecodes te han quedado "anchos" y te matan las clases. Se puede silbar y tolerar 64 bits. Bueno, el jefe es el jefe :-)

 
Maxim Kuznetsov:

ahora sólo puedo alabar.

Bueno, por supuesto que valdría la pena mencionar a Dijkstra, ya que históricamente el Shooting Yard se asocia más con él

Tuve la idea de hacer un artículo similar, incluso estaba escribiendo el material para mí, me ganaste (sobre la parte 2), pero tenía todas las cosas habituales rodó en las máquinas de fuerte y pila

¡te las arreglaste para no rodar el artículo en él (o lisp) !

La guinda del pastel sería el Y-combinador.

PD: Pero tus bytecodes parecen "demasiado anchos" y los matan las clases. Puedes silbar y tolerar 64 bits. Bueno, el jefe es el jefe :-)

Puedes escribir una secuela con reducción de byte-code, aceleración y nuevos tipos de parsers. No he conseguido abarcarlo todo, de hecho, esperaba escribir un artículo, pero como siempre no me cabía.

 
Stanislav Korotky:

Puedes escribir una secuela con la reducción del código de bytes, la aceleración y los nuevos tipos de analizadores sintácticos. No he conseguido abarcarlo todo, de hecho esperaba escribir un solo artículo, pero como siempre no cabía.

El bytecode depende de la máquina virtual. Por un lado, estoy tentado de dar 128 bits o más para el op-code "suma de dos números" ....

y aún no se han inventado nuevos tipos de analizadores sintácticos, todos tienen años ;-) y sólo hay 2 y medio.

PS la estación de clasificación para las necesidades de los usuarios de terminales está por las nubes - se puede introducir una fórmula familiar en el campo de entrada y obtener el resultado.

 
A diferencia de otros artículos, estos dos son muy buenos. Claros, detallados y accesibles. Gracias.
 
La versión actualizada de las calculadoras 1.1 se adjunta al artículo sobre la optimización por enjambre de partículas. Además hay una pequeña corrección de errores en la discusión.
Параллельная оптимизация методом роя частиц (Particle Swarm Optimization)
Параллельная оптимизация методом роя частиц (Particle Swarm Optimization)
  • www.mql5.com
Как известно, MetaTrader 5 позволяет оптимизировать торговые стратегии с помощью встроенного тестера на основе двух алгоритмов: прямого перебора входных параметров и генетики (генетический алгоритм - ГА). Генетическая оптимизация является одной из разновидностей эволюционных алгоритмов, которые предоставляют значительное ускорение процесса...
 
Por favor, muestre cómo utilizar un analizador sintáctico de dicha cadena.
"(EURUSD^2) / (GBPUSD * AUDUSD)"

La dificultad es que necesitamos determinar automáticamente en qué caso y dónde sustituir bid/ask.

En el ejemplo anterior debería ser así.

Value_Bid = (EURUSD_Bid * EURUSD_Bid / (GBPUSD_Ask * AUDUSD__Ask);
Value_Ask = (EURUSD_Ask * EURUSD_Ask / (GBPUSD_Bid * AUDUSD__Bid);


El algoritmo para determinar Bid/Ask es así. Usando el mismo ejemplo.

F(EURUSD, GBPUSD, AUDUSD) = (EURUSD^2) / (GBPUSD * AUDUSD);

bool EURUSD_flag = (F(1, 1, 1) < F(2, 1, 1));
bool GBPUSD_flag = (F(1, 1, 1) < F(1, 2, 1));
bool AUDUSD_flag = (F(1, 1, 1) < F(1, 1, 2));

Value_Bid = F(EURUSD_flag ? EURUSD_Bid : EURUSD_Ask,
              GBPUSD_flag ? GBPUSD_Bid : GBPUSD_Ask,
              AUDUSD_flag ? AUDUSD_Bid : AUDUSD_Ask);

Value_Ask = F(EURUSD_flag ? EURUSD_Ask : EURUSD_Bid,
              GBPUSD_flag ? GBPUSD_Ask : GBPUSD_Bid,
              AUDUSD_flag ? AUDUSD_Ask : AUDUSD_Bid);
 
fxsaber:
Por favor, muéstreme cómo utilizar el analizador sintáctico para una cadena de este tipo.

La principal dificultad es determinar los nombres de todas las variables en la expresión. Para que pueda escribir algo similar.

TestSuiteEvaluator evaluator("EURUSD=1.5;GBPUSD=2.5;AUDUSD=5");
 
Desde el punto de vista del analizador sintáctico, una variable no puede tener 2 valores: bid y ask. Probablemente sea posible envolver los componentes en funciones (ya sea introducir funciones Bid(símbolo), Ask(símbolo), o toda la función "cesta" si el número de componentes está predefinido). Básicamente, el problema original no está claro: si estamos hablando de una sintética/cesta de tres símbolos, entonces en ella cada componente es adquirido inequívocamente por Ask o Bid, dependiendo de la dirección. También se puede considerar la opción de diferentes expresiones dependiendo de la dirección de las transacciones.