English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
L'Uso di ORDER_MAGIC per il Trading con Diversi Expert Advisor su un Singolo Strumento

L'Uso di ORDER_MAGIC per il Trading con Diversi Expert Advisor su un Singolo Strumento

MetaTrader 5Esempi | 16 dicembre 2021, 10:44
452 0
Mykola Demko
Mykola Demko


Introduzione

In MQL5 abbiamo la capacità di assegnare un numero magico a ciascun ordine in sospeso, al fine di utilizzare queste informazioni per identificare l'ordine. Ciò apre vaste possibilità di interazione tra diversi Expert Advisor e lo sviluppo di sistemi ancora più complessi. In questo articolo, vorrei informare il pubblico sulle opportunità sottovalutate del numero Magico.

Ma prima di procedere all'essenza dell'argomento di questo articolo, dobbiamo acquisire una migliore comprensione di ciò che costituisce il numero Magico. Cosa potrebbe essere magico in un numero che determina quale Expert Advisor lo ha impostato? I "miracoli" iniziano con le opportunità che gli sviluppatori stabiliscono nel tipo ulong, che è dichiarato dal numero Magico.

Il tipo ulong è il più lungo

Se osserviamo nel dettaglio il tipo intero long, vediamo che il valore massimo di questo tipo è semplicemente fenomenale:

Tipo

Dimensione in byte

Valore Minimo

Valore Massimo

Analogico nel linguaggio C + +

long

8

-9 223 372 036 854 775 808

9 223 372 036 854 775 807

__int64

ulong

8

0

18 446 744 073 709 551 615

unsigned __int64

Tabella 1 Proprietà dei tipi di dati long e ulong

ma il tipo ulong lo ha superato combinando la mantissa positiva e negativa.

Quindi, la lunghezza specificata è enorme, ma come è stata usata prima?

Nella mia esperienza di lavoro in mql 4, ho spesso notato l'insensatezza della codifica del numero Magico da parte di molti sviluppatori. Il numero Magico è stato usato in modo sensato, ma la sua codifica sembrava abbastanza sciocca. Cosa si può dire dell'individualità del numero Magico 12345, tale Magico è utilizzato da quasi la metà della fraternità in via di sviluppo. La seconda metà utilizza il numero Magico 55555, 33333 e 77777, e questo è praticamente il set completo. Voglio attirare l'attenzione del lettore sul fatto che è improbabile che il suo computer abbia più di 1.000 Expert Advisor, quindi il numero 1000 sarà sufficiente per codificare il nome individuale di tutti i tuoi Expert Advisor.

1000 - sono solo 3 categorie complete, quindi cosa dovremmo fare con le restanti 15 che sono disponibili nel tipo ulong? La risposta è semplice: codificarli.

Cosa dice Wikipidia sulla parola codice:

The Code - regola (algoritmo), il confronto per ogni singolo messaggio di una combinazione strettamente particolare di simboli (caratteri) (o segnali).

Pertanto, stabiliremo le regole. Propongo di prescrivere nel codice del numero Magico, non solo l'ID dell'Expert Advisor, ma anche lo strumento su cui è in esecuzione. Il fatto che l'Expert Advisor sia in esecuzione, ad esempio, su EURUSD, non significa che l'Expert Advisor visualizzerà un ordine solo su tale strumento. Inoltre, penso che sarà utile scrivere il codice di interazione degli Expert Advisor, qualcosa come "tuo/straniero", in modo che l'Expert Advisor, quando controlla le posizioni, possa capire che l'ordine corrente è costruito da un Expert Advisor amichevole. Penso che questo sarà sufficiente per creare un sistema molto complesso.

E quindi riassumiamo ciò che abbiamo: quali opportunità stiamo mettendo nel sistema:

  1. La possibilità di due o più Expert Advisor di lavorare su un unico strumento e non interferire.
  2. La possibilità di due o più Expert Advisor di lavorare su strumenti diversi e completarsi a vicenda.
  3. La capacità di identificare l'ordine dallo strumento, lavorando con l'Expert Advisor.

E così, il compito è impostato, iniziamo ora la sua attuazione.

Semplice Expert Advisor

Redigere il codice del semplice Expert Advisor, ad esempio, tenere la posizione nella direzione del Moving. Penso che il lettore che ha deciso di analizzare il numero Magico, abbia già letto l'articolo Guida Passo Dopo Passo alla Scrittura di un Expert Advisor in MQL5 per Principianti, in caso contrario, consiglio vivamente di farlo, poiché non entrerò nei dettagli della creazione dell'Expert Advisor. Fondamentalmente, l'Expert Advisor aprirà la posizione una volta e la girerà per tutte le altre volte. Pertanto, avremo bisogno della funzione per aprire la posizione, cioè per inserire la richiesta di trading (ordine di trading).

Crea una classe ausiliaria, che calcolerà i parametri per noi per riempire i campi della struttura della richiesta di trading.

