Asesores Expertos: Programación en MQL5 para tráders: códigos fuente del libro: Parte 6. - página 2

 
Stanislav Korotky #:
De todos modos, las órdenes, las operaciones y las posiciones no están relacionadas con los plazos. O ha entendido algo mal o su redacción es incorrecta.
Lo siento, creo que mi elección de la palabra es confusa por"marco de tiempo" me refiero a "rango de fechas". Digamos que quiero seleccionar Operaciones/Ordenes transaccionadas dentro de un rango de fechas dado como por ejemplo Operaciones desde 2025-10-01 00:00:00 hasta 2025-10-22 23:59:59.
 
pauldic #:
Lo siento, creo que mi elección de palabras es confusa, por"marco de tiempo" me refiero a "intervalo de fechas". Digamos que quiero seleccionar transacciones/pedidos realizados dentro de un intervalo de fechas determinado, por ejemplo, transacciones desde 2025-10-01 00:00:00 hasta 2025-10-22 23:59:59.

Si se quiere analizar un subrango de un histórico de operaciones, cuando es más eficiente solicitar sólo esta parte del histórico antes del filtrado, sin afectar al propio código de filtrado:

input datetime SubrangeFrom = 0;
input datetime SubrangeTo = 0;

...

{
   HistorySelect(SubrangeFrom, SubrangeTo);
   // ... el código del filtro va aquí tal cual
}

Si, por alguna razón, desea seleccionar un subrango (más estrecho) dentro del rango global que aplicó con HistorySelect, entonces todavía puede hacerlo en el código de filtrado así:

{
      // algunos de ellos van aquí

      // HistorySelect(0, LONG_MAX);
      // HistorySelectByPosition(PositionID);
      ...
      DealTuple deals[];
      if(SubrangeFrom != SubrangeTo && SubrangeFrom < SubrangeTo)
      {
         filter.let(DEAL_TIME, SubrangeFrom - 1, IS::GREATER).let(DEAL_TIME, SubrangeTo + 1, IS::LESS);
      }
      filter.let(DEAL_POSITION_ID, PositionID).select(deals, true);
      ...
}

La línea resaltada en amarillo establece 2 condiciones para el rango datetime [SubrangoDesde, SubrangoHasta] utilizando calificadores adicionales IS::MAYOR y IS::MENOR (por defecto, no se especifican en otras llamadas a let(), y entonces IS::IGUAL se utiliza normalmente para campos de valor único).

Sólo conozco una razón para aplicar el subfiltro por intervalo de fechas - es para el tiempo de preparación de las órdenes (ORDER_TIME_SETUP), porque HistorySelect se aplica a otra propiedad datetime de las órdenes - a saber, el tiempo de ejecución de la orden (ORDER_TIME_DONE). También puede ser interesante filtrar un subrango de órdenes activas (no en el histórico), si hay muchas.

Puede mirar el ejemplo de script MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5, como punto de partida.
 
Stanislav Korotky #:

Si desea analizar un subrango de un historial de operaciones, cuando sea más eficiente solicitar sólo esta parte del historial antes del filtrado, sin afectar al propio código de filtrado:

Si, por alguna razón, desea seleccionar un subrango (más estrecho) dentro del rango global que aplicó con HistorySelect, entonces todavía puede hacerlo en el código de filtrado así:

La línea resaltada en amarillo establece 2 condiciones para el rango datetime [SubrangoDesde, SubrangoHasta] utilizando calificadores adicionales IS::MAYOR y IS::MENOR (por defecto, no se especifican en otras llamadas a let(), y entonces IS::IGUAL se utiliza normalmente para campos de valor único).

Sólo conozco una razón para aplicar el subfiltro por intervalo de fechas - es para el tiempo de preparación de las órdenes (ORDER_TIME_SETUP), porque HistorySelect se aplica a otra propiedad datetime de las órdenes - a saber, el tiempo de ejecución de la orden (ORDER_TIME_DONE). También puede ser interesante filtrar un subrango de órdenes activas (no en el histórico), si hay muchas.

