English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
preview
Sviluppare un Expert Advisor per il trading da zero (Parte 12): Times e Trade (I)

Sviluppare un Expert Advisor per il trading da zero (Parte 12): Times e Trade (I)

MetaTrader 5Sistemi di trading | 12 dicembre 2022, 17:03
418 0
Daniel Jose
Daniel Jose

Introduzione

La Lettura del Nastro è un metodo di trading utilizzato da alcuni trader in varie fasi del trading. Questo metodo è molto efficace e, se utilizzato correttamente, fornisce una crescita stabile dei profitti in modo più sicuro e coerente rispetto a quando si utilizza la ben nota Price Action, che è pura osservazione delle candele. Tuttavia, l'uso della Lettura del Nastro nella sua forma attualmente presentata è un processo molto complesso e noioso che richiede una costante concentrazione e attenzione. Nel tempo, inevitabilmente iniziamo a commettere errori nell'osservazione.

Il problema nella lettura del nastro è legato alla quantità di informazioni che dobbiamo analizzare. Diamo un'occhiata a un caso d'uso tipico della Lettura del Nastro:


Il vero problema è che durante l'analisi dobbiamo guardare il prezzo e cosa gli è successo, ma controllare questi valori nei mini-contratti è poco pratico. Pertanto, di solito non guardiamo il contenuto del flusso nei mini-contratti, preferiamo invece osservare i contratti completi, poiché sono quelli che muovono il mercato. Questo è ciò che accade realmente, quindi il sistema è simile a quello qui sotto. È un po' più facile da interpretare e da seguire.


Ma anche in questo caso l'applicazione del sistema è un processo molto noioso che richiede estrema attenzione. La situazione si fa ancora più tesa quando vengono attivate le posizioni di stop, e in questo caso possiamo perdere parte del movimento, in quanto lo scorrimento delle informazioni sullo schermo dovrebbe essere molto veloce.


Pianificazione

Tuttavia, la piattaforma MetaTrader 5 ha un sistema alternativo anche per i mini-contratti, che rende il monitoraggio molto più efficiente e semplice. Vediamo come appaiono le cose quando si lavora con i mini-contratti:

Come puoi vedere l'interpretazione è molto più semplice. Tuttavia, per i motivi che abbiamo discusso in precedenza, è più appropriato utilizzare contratti completi, quindi sarà simile al seguente:


Notare che i dati sulle operazioni sono ostacolati dal rumore dei movimenti BID e ASK. Le operazioni sono rappresentate qui come cerchi. Il rosso mostra le operazioni di vendita, quelle blu sono le operazioni di acquisto e il verde mostra gli ordini diretti. Oltre al fatto che disponiamo di informazioni non necessarie per l'osservazione stessa, abbiamo un altro problema: il sistema è separato dal grafico che effettivamente tradiamo, per cui dobbiamo monitorare due schermi. Da un lato questo è un vantaggio, ma in alcuni casi complica notevolmente le cose. Quindi, qui propongo di creare un sistema che sia di facile lettura e allo stesso tempo ci permetta di vedere questo indicatore direttamente sul grafico di trading.


Implementazione

La prima cosa che faremo è modificare la classe C_Terminal in modo da poter accedere all'intero asset del contratto e questo viene fatto aggiungendo il seguente codice:

void CurrentSymbol(void)
{
        MqlDateTime mdt1;
        string sz0, sz1, sz2;
        datetime dt = TimeLocal();
                
        sz0 = StringSubstr(m_Infos.szSymbol = _Symbol, 0, 3);
        m_Infos.szFullSymbol = _Symbol;
        m_Infos.TypeSymbol = ((sz0 == "WDO") || (sz0 == "DOL") ? WDO : ((sz0 == "WIN") || (sz0 == "IND") ? WIN : OTHER));
        if ((sz0 != "WDO") && (sz0 != "DOL") && (sz0 != "WIN") && (sz0 != "IND")) return;
        sz2 = (sz0 == "WDO" ? "DOL" : (sz0 == "WIN" ? "IND" : sz0));
        sz1 = (sz2 == "DOL" ? "FGHJKMNQUVXZ" : "GJMQVZ");
        TimeToStruct(TimeLocal(), mdt1);
        for (int i0 = 0, i1 = mdt1.year - 2000;;)
        {
                m_Infos.szSymbol = StringFormat("%s%s%d", sz0, StringSubstr(sz1, i0, 1), i1);
                m_Infos.szFullSymbol = StringFormat("%s%s%d", sz2, StringSubstr(sz1, i0, 1), i1);
                if (i0 < StringLen(sz1)) i0++; else
                {
                        i0 = 0;
                        i1++;
                }
                if (macroGetDate(dt) < macroGetDate(SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_EXPIRATION_TIME))) break;
        }
}