//+------------------------------------------------------------------+
//| The class provides auxiliary trading calculations                |
//+------------------------------------------------------------------+
class CProvision
  {
protected:
   MqlTradeRequest   trades;                 // pointer to the request structure of OrderSend
public:
   int               TYPE(const double &v[]);  // determines the type, in respect to the  readings of the moving
   double            pricetype(int type);     // calculates the level of the opening, in respect to the type 
   double            SLtype(int type);        // calculates the level of the stop-loss in respect to the type
   double            TPtype(int type);        // calculates the level of the take-profit, in respect to the type
   long              spread();               // returns the spread of the current instrument
   int               SendOrder(ENUM_ORDER_TYPE type,double volume);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CProvision::SendOrder(ENUM_ORDER_TYPE type,double volume)
  {
   trades.action          =TRADE_ACTION_DEAL;       // Type of the implemented actions
   trades.magic           =magic;                 // Stamp of the Expert Advisor (identifier of the magic number)
   trades.symbol          =_Symbol;                // Name of the trading instrument
   trades.volume          =volume;                // Request the volume of the trade in lots
   trades.price           =pricetype((int)type);  // Price       
   trades.sl              =SLtype((int)type);     // Level of Stop Loss order
   trades.tp              =TPtype((int)type);     // Level of Take Profit order         
   trades.deviation=(int)spread();                // Maximum acceptable deviation from the requested price
   trades.type=type;                              // Order type
   trades.type_filling=ORDER_FILLING_FOK;
   if(OrderSend(trades,res)){return(res.retcode);}
   return(-1);
  }
//+------------------------------------------------------------------+
//| Determines the type, in respect to the reading of the moving     |
//+------------------------------------------------------------------+
int CProvision::TYPE(const double &v[])
  {
   double t=v[0]-v[1];
   if(t==0.0)t=1.0;
   return((int)(0.5*t/fabs(t)+0.5));
  }
//+------------------------------------------------------------------+
//| Calculates the level of opening in respect to the type           |
//+------------------------------------------------------------------+
double CProvision::pricetype(int type)
  {
   if(SymbolInfoTick(_Symbol,tick))
     {
      if(type==0)return(tick.ask);
      if(type==1)return(tick.bid);
     }
   return(-1);
  }
//+------------------------------------------------------------------+
//| Calculates the level of stop-loss in respect to the type         |
//+------------------------------------------------------------------+
double CProvision::SLtype(int type)
  {
   if(SymbolInfoTick(_Symbol,tick))
     {
      if(type==0)return(tick.bid-SL*SymbolInfoDouble(Symbol(),SYMBOL_POINT));
      if(type==1)return(tick.ask+SL*SymbolInfoDouble(Symbol(),SYMBOL_POINT));
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| Calculates the level of timeframe in respect to the type         |
//+------------------------------------------------------------------+
double CProvision::TPtype(int type)
  {
   if(SymbolInfoTick(_Symbol,tick))
     {
      if(type==0)return(tick.bid+TP*SymbolInfoDouble(Symbol(),SYMBOL_POINT));
      if(type==1)return(tick.ask-TP*SymbolInfoDouble(Symbol(),SYMBOL_POINT));
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| Returns the spread                                               |
//+------------------------------------------------------------------+
long CProvision::spread() 
  {
   return(SymbolInfoInteger(_Symbol,SYMBOL_SPREAD));
  }

Avendo una classe del genere, possiamo scrivere un codice per un semplice Expert Advisor senza problemi: 

//+------------------------------------------------------------------+
//| Code of the Expert Advisor                                       |
//+------------------------------------------------------------------+

//--- Input parameters
input ulong              magic       =1;           // magic
input int                SL          =300;         // Stop Loss
input int                TP          =1000;        // Take Profit
input int                MA_Period   =25;         // MA period
input double             lot         =0.1;         // Volume of position
input int                MA_shift    =0;          // Shift of indicator
input ENUM_MA_METHOD     MA_smooth   =MODE_SMA;     // Smoothing type
input ENUM_APPLIED_PRICE price       =PRICE_OPEN;    // Price type 

//--- We will store the indicator's handle
int
MA_handle,     // Handle of the indicator
type_MA,       // Type that specify the direction of MA
rezult;        // The variable takes the value of the result of the OrderSend operation
double v[2];    // Buffer for receiving values of MA

MqlTradeResult   res;   // Pointer to the structure of responding by OrderSend
MqlTick         tick;  // Pointer to the structure of last market information
CProvision      prov;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Create the indicator's handle
   MA_handle=iMA(Symbol(),0,MA_Period,MA_shift,MA_smooth,price);
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CopyBuffer(MA_handle,0,0,2,v)<=0)
     {Print("#",magic,"Error of copying");return;}
   type_MA=prov.TYPE(v); // Determine type depending on MA indication

   if(PositionSelect(_Symbol))// If there is an open position 
     {
      if(PositionGetInteger(POSITION_TYPE)!=type_MA)// Check if its time to close
        {
         Print("#",magic,"Position by magic number has volume ",PositionGetDouble(POSITION_VOLUME),
               " reverse position of type ",PositionGetInteger(POSITION_TYPE)," by ",type_MA);
         rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,PositionGetDouble(POSITION_VOLUME)+lot);
         // reverse the position
         if(rezult!=-1)Print("#",magic," Code of the operation result ",rezult," volume ",res.volume);
         else{Print("#",magic,"Error",GetLastError()); return;}
        }
     }
   else // If there is no open position then open
     {
      Print("#",magic,"Position by magic number has volume ",PositionGetDouble(POSITION_VOLUME),
            " open position of type ",type_MA);
      rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,lot);
      // open position 
      if(rezult!=-1)Print("#",magic," Code of operation result ",rezult," volume ",res.volume);
      else{Print("#",magic,"Error",GetLastError()); return;}
     }
  } 

Eseguilo e assicurati che l’Expert Advisor non differisca in termini di redditività, ma scambi esattamente secondo la logica specificata, che è esattamente ciò di cui abbiamo bisogno da esso.

Figura1. Il lavoro di un Expert Advisor su un singolo strumento

Figura 1. Il lavoro di un Expert Advisor su un singolo strumento

Ora proveremo a eseguire questo EA, ma su diversi time frame di uno strumento (per gli esperimenti abbiamo scelto uno strumento casuale, che è EURUSD: o)

Figura2. Il conflitto di due Expert Advisor sullo stesso strumento su timeframe diversi

Figura 2. Il conflitto di due Expert Advisor sullo stesso strumento su timeframe diversi

Poiché entrambi gli Expert Advisor sono in esecuzione su un singolo strumento e il codice non specifica la condivisione delle posizioni, entrambi gli Expert Advisor stanno cercando di correggere la posizione di trading, a seconda delle letture dei loro indicatori, e come conseguenza di ciò, - sorge un conflitto. L'Expert Advisor che è in esecuzione su M1 sta cercando di trasformare la posizione nella cella, mentre il suo rivale cerca di fermarlo. E' ovvio che abbiamo bisogno di un calcolo separato delle posizioni, che è ciò che faremo ora.


Posizione o posizione virtuale?

Poiché in MetaTrader 5 gli sviluppatori sono passati dagli ordini alla considerazione delle posizioni, ha senso considerare in modo più dettagliato le funzioni associate alla registrazione delle posizioni.

// Returns the number of open positions.
int     PositionsTotal();

// Returns the symbol of the open position by the number in the list of positions.
string  PositionGetSymbol(int  index);

// Selects the open position for further working with it.
bool    PositionSelect(string  symbol, uint timeout=0);

// Function returns the requested property of the open position.
double  PositionGetDouble(ENUM_POSITION_PROPERTY  property_id);

// The function returns the requested property of the open position.
long    PositionGetInteger(ENUM_POSITION_PROPERTY  property_id);

// The function returns the requested property of the open position.
string  PositionGetString(ENUM_POSITION_PROPERTY  property_id);

Identificatori delle enumerazioni per le funzioni di ottenimento della richiesta delle proprietà di posizione conformi PositionGetDouble , PositionGetInteger, e PositionGetString fornite nelle tabelle 2-4.

Identificatore

Descrizione

Tipo

POSITION_VOLUME

Volume della posizione

double

POSITION_PRICE_OPEN

Prezzo della posizione

double

POSITION_SL

Livello di Stop Loss per la posizione aperta

double

POSITION_TP

Livello di Take Profit per la posizione aperta

double

POSITION_PRICE_CURRENT

Prezzo corrente dal simbolo

double

POSITION_COMMISSION

Commissione

double

POSITION_SWAP

Swap accumulato

double

POSITION_PROFIT

Profitto corrente

double

Tabella 2 Valore di enumerazione ENUM_POSITION_PROPERTY_DOUBLE

Identificatore

Descrizione

Tipo

POSITION_TIME

Tempo di apertura delle posizioni

datetime

POSITION_TYPE

Tipo di posizione

ENUM_POSITION_TYPE

POSITION_MAGIC

Numero Magic per la posizione (vedi ORDER_MAGIC )

long

POSITION_IDENTIFIER

Identificazione della posizione - questo è un numero univoco che viene assegnato a ciascuna posizione riaperta e che non cambia durante il suo ciclo di vita. Il fatturato di una posizione non cambia il suo ID.

long

Tabella 3 Valori di enumerazione ENUM_POSITION_PROPERTY_INTEGER

Identificatore

Descrizione

Tipo

POSITION_SYMBOL

Simbolo, per il quale viene aperta la posizione

string

POSITION_COMMENT

Commento alla posizione

string

Tabella 4 Valori di enumerazione ENUM_POSITION_PROPERTY_STRING

Dalle funzioni, possiamo vedere chiaramente che il linguaggio non contiene la divisione delle posizioni, basata sul principio di "chi ha fatto l'ordine", ma la possibilità di tali record è disponibile poiché il ORDER_MAGIC, il POSITION_MAGIC e il DEAL_MAGIC sono lo stesso numero esatto, e sono presi dal numero magico, indicato dall'utente. Il POSITION_MAGIC è preso dal DEAL_MAGIC, che apre la posizione, e il DEAL_MAGIC è a sua volta preso dal ORDER_MAGIC dell'ordine effettuato.

L'identificazione di un ordine, una transazione o una posizione possono essere eseguiti senza problemi, ma è impossibile condurre una posizione con un particolare numero Magic. Ora cercheremo di eliminare questa carenza . Creiamo analoghi di funzioni integrate, ma con l'identificazione dal numero Magico. Dichiara una classe per aver lavorato con una posizione virtuale sul numero Magico.

Dal momento che abbiamo l'opportunità di lavorare con l'OOP, dichiariamo anche la nostra struttura (acquisendo ulteriore pratica di scrittura oggettiva).

//+------------------------------------------------------------------+
//| Structure of the CPositionVirtualMagic class                     |
//+------------------------------------------------------------------+
struct SPositionVirtualMagic
  {
   double            volume; // volume of virt. position
   ENUM_POSITION_TYPE type;  // type of virt. position
  };
//+--------------------------------------------------------------------------------+
//| The class calculates the virtual position of an Expert Advisor by magic number |
//+--------------------------------------------------------------------------------+
class CPositionVirtualMagic
  {
protected:
   SPositionVirtualMagic pvm;
public:
   double               cVOLUME(){return(pvm.volume);}
   // Returns the volume of virtual position of an Expert Advisor
   ENUM_POSITION_TYPE   cTYPE(){return(pvm.type);}
   // Returns the type of virtual position of an Expert Advisor
   bool              PositionVirtualMagic(ulong Magic,
                                          string symbol,
                                          datetime CurrentTime
                                          );
   // the method of calculation virt. position returns the presence or absence of virt. position
private:
   void              prHistory_Deals(ulong &buf[],int HTD);
   // Fills the array of tickets
  };
//+-------------------------------------------------------------------------------------+
//| Method of calculation of virt. position, returns true if there is a virt. position  |
//+-------------------------------------------------------------------------------------+
bool  CPositionVirtualMagic::PositionVirtualMagic(ulong Magic,
                                                  string symbol,
                                                  datetime CurrentTime
                                                  )
  {
   int DIGITS=(int)-log10(SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP));
   if(DIGITS<0)DIGITS=0;
   ulong Dticket=0;
   int History_Total_Deals=-1;
   double volume=0,volume_BUY=0,volume_SELL=0;
   ulong DTicketbuf[];

   do
     {
      if(HistorySelect(0,TimeCurrent()))
        {
         History_Total_Deals=HistoryDealsTotal();
         prHistory_Deals(DTicketbuf,History_Total_Deals);
        }
      HistorySelect(0,TimeCurrent());
     }
   while(History_Total_Deals!=HistoryDealsTotal());

   for(int t=0;t<History_Total_Deals;t++)
     {
      Dticket=DTicketbuf[t];
      if(HistoryDealSelect(Dticket))
        {
         if(HistoryDealGetInteger(Dticket,DEAL_TIME)>=CurrentTime)
           {
            if(HistoryDealGetInteger(Dticket,DEAL_MAGIC)==Magic)
              {
               if(HistoryDealGetInteger(Dticket,DEAL_TYPE)==DEAL_TYPE_BUY)
                 {
                  volume_BUY+=HistoryDealGetDouble(Dticket,DEAL_VOLUME);
                 }
               else
                 {
                  if(HistoryDealGetInteger(Dticket,DEAL_TYPE)==DEAL_TYPE_SELL)
                    {
                     volume_SELL+=HistoryDealGetDouble(Dticket,DEAL_VOLUME);
                    }
                 }
              }
           }
        }
      else{HistorySelect(0,TimeCurrent());t--;}
      // if there is a fault, load history data and pass the step again
     }
   volume=NormalizeDouble(volume_BUY-volume_SELL,DIGITS);
   if(volume<0)pvm.type=POSITION_TYPE_SELL;
   else
     {
      if(volume>0)pvm.type=POSITION_TYPE_BUY;
     }
   pvm.volume=fabs(volume);
   if(pvm.volume==0)return(false);
   else return(true);
  }