Puedes mirar el script de ejemplo MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5, como punto de partida.
@StanislavKorotky Gracias una vez más... Es un gran punto de partida para mí y voy a empezar a trabajar con él
 

Corrección de errores MQL5/Include/MQL5Book/TradeUtils.mqh.

   bool Equal(const double v1, const double v2)
   {
      return v1 == v2 || fabs(v1 - v2) < DBL_EPSILON * fmax(1.0, fmax(fabs(v1), fabs(v2)));
   }
Archivos adjuntos:
TradeUtils.mqh  12 kb
 
pauldic #:

Utilice elbotón CÓDIGO (Alt-S) al insertar código.

Un moderador ha formateado el código pegado incorrectamente. Normalmente, dicho código se elimina.

@StanislavKorotky Por favor, ¿puede ayudar a mirar en este error, creo que comenzó después de las actualizaciones MT5 porque sabía que el código funciona en los meses anteriores sin ninguna modificación.

parámetro tipo de conversión 'long[][2]' a 'string[][] &' no está permitido SymbolFilter.mqh 199 20

tipo de conversión de parámetro 'double[][2]' a 'string[][] &' no está permitido TradeFilter.mqh 332 20
la conversión del parámetro 'long[][2]' en 'string[][] &' no está permitida TradeFilter.mqh 163 17


Sospecho que el siguiente código ayudará a reproducir el problema:


Hola @Paul Dick

Prueba este https://www.mql5.com/es/code/57233 para ordenar matrices

Introsort (Introspective sort) using Function Pointers
Introsort (Introspective sort) using Function Pointers
  • 2025.03.18
  • www.mql5.com
A hybrid sorting algorithm that provide fast performance for sorting arrays of simple types, structures or object pointers.
 

Adjunto una versión actualizada del archivo de cálculo del criterio deoptimización personalizado basado en R2 - RSquared.mqh, en la que se ha corregido el cálculo para el caso de lotes variables.

Se ha mejorado notablemente la calidad de la estimación - a juzgar por la tabla de resultados de la optimización, se ha obtenido la combinación del factor de recuperación y los parámetros de Sharpe.

Ejemplo de utilización.

double OnTester()
{
   HistorySelect(0, LONG_MAX);
   
   #define  STAT_PROPS 5
   
   const ENUM_DEAL_PROPERTY_DOUBLE props[STAT_PROPS] =
   {
      DEAL_PROFIT, DEAL_SWAP, DEAL_COMMISSION, DEAL_FEE, DEAL_VOLUME
   };
   double expenses[][STAT_PROPS];
   ulong tickets[]; // usado aquí sólo para coincidir con el prototipo 'select', pero útil para depuración
   
   DealFilter filter;
   filter.let(DEAL_TYPE, (1 << DEAL_TYPE_BUY) | (1 << DEAL_TYPE_SELL), IS::OR_BITWISE)
      .let(DEAL_ENTRY, (1 << DEAL_ENTRY_OUT) | (1 << DEAL_ENTRY_INOUT) | (1 << DEAL_ENTRY_OUT_BY), IS::OR_BITWISE)
      .select(props, tickets, expenses);

   const int n = ArraySize(tickets);
   
   double balance[];
   double volumes[]; // tener en cuenta los volúmenes comerciales para utilizar el criterio R2
   
   ArrayResize(balance, n + 1);
   balance[0] = 0;
   ArrayResize(volumes, n + 1);
   volumes[0] = 0;
   
   for(int i = 0; i < n; ++i)
   {
      double result = 0;
      for(int j = 0; j < STAT_PROPS - 1; ++j)
      {
         result += expenses[i][j];
      }
      // utilizar los volúmenes como modelo - más inversiones - más beneficios esperados
      volumes[i + 1] = expenses[i][STAT_PROPS - 1] + volumes[i];
      balance[i + 1] = result + balance[i];
   }
   
   const double r2 = RSquaredTest(balance, volumes);
   
   #undef  STAT_PROPS
   
   return r2 * 100;
}
Archivos adjuntos:
RSquared.mqh  4 kb