// ... Class code ...

inline string GetFullSymbol(void) const { return m_Infos.szFullSymbol; }


Aggiungendo le linee evidenziate, abbiamo accesso all'asset desiderato, che utilizzeremo nel nostro programma Time & Trade. Successivamente, possiamo passare alla creazione di una classe oggetto che supporterà il nostro Time & Trade. Questa classe conterrà alcune funzioni molto interessanti. Per prima cosa è necessario creare una sottofinestra che conterrà il nostro indicatore. È facile da fare, tuttavia, per motivi pratici non utilizzeremo il sistema della sottofinestra che abbiamo utilizzato in precedenza. Forse il concetto cambierà in futuro, ma per ora lavoreremo con Time & Trade in una finestra separata dal sistema degli indicatori, il che comporta molto lavoro preparatorio.

Iniziamo con la creazione di un nuovo file di supporto in modo da avere un nome diverso per l'indicatore. Invece di creare file sopra altri file, facciamo qualcosa di più elegante. Stiamo modificando il file di supporto per avere più possibilità. Il nuovo file di supporto è mostrato di seguito:

#property copyright "Daniel Jose 07-02-2022 (A)"
#property version   "1.00"
#property description "This file only serves as supporting indicator for SubWin"
#property indicator_chart_window
#property indicator_plots 0
//+------------------------------------------------------------------+
input string user01 = "SubSupport";             //Short Name
//+------------------------------------------------------------------+
int OnInit()
{
        IndicatorSetString(INDICATOR_SHORTNAME, user01);
        
        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
{
        return rates_total;
}
//+------------------------------------------------------------------+


Ho evidenziato le modifiche che dovrebbero essere apportate al file sorgente. Ora dobbiamo apportare delle modifiche al nostro codice dell’EA. Creeremo ora una nuova classe:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_Terminal.mqh"
//+------------------------------------------------------------------+
class C_FnSubWin
{
        private :
                string  m_szIndicator;
                int             m_SubWin;
//+------------------------------------------------------------------+
                void Create(const string szIndicator)
                        {
                                int i0;
                                m_szIndicator = szIndicator;
                                if ((i0 = ChartWindowFind(Terminal.Get_ID(), szIndicator)) == -1)
                                        ChartIndicatorAdd(Terminal.Get_ID(), i0 = (int)ChartGetInteger(Terminal.Get_ID(), CHART_WINDOWS_TOTAL), iCustom(NULL, 0, "::" + def_Resource, szIndicator));
                                m_SubWin = i0;
                        }
//+------------------------------------------------------------------+
        public  :
//+------------------------------------------------------------------+
                C_FnSubWin()
                        {
                                m_szIndicator = NULL;
                                m_SubWin = -1;
                        }
//+------------------------------------------------------------------+
                ~C_FnSubWin()
                        {
                                Close();
                        }
//+------------------------------------------------------------------+
                void Close(void)
                        {
                                if (m_SubWin >= 0) ChartIndicatorDelete(Terminal.Get_ID(), m_SubWin, m_szIndicator);
                                m_SubWin = -1;
                        }
//+------------------------------------------------------------------+
inline int GetIdSubWinEA(const string szIndicator = NULL)
                        {
                                if ((szIndicator != NULL) && (m_SubWin < 0)) Create(szIndicator);
                                return m_SubWin;
                        }
//+------------------------------------------------------------------+
inline bool ExistSubWin(void) const { return m_SubWin >= 0; }
//+------------------------------------------------------------------+
};
//+------------------------------------------------------------------+


Questa classe sostituisce C_SubWindow ed ora supporta la creazione di finestre secondarie su un grafico. Per capire come funziona questa classe, dai una rapida occhiata alla nuova classe C_SubWindow qui sotto:

#include "C_ChartFloating.mqh"
#include <NanoEA-SIMD\Auxiliar\C_FnSubWin.mqh>
//+------------------------------------------------------------------+
class C_SubWindow : public C_ChartFloating
{
//+------------------------------------------------------------------+
        private :
                C_FnSubWin      m_fnSubWin;
//+------------------------------------------------------------------+
        public  :
//+------------------------------------------------------------------+
                ~C_SubWindow()
                        {
                                Close();
                        }       
//+------------------------------------------------------------------+
                void Close(void)
                        {
                                m_fnSubWin.Close();
                                CloseAlls();
                        }
//+------------------------------------------------------------------+
inline int GetIdSubWinEA(void)
                        {
                                return m_fnSubWin.GetIdSubWinEA("SubWinSupport");
                        }
//+------------------------------------------------------------------+
inline bool ExistSubWin(void) const { return m_fnSubWin.ExistSubWin(); }
//+------------------------------------------------------------------+
};
//+------------------------------------------------------------------+


Prestare attenzione che la classe contenga la definizione dell'indicatore che verrà utilizzato per supportare i modelli. È evidenziato nel codice sopra. Ora arriva la parte difficile. Se usiamo un altro nome invece di SubWinSupport, la classe C_FnSubWin cercherà un altro indicatore. Useremo questo trucco per evitare di creare i file degli indicatori. Diciamo semplicemente alla classe C_FnSubWin quale dovrebbe essere il nome breve dell'indicatore desiderato. Pertanto, non siamo limitati dal numero di sottofinestre o da file di indicatori non necessari utilizzati solo per creare una sottofinestra dell’Expert Advisor.

Successivamente possiamo passare alla creazione della classe C_TimeAndTrade.


La classe C_TimesAndTrade

La classe oggetto C_TimesAndTrade è composta da diversi piccoli pezzi ognuno dei quali è responsabile di qualcosa di specifico. Il codice mostrato di seguito è la prima cosa che l’EA chiama per questa classe:

void Init(const int iScale = 2)
{
        if (!ExistSubWin())
        {
                CreateCustomSymbol();
                CreateChart();
        }
        ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale)));
}