Nel testo sopra (dove viene fornito il codice della classe CProvision), non è stato spiegato da dove proviene tutto e dove va oltre, poiché lo sviluppo dell'Expert Advisor non è l'argomento di questo articolo.

Ma considereremo in dettaglio la classe CPositionVirtualMagic.

Alla classe viene assegnata la struttura:

struct SPositionVirtualMagic

che viene utilizzata per accettare i risultati dei calcoli, tale dichiarazione globale all'interno della classe, grazie a pvm (variabile della struttura), questa struttura sarà disponibile ovunque, in qualsiasi metodo della classe.

Segui quindi i due metodi della classe:

double               cVOLUME(){return(pvm.volume);} // Returns the volume of the virtual position of the EA
ENUM_POSITION_TYPE   cTYPE()  {return(pvm.type);}   // Returns the type of the virtual position of the EA

Questi metodi sono dichiarati pubblici e, pertanto, saranno disponibili tramite la variabile class chiamata, in qualsiasi punto del programma, e sono progettati per l'output dei valori della struttura nella posizione richiesta.

Questa è anche la sezione in cui viene dichiarato il seguente metodo:

bool              PositionVirtualMagic(ulong Magic,string symbol,datetime CurrentTime);

Questa è la funzione principale della classe, e ci concentreremo ulteriormente sulle sue analisi dettagliate, e nel frattempo, mi supererò e descriverò la funzione sotto l’indicatore dell'accesso privato:

