Sistemi Esperti: MQL5 Programming for Traders – Source Codes from the Book. Parte 6 - pagina 2

 
Stanislav Korotky #:
Gli ordini, le operazioni e le posizioni non sono comunque legati ai timeframe. O avete frainteso qualcosa o la vostra formulazione non è corretta.
Mi dispiace, ma credo che la mia scelta di parole sia confusa: con"timeframe" intendo "intervallo di date". Diciamo che voglio selezionare le transazioni/ordini effettuati in un determinato intervallo di date, ad esempio le transazioni dal 2025-10-01 00:00:00 al 2025-10-22 23:59:59.
 
pauldic #:
Mi dispiace, ma credo che la mia scelta di parole sia confusa: per"intervallo di tempo" intendo "intervallo di date". Diciamo che voglio selezionare le transazioni/ordini effettuati in un determinato intervallo di date, come ad esempio le transazioni dal 2025-10-01 00:00:00 al 2025-10-22 23:59:59.

Se si desidera analizzare un sottoinsieme della cronologia delle transazioni, è più efficiente richiedere solo questa parte della cronologia prima del filtraggio, senza influenzare il codice di filtraggio stesso:

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

...

{
   HistorySelect(SubrangeFrom, SubrangeTo);
   // ... Il codice del filtro va qui così com'è
}

Se, per qualche motivo, si desidera selezionare un sottoinsieme (più ristretto) all'interno dell'intervallo globale applicato con HistorySelect, è ancora possibile farlo nel codice di filtraggio in questo modo:

{
      // alcuni di questi vanno qui

      // 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 riga evidenziata in giallo imposta due condizioni per l'intervallo di date [SubrangeFrom, SubrangeTo] utilizzando i qualificatori aggiuntivi IS::GREATER e IS::LESS (per impostazione predefinita, non sono specificati in altre chiamate a let() e IS::EQUAL è normalmente utilizzato per i campi a valore singolo).

Conosco solo un motivo per applicare il sottofiltro per intervallo di date: è per il tempo di preparazione degli ordini (ORDER_TIME_SETUP), perché HistorySelect viene applicato a un'altra proprietà datetime degli ordini, ovvero il tempo di esecuzione dell'ordine (ORDER_TIME_DONE). Inoltre, potrebbe essere interessante filtrare un sottogruppo di ordini attivi (non presenti nella cronologia), se ce ne sono molti.

Come punto di partenza si può consultare lo script di esempio MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5.
 
Stanislav Korotky #:

Se si desidera analizzare un sottoinsieme della cronologia di trading, è più efficiente richiedere solo questa parte della cronologia prima del filtraggio, senza influenzare il codice di filtraggio stesso:

Se, per qualche motivo, si desidera selezionare un sottoinsieme (più ristretto) all'interno dell'intervallo globale applicato con HistorySelect, è ancora possibile farlo nel codice di filtraggio in questo modo:

La linea evidenziata in giallo imposta due condizioni per l'intervallo di date [SubrangeFrom, SubrangeTo] utilizzando i qualificatori aggiuntivi IS::GREATER e IS::LESS (per impostazione predefinita, non sono specificati in altre chiamate a let() e IS::EQUAL è normalmente utilizzato per campi a valore singolo).

Conosco solo un motivo per applicare il sottofiltro per intervallo di date: è per il tempo di preparazione degli ordini (ORDER_TIME_SETUP), perché HistorySelect viene applicato a un'altra proprietà datetime degli ordini, ovvero il tempo di esecuzione dell'ordine (ORDER_TIME_DONE). Inoltre, potrebbe essere interessante filtrare un sottogruppo di ordini attivi (non presenti nella cronologia), se ce ne sono molti.

Come punto di partenza si può consultare lo script di esempio MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5.
@StanislavKorotky Grazie ancora... È un ottimo punto di partenza per me e inizierò a lavorarci.
 

Correzione del bug 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)));
   }
File:
TradeUtils.mqh  12 kb
 
pauldic #:

Utilizzare ilpulsante CODICE (Alt-S) quando si inserisce il codice.

Un moderatore ha formattato il codice incollato in modo errato. Di solito, tale codice viene rimosso.

@StanislavKorotky Per favore, potete aiutarmi a esaminare questo errore, credo che sia iniziato dopo gli aggiornamenti di MT5 perché sapevo che il codice funzionava nei mesi precedenti senza alcuna modifica.

la conversione del tipo di parametro 'long[][2]' in 'string[][] &' non è consentita SymbolFilter.mqh 199 20

il tipo di conversione dei parametri 'double[][2]' in 'string[][] &' non è consentito TradeFilter.mqh 332 20
la conversione del tipo di parametro 'long[][2]' in 'string[][] &' non è consentita TradeFilter.mqh 163 17


Sospetto che il codice seguente possa aiutare a replicare il problema:


Ciao @Paul Dick

Provare questo https://www.mql5.com/it/code/57233 per l'ordinamento degli array

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.
 

Allego una versione aggiornata del file di calcolo del criterio diottimizzazione personalizzato basato su R2 - RSquared.mqh, in cui è stato corretto il calcolo per il caso di lotti variabili.

La qualità della stima è stata notevolmente migliorata: a giudicare dalla tabella dei risultati dell'ottimizzazione, è stata ottenuta la combinazione del fattore di recupero e dei parametri di Sharpe.

Esempio di utilizzo.

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[]; // Utilizzato solo per corrispondere al prototipo 'select', ma utile per il debug
   
   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[]; // prendere in considerazione i volumi di scambio per l'utilizzo del 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];
      }
      // utilizzare i volumi come modello - più investimenti - più rendimenti attesi
      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;
}
File:
RSquared.mqh  4 kb