Questo codice verificherà se la sottofinestra di supporto esiste. Se non esiste ancora, il codice ne creerà una. Ora, dai un'occhiata al seguente codice di supporto iniziale della classe:

inline void CreateCustomSymbol(void)
{
        m_szCustomSymbol = "_" + Terminal.GetFullSymbol();
        SymbolSelect(Terminal.GetFullSymbol(), true);
        SymbolSelect(m_szCustomSymbol, false);
        CustomSymbolDelete(m_szCustomSymbol);
        CustomSymbolCreate(m_szCustomSymbol, StringFormat("Custom\\Robot\\%s", m_szCustomSymbol), Terminal.GetFullSymbol());
        CustomRatesDelete(m_szCustomSymbol, 0, LONG_MAX);
        CustomTicksDelete(m_szCustomSymbol, 0, LONG_MAX);
        SymbolSelect(m_szCustomSymbol, true);
};

Questo codice creerà un simbolo personalizzato e resetterà tutti i dati all'interno di quel simbolo. Per abilitare la visualizzazione dei contenuti del simbolo nella finestra che andremo a creare, occorre prima aggiungere questo simbolo al Market Watch. Questo viene fatto nella riga seguente.

SymbolSelect(m_szCustomSymbol, true);

Il simbolo personalizzato verrà creato in Custom\Robot <Nome simbolo>.. I suoi dati iniziali saranno forniti dal simbolo originale. Questo è implementato nel codice seguente:

CustomSymbolCreate(m_szCustomSymbol, StringFormat("Custom\\Robot\\%s", m_szCustomSymbol), Terminal.GetFullSymbol());

Fondamentalmente, questo è tutto. Aggiungi la classe all'EA ed eseguila come segue:

// ... Expert Advisor code

#include <NanoEA-SIMD\Tape Reading\C_TimesAndTrade.mqh>

// ... Expert Advisor code

input group "Times & Trade"
input   int     user041 = 2;    //Escala
//+------------------------------------------------------------------+
C_TemplateChart Chart;
C_WallPaper     WallPaper;
C_VolumeAtPrice VolumeAtPrice;
C_TimesAndTrade TimesAndTrade;
//+------------------------------------------------------------------+
int OnInit()
{
// ... Expert Advisor code

        TimesAndTrade.Init(user041);
        
        OnTrade();
        EventSetTimer(1);
   
        return INIT_SUCCEEDED;
}


Il risultato è il seguente:


Ed è esattamente quello che ci si aspettava. Ora, aggiungiamo i valori delle operazioni eseguite nel grafico _DOLH22. Questo grafico rifletterà tutte le transazioni eseguite per fornire la rappresentazione grafica di Times & Trade. La presentazione sarà sotto forma di modelli di candele giapponesi, perché sono facili da usare. Prima di questo, dobbiamo fare alcune cose, in particolare, connettere e sincronizzare il simbolo. Questo viene fatto nella funzione seguente.