void              prHistory_Deals(ulong &buf[],int HTD);

Questo metodo produce un ticket di record di transazioni nell'array, che è fondamentalmente un ciclo, e potrebbe essere descritto nella funzione chiamata, ma volevo ridurre la dimensione (al fine di aumentare la leggibilità del codice) della funzione PositionVirtualMagic(), e così ho spostato questo ciclo oltre i limiti della funzione e ho dimostrato come utilizzare l’indicatore dell'accesso privato.

Quindi torniamo al  PositionVirtualMagic() . Questa funzione, all'inizio ha un calcolo di precisione di una riga, a cui è necessario arrotondare il doppio valore del volume della posizione calcolata.

int DIGITS=(int)-log10(SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP)); if(DIGITS<0)DIGITS=0;

Questo è necessario per fare l'operazione di confronto a zero, altrimenti un certo equilibrio nelle 8 cifre dopo il punto decimale, ci impedirà di equiparare il valore a zero e causerà un errore di esecuzione.

Il volume della posizione viene arrotondato allo step minimo. E se lo step minimo è maggiore di 1, l'arrotondamento viene eseguito dalla parte integrale. Il prossimo è il ciclo while, ma viene usato in un modo nuovo (diverso da quello in mql4), poiché la verifica dell'espressione veritiera viene fatta alla fine del ciclo, piuttosto che all'inizio:

    do
     {
      if(HistorySelect(0,TimeCurrent()))
        {
         History_Total_Deals=HistoryDealsTotal();
         prHistory_Deals(DTicketbuf,History_Total_Deals);
        }
      HistorySelect(0,TimeCurrent());  
     }
   while(History_Total_Deals!=HistoryDealsTotal());

Tale approccio viene utilizzato perché l'espressione di veridicità viene calcolata all'interno del ciclo e, al suo lancio, non è ancora preparata per questa verifica.

Il ciclo contiene il Caricamento della cronologia, voglio attirare l'attenzione del lettore sul fatto che questa è una condizione richiesta al fine di garantire il lavoro delle funzioni integrate di lavorare con la cronologia.

HistorySelect(0,TimeCurrent())

Penso che dovrei spiegare il mio sistema di scelta dei nomi delle variabili.

Il lettore attento dovrebbe aver notato che i nomi delle classi sono definiti dalla lettera iniziale "C", questo non è richiesto dalla sintassi e può essere dato qualsiasi nome, ma in questo modo rende la lettura molto più facile. Se la lettera "C" appare prima del nome, sappiamo subito che questo è il nome della classe, e se la lettera è "S" - allora è una struttura. Se la variabile assume il valore di una funzione incorporata, allora cambio semplicemente i componenti del nome della funzione e ottengo il nome della variabile, ad esempio in questo modo:

CurrentTime = TimeCurrent();

Semplice e leggibile, possiamo vedere immediatamente cosa contiene la variabile. Soprattutto perché MetaEditor contiene la funzione per spostare un particolare parte di codice in una posizione specifica.

Rivedendo ulteriormente il codice, vediamo che dopo il caricamento della cronologia, segue la chiamata alla funzione:

History_Total_Deals=HistoryDealsTotal();

con la memorizzazione del numero di transazioni nella variabile. Con la stessa condizione, implementeremo la verifica per l'uscita dal ciclo. A cosa serve questa verifica? E perché non possiamo semplicemente caricare la cronologia e quindi recuperare le transazioni da essa?

Il problema risiede nel fatto che durante il lavoro degli Expert Advisor, la cronologia sarà richiesta separatamente da ciascun EA, e quindi se gli Expert Advisor sono in esecuzione in momenti diversi, la profondità della cronologia sarà diversa. E questo significa che quando un Expert Advisor entra nel ciclo e carica la cronologia per il suo periodo, quindi prima di raggiungere la fine del ciclo, potrebbe scoprire che questa cronologia è già stata caricata su richiesta di un altro Expert Advisor, e quindi è necessario fare una verifica per l'autenticità.

Per inciso, potrebbe non essere il miglior tipo di verifica, ma funziona. E quindi, continuiamo. Nel ciclo richiamiamo il metodo class, che inserisce i valori dei ticket delle transazioni in un buffer appositamente preparato. Dopo aver chiamato la funzione prHistory_Deals (), produciamo nuovamente il caricamento della cronologia.

Questo è il modo in cui viene organizzata la verifica se ci sono stati o meno cambiamenti nella storia delle negoziazioni, nel corso del lavoro della funzione prHistory_Deals (). Se non ci sono state modifiche, la variabile di History_Total_Deals sarà uguale a HistoryDealsTotal () e si verificherà un'uscita dal ciclo per un singolo passaggio. Se ci sono stati cambiamenti, il sistema avvierà un secondo ciclo e continuerà a ripetere fino a quando la cronologia dei ticket non verrà caricata senza errori (e non dimenticare di mettere ";" alla fine):

while(History_Total_Deals!=HistoryDealsTotal());

Più avanti nel ciclo per, avviene il calcolo delle posizioni virtuali.

Se la transazione ha superato con successo una serie di filtri (l'ora della transazione e il numero magico della transazione), il suo volume aumenta quella parte della posizione virtuale, il tipo a cui appartiene la transazione.

Voglio far notare che registro i calcoli delle posizioni virtuali solo dal lancio dell'Expert Advisor, sebbene siano possibili altre opzioni.

Qui va notato come viene calcolata esattamente la posizione. Dal libro dei record, che tutti noi abbiamo usato da tempo immemorabile e fino ad oggi, abbiamo spese e profitti, e il conteggio del saldo è mantenuto come differenza tra questi valori, lo stesso schema si applica al calcolo di una posizione: se apri lotti, 0,2 per vendere e 0,3 per comprare, ciò significa che mantieni la posizione di 0,1 per Buy. Il tempo di apertura e la differenza di livelli sono categorie di profitto, ma la posizione che avrai è di 0,1 lotti, il tipo Buy.

Questo è il motivo per cui riassumiamo semplicemente tutte le transazioni effettuate dall'Expert Advisor su Buy e separatamente su Sell, quindi le confrontiamo e otteniamo la posizione generale (in realtà, questo è ciò con cui è impegnato il resto della funzione esaminata).

Calcolo del volume delle posizioni:

volume=NormalizeDouble(volume_BUY-volume_SELL,DIGITS);

Riconoscimento del tipo di posizione con l'output del valore nella struttura:

   if(volume<0)pvm.type=POSITION_TYPE_SELL;
   else
     {
      if(volume>0)pvm.type=POSITION_TYPE_BUY;
     }

Output di volume nella struttura:

pvm.volume=fabs(volume);

 L'output del valore della funzione: se il volume della posizione è 0, allora è falso, altrimenti, se la posizione esiste, allora è vero:

   if(pvm.volume==0)return(false);
   else return(true);

Ora, avendo la funzione della posizione virtuale, possiamo facilmente redigere il codice dell'Expert Advisor, che non sarà in conflitto con i suoi "vicini".

Per risparmiare spazio, fornirò alcune parti del codice, che non sono state esposte sopra, piuttosto che l'intero codice stesso.

//+------------------------------------------------------------------+
//| Code of the Expert Advisor                                       |
//+------------------------------------------------------------------+

//--- input parameters
input ulong              magic       =1;           // magic
input int                SL          =300;         // Stop Loss
input int                TP          =1000;        // Take Profit
input int                MA_Period   =25;          // MA period
input double             lot         =0.1;         // Volume of position
input int                MA_shift    =0;          // Shift of indicator
input ENUM_MA_METHOD     MA_smooth   =MODE_SMA;     // Smoothing type
input ENUM_APPLIED_PRICE price       =PRICE_OPEN;    // Price type 
//--- we will store the indicator's handle
int MA_handle,type_MA,rezult;
double v[2];
datetime  CurrentTime;  // The variable stores the time of start of the Expert Advisor
MqlTradeResult    res;   // Pointer to the structure of responding by OrderSend
MqlTick          tick;  // Pointer to the structure of last market information
CPositionVirtualMagic cpvm;
CProvision prov;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   CurrentTime=TimeCurrent();// The variable stores the time of start of the Expert Advisor
//--- Create the indicator's handle
   MA_handle=iMA(Symbol(),0,MA_Period,MA_shift,MA_smooth,price);
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CopyBuffer(MA_handle,0,0,2,v)<=0)
     {Print("#",magic,"Error of copying");return;}
   type_MA=prov.TYPE(v); // Determine type depending on MA indication

   if(cpvm.PositionVirtualMagic(magic,_Symbol,CurrentTime))// If there is ab open position 
     {
      if((int)cpvm.cTYPE()!=type_MA)// Check if it is time to close
        {
         Print("#",magic,"Position by magic number has volume ",cpvm.cVOLUME(),
               " reverse position of type ",(int)cpvm.cTYPE()," by ",type_MA);
         //cpvm.cVOLUME() - volume of virtual position
         rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,cpvm.cVOLUME()+lot);// reverse the poistion
         if(rezult!=-1)Print("#",magic," Code of the operation result ",rezult," volume ",res.volume);
         else{Print("#",magic,"Error",GetLastError()); return;}
        }
     }
   else // If there is no open position then open
     {
      Print("#",magic,"Poistion by magic number has volume ",cpvm.cVOLUME()," open position of type ",type_MA);
      rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,lot);// Open position 
      if(rezult!=-1)Print("#",magic," Code of the operation result ",rezult," volume ",res.volume);
      else{Print("#",magic,"Error",GetLastError()); return;}
     }
  }

Esegui l'Expert Advisor tre volte su un singolo strumento, ma con timeframe diversi, oltre a assegnare numeri magici diversi ogni volta:

Figura 3. Assegniamo numeri magici diversi a due Expert Advisor identici, (uno strumento,timeframe diversi) lancio del primo Expert Advisor

Figura 3. Assegniamo numeri magici diversi a due Expert Advisor identici, (uno strumento, timeframe diversi) lancio del primo Expert Advisor

Figura 4. Assegniamo numeri magici diversi a due Expert Advisor identici (uno strumento, timeframe diversi) lancio del secondo Expert Advisor

Figura 4. Assegniamo numeri magici diversi a due Expert Advisor identici (uno strumento, timeframe diversi) lancio del secondo Expert Advisor

Figura 5. Il risultato è un lavoro senza conflitti di Expert Advisor su un unico strumento, con vari numeri magici

Figura 5. Il risultato è un lavoro senza conflitti di Expert Advisor su un unico strumento con vari numeri magici

Il periodo di prova è stato superato con successo, gli Expert Advisor si sono gentilmente ceduti l'un l'altro e non sembrano essere presenti questioni contrastanti.

Il primo punto delle specifiche tecniche è stato implementato, ma non è tutto.


Codificare il numero magico

Per l'implementazione delle seguenti parti, dovremo sviluppare una classe di metodi, che codificano / decodificheranno le informazioni, oltre a recuperare i valori dalle funzioni integrate e trasformarli in un formato specifico.

Per fare ciò, ripetere i termini di codifica (per così dire, le specifiche tecniche per lo sviluppo):

  • I metodi devono codificare il nome dell'Expert Advisor (chiamiamolo il nome digitale),
  • Codice di riconoscimento tuo/straniero (chiamiamolo il codice di interazione)
  • Codice simbolo, su cui è in esecuzione l'Expert Advisor (per poter determinare dalla transazione da cui sta lavorando l'EA).

Per cominciare, selezioniamo il nome per la nuova classe, - lascia che sia magico (un nome generico), assegna la nostra enumerazione per rendere il codice più visivamente comprensibile.

enum Emagic
  {
   ENUM_DIGITAL_NAME,    // digital name if the Expert Advisor
   ENUM_CODE_INTERACTION,// code of interaction
   ENUM_EXPERT_SYMBOL    // symbol, on which the EA is launched
  };