inline void Connect(void)
{
        switch (m_ConnectionStatus)
        {
                case 0:
                        if (!TerminalInfoInteger(TERMINAL_CONNECTED)) return; else m_ConnectionStatus = 1;
                case 1:
                        if (!SymbolIsSynchronized(Terminal.GetFullSymbol())) return; else m_ConnectionStatus = 2;
                case 2:
                        m_LastTime = TimeLocal();
                        m_MemTickTime = macroMinusMinutes(60, m_LastTime) * 1000;
                        m_ConnectionStatus = 3;
                default:
                        break;
        }
}

La funzione controlla se il terminale è connesso e quindi sincronizza il simbolo. Successivamente, possiamo iniziare a catturare i valori e visualizzarli sullo schermo. Ma per questo è necessario apportare una piccola modifica al codice di inizializzazione. La modifica è evidenziata nel seguente codice:

void Init(const int iScale = 2)
{
        if (!ExistSubWin())
        {
                CreateCustomSymbol();
                CreateChart();
                m_ConnectionStatus = 0;
        }
        ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale)));
}

Successivamente possiamo vedere la sua funzione di cattura.

inline void Update(void)
{
        MqlTick Tick[];
        MqlRates Rates[def_SizeBuff];
        int i0, p1, p2 = 0;
        int iflag;

        if (m_ConnectionStatus < 3) return;
        if ((i0 = CopyTicks(Terminal.GetFullSymbol(), Tick, COPY_TICKS_ALL, m_MemTickTime, def_SizeBuff)) > 0)
        {
                for (p1 = 0, p2 = 0; (p1 < i0) && (Tick[p1].time_msc == m_MemTickTime); p1++);
                for (int c0 = p1, c1 = 0; c0 < i0; c0++)
                {
                        if (Tick[c0].volume == 0) continue;
                        iflag = 0;
                        iflag += ((Tick[c0].flags & TICK_FLAG_BUY) == TICK_FLAG_BUY ? 1 : 0);
                        iflag -= ((Tick[c0].flags & TICK_FLAG_SELL) == TICK_FLAG_SELL ? 1 : 0);
                        if (iflag == 0) continue;
                        Rates[c1].high = Tick[c0].ask;
                        Rates[c1].low = Tick[c0].bid;
                        Rates[c1].open = Tick[c0].last;
                        Rates[c1].close = Tick[c0].last + ((Tick[c0].volume > 200 ? 200 : Tick[c0].volume) * (Terminal.GetTypeSymbol() == C_Terminal::WDO ? 0.02 : 1.0) * iflag);
                        Rates[c1].time = m_LastTime;
                        p2++;
                        c1++;
                        m_LastTime += 60;
                }
                CustomRatesUpdate(m_szCustomSymbol, Rates, p2);
                m_MemTickTime = Tick[i0 - 1].time_msc;
        }
}

La funzione di cui sopra consente di acquisire assolutamente tutti i tick di trading per verificare se sono tick in vendita o in acquisto. Se questi tick sono relativi a variazioni BID o ASK, cioè senza volume, l'informazione non viene salvata. Lo stesso vale per i ticks, che sono ordini diretti che non incidono sul movimento del prezzo, anche se spesso sono correlati al movimento, in quanto ci sono operatori di mercato che forzano il prezzo ad un certo valore solo per evadere un ordine diretto, e poi, poco dopo, lasciare che il prezzo si muova liberamente. Questi tick, relativi alla modifica di BID e ASK, saranno utilizzati in un'altra versione, che vedremo nel prossimo articolo, poiché sono di importanza secondaria nell’intero sistema. Dopo aver controllato il tipo di transazione, abbiamo una sequenza di righe che sono molto importanti e che dovresti comprendere. Queste righe nel codice sottostante costruiranno una candela per ogni tick che è passato attraverso il sistema di analisi e che dovrebbe essere salvato.

Rates[c1].high = Tick[c0].ask;
Rates[c1].low = Tick[c0].bid;
Rates[c1].open = Tick[c0].last;
Rates[c1].close = Tick[c0].last + ((Tick[c0].volume > 200 ? 200 : Tick[c0].volume) * (Terminal.GetTypeSymbol() == C_Terminal::WDO ? 0.02 : 1.0) * iflag);
Rates[c1].time = m_LastTime;