L'enumerazione funziona in maniera semplice: si descrivono i nomi, separati da virgole, e il compilatore assegna loro numeri in sequenza.

Prima di tutto, se assegni una variabile di un tipo diverso (non è applicabile ai numeri), quindi quando specifichi un parametro dall'enumerazione, riceverai un errore durante la compilazione e, in secondo luogo, ottieni chiarezza: non assegni semplicemente 0 , ma piuttosto dai il comando per assegnare ENUM_DIGITAL_NAME .

Come per la creazione di una struttura o di una classe, ho scelto un nome semplice per l'enumerazione. Ho semplicemente aggiunto E al nome generalmente selezionato, e ottenuto rispettivamente Emagic , la struttura corrispondente sarà Smagic e la classe Cmagic .

Anche in questo caso, bisogna prestare attenzione al fatto che questo argomento non è obbligatorio ed è possibile chiamare l’enumerazione Enumerator, la struttura Structurer e la classe Classifier. Ma questo non fornirà un’omogeneità nei nomi e leggere questo tipo di codice sarà scomodo.

Successivamente, creiamo una struttura per la memorizzazione dei nostri codici.

struct Smagic
  {
   ulong             magicnumber;      // magic in an assembled form - how it is written in the order
   int               digital_name;     // digital name
   int               code_interaction; // code of interaction
   int               expert_symbol;    // symbol, on which the Expert Advisor is launched
  };

Dopodiché, dichiara la classe Cmagic, in cui registriamo tutti i metodi di codifica e decodifica di Magic, inclusi i metodi del precedente Expert Advisor (basta dichiararli nella classe corrente e riscrivere le intestazioni)

class Cmagic
  {
protected:
   Smagic            mag;
   SPositionVirtualMagic pvm;
public:
// the function returns the assembled magic, assembled from the incoming data
   ulong             SetMagic_request(int digital_name=0,int code_interaction=0);

// the function obtains the assembled magic and divides it according to the assembly logic
   ulong             SetMagic_result(ulong magicnumber);    

// the function obtains the return identification and returns the requested part of the assembled magic
   ulong             GetMagic_result(Emagic enum_); 

// the function obtains the return identification and returns the textual interpretation of the request part of the assembled magic
   string            sGetMagic_result(Emagic enum_);

// returns the voulme of the virtual position of the Expert Advisor
   double            cVOLUME(){return(pvm.volume);}
   
// returns the type of the virtual position of the Expert Advisor
   ENUM_POSITION_TYPE  cTYPE(){return(pvm.type);}
                                           
// method of calculating the virtual position, returns the presence of absence of the virtual position   
   bool              PositionVirtualMagic(Emagic enum_,
                                          string symbol,
                                          datetime CurrentTime);
private:
// function divides the magic into three parts  of three charges, and returns the part to which the category points to
   int               decodeMagic_result(int category); 

// interpretor of instrument symbols into the digital code                                                      
   int               symbolexpert();     
   
// interpretor of the digital code into the prescribed text (Expert Advisors)
   string            expertcode(int code);    
                                 
// interpretor of the digital code into the prescribed text (interaction)   
   string            codeinterdescript(int code);

// interpretor of the digital code into the instrument symbol                                         
   string            symbolexpert(int code);

// cycle of recording tickets into the buffer
   void              prHistory_Deals(ulong &buf[],int HTD);    
  };   

Ora svilupperemo i metodi.

Il primo metodo della classe:

//+---------------------------------------------------------------------+
//| Function returns the assembled magic, assembled from the input data |
//+---------------------------------------------------------------------+
ulong Cmagic::SetMagic_request(int digital_name=0,int code_interaction=0)
  {
   if(digital_name>=1000)Print("Incorrectly specified digital name of the Expert Advisor (more than 1000)");
   if(code_interaction>=1000)Print("Incorrectly specified the code of recognizing yours-foreign (more than 1000)");
   mag.digital_name     =digital_name;
   mag.code_interaction =code_interaction;
   mag.expert_symbol    =symbolexpert();
   mag.magicnumber      =mag.digital_name*(int)pow(1000,2)+
                         mag.code_interaction*(int)pow(1000,1)+
                         mag.expert_symbol;
   return(mag.magicnumber);
  }

Questo metodo riceve due valori: un nome digitale dell'Expert Advisor e il codice di interazione.

ulong Cmagic::SetMagic_request(int digital_name=0,int code_interaction=0)

E ne verifica immediatamente la correttezza:

   if(digital_name>=1000)Print("Incorrectly specified the digital name of the Expert Advisor(more than 1000)");
   if(code_interaction>=1000)Print("Incorrectly specifies the code of recognizing yours-foreign (more than 1000)");

Ma non ci sono ritorsioni contro le azioni dell'utente, anche in caso di errore, continua docilmente a funzionare.

Segue l'assegnazione nella struttura dei dati di input, che l'utente specifica, tuttavia il simbolo dello strumento non è specificato e si ottiene dal metodo privato:

int Cmagic::symbolexpert()

Non fornirò il suo codice, perché è molto lungo ed è presente nel file allegato. Lasciatemi solo dire che questo metodo è fondamentalmente solo una tabella, che assegna a ogni simbolo dalla finestra "market view" un numero corrispondente: per EURUSD, ad esempio, è 1, ecc.

È certamente possibile ottenere questi dati in modo dinamico, scrivendo un codice per un sondaggio di quali valute sono presenti nella finestra "market view", ma la soluzione deve corrispondere alla complessità del problema, e non ha senso occuparsi di richiamare le finestre; quindi lo faremo nel modo semplice, comprendere un elenco di valute e assegnare un indice a ciascuna di esse.

E, infine, la linea più essenziale dell'intero metodo:

mag.magicnumber      =mag.digital_name*(int)pow(1000,2)+
                      mag.code_interaction*(int)pow(1000,1)+
                      mag.expert_symbol;

assemblata dalle parti disparate di tutto il Magic. Questo è il Magic che verrà assegnato all'ordine del nostro Expert Advisor.

Il prossimo metodo pubblico della classe:

//+------------------------------------------------------------------+
//| Function obtains the assembled magic                             |
//| and divides it according to the logic of the assembly            |
//+------------------------------------------------------------------+
ulong Cmagic::SetMagic_result(ulong magicnumber)
  {
   mag.magicnumber      =magicnumber;
   mag.expert_symbol    =decodeMagic_result(1);
   mag.code_interaction =decodeMagic_result(2);
   mag.digital_name     =decodeMagic_result(3);
   return(mag.magicnumber);
  }

In realtà, questo metodo funge da shell, distribuendo attraverso la struttura i risultati di tre chiamate di un singolo metodo privato. La dichiarazione sotto tale indicatore è buona nel fatto che non vengono visualizzati nel messaggio di prompt pop-up, quando si richiama una variabile di classe, creando l'impressione che tutto il lavoro sia stato svolto da una funzione pubblica.

Ma torniamo alle nostre funzioni private:

//+------------------------------------------------------------------+
//| Function divides the magic into three parts of three charges     |
//| and returns the part, which the category points to               |
//+------------------------------------------------------------------+
int Cmagic::decodeMagic_result(int category)
  {
   string string_value=(string)mag.magicnumber;
   int rem=(int)MathMod(StringLen(string_value),3);
   if(rem!=0)
     {
      rem=3-rem;
      string srem="0";
      if(rem==2)srem="00";
      string_value=srem+string_value;
     }
   int start_pos=StringLen(string_value)-3*category;
   string value=StringSubstr(string_value,start_pos,3);
   return((int)StringToInteger(value));
  }

Visivamente, questo metodo può essere rappresentato come una lettura di un numero di tre cifre dal campo specificato, ad esempio, se abbiamo un Magic 123456789 , possiamo rappresentarlo come | 123 | 456 | 789 | se il campo specificato è 1 , il risultato sarà 789 poiché i campi sono numerati da destra a sinistra.

Pertanto, dopo aver utilizzato tutti e tre i campi nel metodo chiamato, distribuiamo alla struttura tutti i dati acquisiti. Questo viene fatto attraverso una procedura in cui si riporta il Magic a un minuscolo tipo di stringa:

string string_value=(string)mag.magicnumber;

seguito dall'ordine dei singoli componenti di linea.

Successivamente segui due funzioni simili, che sono interruttori nella loro essenza interruttore, e differiscono solo nel tipo di valori di uscita:

//+------------------------------------------------------------------+
//| Function obtains the identifier of the return                    |
//| and returns the requested part of the assembled magic            |
//+------------------------------------------------------------------+
ulong Cmagic::GetMagic_result(Emagic enum_)
  {
   switch(enum_)
     {
      case ENUM_DIGITAL_NAME     : return(mag.digital_name);     break;
      case ENUM_CODE_INTERACTION : return(mag.code_interaction); break;
      case ENUM_EXPERT_SYMBOL    : return(mag.expert_symbol);    break;
      default: return(mag.magicnumber); break;
     }
  }
//+------------------------------------------------------------------------------+
//| Function obtains the identifier of the return and returns                    |
//| a textual interpretation of the requested type of the assembled magic        |
//+------------------------------------------------------------------------------+
string Cmagic::sGetMagic_result(Emagic enum_)
  {
   switch(enum_)
     {
      case ENUM_DIGITAL_NAME     : return(expertcode(mag.digital_name));            break;
      case ENUM_CODE_INTERACTION : return(codeinterdescript(mag.code_interaction)); break;
      case ENUM_EXPERT_SYMBOL    : return(symbolexpert(mag.expert_symbol));         break;
      default: return((string)mag.magicnumber); break;
     }
  }

Le funzioni restituiscono la parte del Magic, che specifica il parametro di tipo Emagic, con il primo che dà il risultato sotto forma di ulong che viene utilizzato nei calcoli e il secondo che dà i risultati del tipo stringa che può essere utilizzato per la visualizzazione.

Nella funzione GetMagic_result () tutto è organizzato in maniera semplice, distribuisce i valori della struttura attraverso i rami switch, mentre sGetMagic_result () è un po’ più complicato. Ogni caso di ramo richiama una funzione di tabella, che trasferisce il valore della struttura in una forma visiva. Quindi, se il valore mag.expert_symbol = , 1, allora la prima funzione darà 1 , e la seconda EURUSD .

Ho già descritto i vantaggi delle funzioni di tabella nella codifica / decodifica delle informazioni, quindi menzionerò solo che ogni caso dovrebbe essere considerato separatamente in base alla complessità di implementazione di un metodo senza tabella e ai suoi vantaggi per il tempo necessario per scrivere le tabelle. Se è più facile scrivere una tabella di stati, allora non c'è bisogno di complicare le cose. Ma se la scrittura della tabella richiederà molto tempo, allora ovviamente, la preferenza dovrebbe essere data ai metodi procedurali. Non sto fornendo le tabelle per risparmiare spazio (possono essere trovate nei file allegati).

Fondamentalmente questo è tutto, la nostra classe è stata sviluppata, tuttavia, ci sono ancora le quattro funzioni rimanenti che abbiamo usato nello sviluppo del precedente Expert Advisor. 

Li ho semplicemente dichiarati nuovamente in una nuova classe, soprattutto considerando che dovevano essere leggermente modificati.

Ora il metodo principale:

bool  Cmagic::PositionVirtualMagic(Emagic enum_,
                                   string symbol,
                                   datetime CurrentTime)

non solo è dichiarato come un metodo di classe Cmagic, ma ha anche un diverso insieme di parametri.

Invece del Magic, ora ottiene l'identificazione dal campo del Magic, a cui è stata calcolata la posizione. Inoltre, anche se il simbolo era presente nell'ultima opzione, è stato utilizzato solo per ottenere informazioni sul passo del lotto dal simbolo. E ora è prescritto nel filtro e può partecipare, alla pari con gli altri, al filtrazione del conteggio delle posizioni.

Che cosa comporta questo? Ora possiamo filtrare contemporaneamente le transazioni, che erano aperte su uno strumento diverso, ma dallo stesso Expert Advisor. In tal modo non saranno confusi con altri Expert Advisor simili in esecuzione su uno strumento diverso. Ad essere onesti, è molto difficile descrivere tutti i diversi modi di utilizzare questo nuovo sistema di calcoli. E il lettore può decidere personalmente di cosa ha bisogno da un sistema così complicato. Ti consiglio vivamente di non complicare i casi, dove puoi scrivere semplicemente, e di non temere tali complicazioni quando ce n'è un evidente bisogno.

Poiché la classe è stata progettata, è tempo di testarla su un nuovo Expert Advisor:

//+------------------------------------------------------------------+
//| Code of the Expert Advisor                                       |
//+------------------------------------------------------------------+
//--- input parameters
input ulong              digital_name_       =4;           // Digital name of Expert Advisor
input ulong              code_interaction_   =1;           // Code of interaction
input Emagic             _enum               =0;           // Model of magic number  
input int                SL                  =300;         // Stop Loss
input int                TP                  =1000;        // Take Profit
input int                MA_Period           =25;          // MA period
input double             lot                 =0.4;         // Volume of position
input int                MA_shift            =0;           // Shift of indicator
input ENUM_MA_METHOD     MA_smooth           =MODE_SMA;      // Smoothing type
input ENUM_APPLIED_PRICE price               =PRICE_OPEN;    // Price type 

//--- we will store the indicator's handle
int MA_handle,type_MA,rezult;
static ulong magic;
double v[2];
datetime  CurrentTime;// The variable stores the time of start of the Expert Advisor

MqlTradeResult  res;   // Pointer to the structure of responding by OrderSend
MqlTick         tick;  // Pointer to the structure of last market information
CProvision prov;
Cmagic mg;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   magic=mg.SetMagic_request(digital_name_,code_interaction_);
// Stamp of Expert Advisor (the magic number identifier) the magic variable is declared at the global scope
// used in int CProvision::SendOrder(ENUM_ORDER_TYPE type,double volume)
   CurrentTime=TimeCurrent();// The variable stores the time of start of the Expert Advisor
//--- Create the indicator's handle
   MA_handle=iMA(Symbol(),0,MA_Period,MA_shift,MA_smooth,price);
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CopyBuffer(MA_handle,0,0,2,v)<=0)
     {Print("#",magic,"Error of copying");return;}
   type_MA=prov.TYPE(v); // Determine type depending on MA indication
   mg.SetMagic_result(magic);// put the information into the structure
   if(mg.PositionVirtualMagic(_enum,_Symbol,CurrentTime))// If three is an open position 
     {
      if((int)mg.cTYPE()!=type_MA)// Check if it is time to close
        {
         mg.SetMagic_result(magic);// put the information into the structure
         Print("#",mg.GetMagic_result(_enum),"Position by magic number has volume ",mg.cVOLUME(),
               " reverse position of type ",(int)mg.cTYPE()," by ",type_MA);
         //cpvm.cVOLUME() - volume of virtual position
         rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,mg.cVOLUME()+lot);// reverse position
         if(rezult!=-1)Print("№",magic," Code of the operation result ",rezult," volume ",res.volume);
         else{Print("№",magic,"Error",GetLastError()); return;}
        }
     }
   else // If there is no open position then open
     {
      Print("#",magic,"Position by magic number has volume  ",mg.cVOLUME()," open position of type",type_MA);
      rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,lot);// Open position 
      if(rezult!=-1)Print("#",magic," Code of the operation result ",rezult," volume ",res.volume);
      else{Print("#",magic,"Error",GetLastError()); return;}
     }
  }

Come accennato in precedenza, questo Expert Advisor è estremamente semplice ed è stato creato solo per dimostrarne le diverse capacità, eseguirlo tre volte su un singolo strumento:

Figura 6. Installazione di tre Expert Advisor, con Magic differenti su grafici diversi

Figura 6. Installazione di tre Expert Advisor con magic differenti su grafici diversi

Figura 7. Il risultato è un trading senza conflitti di tre Expert Advisor con magic diversi

Figura 7. Il risultato è un trading senza conflitti di tre Expert Advisor con magic diversi

Come si può vedere dalle stampe dei messaggi degli Expert Advisor, tutti e tre i partecipanti sono stati lanciati con successo e non hanno dimostrato conflitti.


Conclusione

Fornendo l'opportunità di assegnare ordini magici alle operazioni di trading, i creatori di MQL5 hanno notevolmente facilitato la vita degli scrittori di Expert Advisor. Ma gli sviluppatori possono fornirti solo strumenti: devi essere tu a ottenere effettivamente i diamanti.

Buona fortuna e alla prossima.


Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/112

File allegati |
magic_exp0_en.mq5 (8.34 KB)
magic_exp1_en.mq5 (11.84 KB)
magic_exp2_en.mq5 (25.39 KB)
Una Libreria per la Costruzione di un Grafico tramite l'API Google Chart Una Libreria per la Costruzione di un Grafico tramite l'API Google Chart
La costruzione di vari tipi di diagrammi è una parte essenziale nelle analisi della situazione del mercato e del test di un sistema di trading. Spesso, per costruire un diagramma di bell'aspetto, è necessario organizzare l'output dei dati in un file, dopo di che viene utilizzato in applicazioni come MS Excel. Questo non è molto conveniente e ci priva della possibilità di aggiornare dinamicamente i dati. L'API di Google Charts ha fornito i mezzi per creare grafici in modalità online, inviando una richiesta speciale al server. In questo articolo cercheremo di automatizzare il processo di creazione di tale richiesta e ottenere un grafico dal server di Google.
I Principi del Calcolo Economico degli Indicatori I Principi del Calcolo Economico degli Indicatori
Le chiamate all'utente e gli indicatori tecnici occupano pochissimo spazio nel codice del programma dei sistemi di trading automatizzati. Spesso si tratta semplicemente di poche righe di codice. Ma capita spesso che siano queste poche righe di codice a impiegare la maggior parte del tempo, che deve essere speso per testare l'Expert Advisor. Pertanto, tutto ciò che è correlato ai calcoli dei dati all'interno di un indicatore, deve essere considerato molto attentamente di quanto sembrerebbe a prima vista. In questo articolo si parlerà proprio di questo.
Una soluzione senza DLL per comunicare tra i terminali MetaTrader 5 utilizzando le Named Pipe Una soluzione senza DLL per comunicare tra i terminali MetaTrader 5 utilizzando le Named Pipe
L'articolo descrive come implementare la comunicazione tra processi tra i terminali client MetaTrader 5 utilizzando le named pipe. Per l'utilizzo delle named pipe, viene sviluppata la classe CNamedPipes. Per il test del suo utilizzo e per misurare il throughput della connessione, vengono presentati l'indicatore di tick, gli script server e client. L'uso di named pipe è sufficiente per le quotazioni in tempo reale.
Test delle Prestazioni del Calcolo delle Medie Mobili in MQL5 Test delle Prestazioni del Calcolo delle Medie Mobili in MQL5
Dal momento della creazione del primo indicatore della media mobile, sono comparsi numerosi indicatori. Molti di loro utilizzano metodi di smoothing simili, ma non sono state studiate le prestazioni di diversi algoritmi di medie mobili. In questo articolo, prenderemo in considerazione i possibili modi d’utilizzo delle medie mobili in MQL5 e confronteremo le loro prestazioni.