Il massimo e il minimo della candela indicano lo spread al momento del trade, ovvero il valore che esisteva tra BID e ASK sarà l'ombra della candela creata, e il valore di apertura della candela è il prezzo alla quale la transazione è stata effettivamente completata. Ora dai un'occhiata da vicino alla riga di codice evidenziata. Per ogni tick di trading abbiamo il volume, questa linea creerà un piccolo aggiustamento a quel volume in modo che la scala non sia in eccesso. È possibile regolare i valori in base alla propria analisi, a seconda dell'asset, a propria discrezione.

Ora l'ultimo dettaglio - il tempo. Ogni candela corrisponderà a un minuto, in quanto non è possibile tracciare valori inferiori. Quindi ognuna di loro rimarrà nella posizione corrispondente ogni minuto. Questo non è tempo reale, questo è tempo virtuale. Non confondere il tempo di negoziazione con il tempo del grafico: le operazioni possono avvenire in millisecondi, ma le informazioni grafiche verranno tracciate ogni minuto su una scala grafica. Potremmo utilizzare qualsiasi altro valore, ma questo, essendo il più piccolo possibile, semplifica notevolmente la programmazione. Il risultato di questo sistema può essere visto di seguito:

Vediamo che la lettura è del tutto possibile ora e che l'interpretazione è semplice. Sebbene il nastro dell'ordine fosse molto lento al momento dell'acquisizione, penso che sia sufficiente per rendere l'idea.

Le informazioni finali su questo sistema possono essere visualizzate nella figura seguente:

Prestate attenzione, ci sono quattro diverse configurazioni che possono essere visualizzate sul sistema. A cosa servono? Lo vedremo nel prossimo articolo, che aiuterà a capire perché ci sono quattro configurazioni Times & Trade. Ad ogni modo, abbiamo già un sistema funzionante che forse è sufficiente per un uso intensivo. Ma se capisci cosa sta succedendo e cosa sta causando la generazione dei quattro modelli di candele, puoi ottenere molto di più da questo sistema e chissà, magari diventerà il tuo indicatore principale...


Conclusioni

Abbiamo creato il sistema Times & Trade da utilizzare nel nostro EA per analizzare la lettura del nastro. Dovrebbe fornire la stessa velocità di analisi del sistema alternativo presente in MetaTrader 5. Abbiamo raggiunto questo obiettivo attraverso la creazione di un sistema grafico, invece di leggere e cercare di comprendere un'enorme quantità di numeri e valori. Nel prossimo articolo implementeremo alcune informazioni mancanti nel sistema. Avremo bisogno di aggiungere alcuni nuovi elementi al codice del nostro Expert Advisor.



Tradotto dal portoghese da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/pt/articles/10410

File allegati |
EA_-_Times_e_Trade.zip (5982.95 KB)
Sviluppare un Expert Advisor per il trading da zero (Parte 13): Times e Trade (II) Sviluppare un Expert Advisor per il trading da zero (Parte 13): Times e Trade (II)
Oggi costruiremo la seconda parte del sistema Times & Trade per l'analisi del mercato. Nel precedente articolo "Times & Trade (I)" abbiamo discusso di un sistema di organizzazione grafica alternativa, che consentirebbe di avere un indicatore per l'interpretazione più rapida possibile delle transazioni eseguite sul mercato.
Operazioni con matrici e vettori in MQL5 Operazioni con matrici e vettori in MQL5
Le matrici e i vettori sono stati introdotti in MQL5 per un’operatività efficiente con soluzioni matematiche. I nuovi tipi offrono metodi integrati per creare codice conciso e comprensibile, vicino alla notazione matematica. Gli array offrono ampie possibilità, ma ci sono molti casi in cui le matrici sono molto più efficienti.
Impara come progettare un sistema di trading tramite MFI Impara come progettare un sistema di trading tramite MFI
Il nuovo articolo della nostra serie sulla progettazione di un sistema di trading basato sugli indicatori tecnici più popolari considera un nuovo indicatore tecnico - il Money Flow Index (MFI). Lo impareremo in dettaglio e svilupperemo un semplice sistema di trading tramite MQL5 per eseguirlo in MetaTrader 5.
Impara come progettare un sistema di trading tramite Accumulazione/Distribuzione (AD) Impara come progettare un sistema di trading tramite Accumulazione/Distribuzione (AD)
Benvenuti nel nuovo articolo della nostra serie sull'apprendimento di come progettare sistemi di trading basati sugli indicatori tecnici più popolari. In questo articolo, impareremo a conoscere un nuovo indicatore tecnico chiamato Indicatore di Accumulazione/Distribuzione e scopriremo come progettare un sistema di trading MQL5 basato su semplici strategie con AD.