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

Sviluppare un Expert Advisor per il trading da zero (Parte 22): Nuovo sistema di ordini (V)

MetaTrader 5Trading | 24 ottobre 2023, 11:42
402 0
Daniel Jose
Daniel Jose

Introduzione

Non è così facile implementare un nuovo sistema poiché spesso incontriamo problemi che complicano notevolmente il processo. Quando compaiono questi problemi, dobbiamo fermarci e rianalizzare la direzione in cui ci stiamo muovendo, decidendo se possiamo lasciare le cose così come sono o se dobbiamo dargli un nuovo aspetto.

Tali decisioni possono essere abbastanza frequenti durante la creazione di un sistema, soprattutto se non abbiamo una scadenza o un budget chiari: quando non siamo sotto pressione, possiamo testare e aggiustare le cose per fare del nostro meglio per garantire stabilità in termini di sviluppo e miglioramento.

I programmi seri, soprattutto quelli commerciali sviluppati con determinati budget o scadenze, di solito contengono molti errori che necessitano correzioni in seguito. Spesso chi sviluppa il sistema non ha tempo per implementare o apprendere alcune soluzioni che potrebbero essere molto vantaggiose per il sistema. È così che otteniamo programmi che, in molti casi, non sono all’altezza di ciò che i programmatori potrebbero creare. A volte le aziende rilasciano una versione dopo l'altra, con piccoli miglioramenti o correzioni di bug. Questo non perché i bug siano stati rilevati dopo il rilascio del programma, ma perché i programmatori erano sotto pressione prima del rilascio.

Questo di fatto avviene lungo tutta la catena produttiva. Tuttavia, mentre siamo nel processo di creazione della soluzione, stiamo cercando il modo migliore e preferibilmente più semplice. Inoltre, possiamo permetterci di esplorare tutte le soluzioni possibili e fattibili. Se necessario, possiamo fermarci e tornare un po' indietro per modificare e migliorare il processo di sviluppo del sistema. Molto spesso, una piccola sosta e un cambio di direzione possono aiutare molto nello sviluppo del sistema desiderato.

Nell'articolo Sviluppare un sistema di trading da zero (Parte 21) il sistema era quasi pronto. Mancava solo la parte responsabile dello spostamento degli ordini direttamente sul grafico. Per implementare questa parte, ho controllato e ho notato alcune stranezze nel codice: c'erano molte parti che si ripetevano. Tuttavia, siamo stati molto attenti a evitare ripetizioni inutili. Quel che è peggio è che alcune cose non hanno funzionato come avrebbero dovuto, ad esempio, quando si utilizzavano asset molto differenti. Quando abbiamo iniziato a progettare l'EA e quando ho iniziato a documentarlo negli articoli che sono stati pubblicati qui, pensavo di utilizzarlo principalmente per il trading di futures sulla borsa B3. In realtà, ho finito per svilupparlo per tradare il futures sul dollaro o indici noti come WDO e WIN. Ma man mano che il sistema si avvicinava sempre di più a quello che inizialmente volevo utilizzare, mi sono reso conto che poteva essere esteso ad altri mercati o asset. È qui che è sorto il problema.


1.0. Tornare agli appunti

Per comprendere il problema, presta attenzione a un dettaglio importante che molte persone trascurano quando sviluppano un Expert Advisor. Come vengono definiti i contratti nel sistema di trading? MetaTrader 5 fornisce queste informazioni, mentre MQL5 consente di accedervi. Quindi, dobbiamo comprendere i dati in modo da creare la matematica per generalizzare i calcoli e ottenere il sistema più completo.

Il sistema di ordini che stiamo sviluppando è progettato per fare trading direttamente dal grafico, senza la necessità di altre risorse esterne o di qualsiasi cosa che possa essere creata in futuro. Questo sviluppo è un tentativo di creare un sistema di trading molto simile a quello utilizzato nelle piattaforme, ma completamente open source in modo da poter personalizzare e aggiungere le informazioni di cui hai bisogno.

L'idea è quella di consentire all'utente di sapere cosa sta succedendo con una posizione semplicemente guardandola. Sebbene l'idea sembri molto buona, il sistema di trading non rende la vita facile a coloro che stanno cercando di creare un sistema per il FOREX e per i mercati azionari come B3. Il livello di informazioni disponibili è sufficiente per personalizzare gli ordini per un mercato o per un altro, ma creare qualcosa di generale è diventato un problema, quasi un insulto personale. Tuttavia, ho deciso però di affrontare il problema e provare a creare un sistema universale.

Anche se non sono sicuro di poterlo fare davvero, posso almeno mostrarti come trovare le informazioni necessarie e quindi se hai bisogno di personalizzare l'EA per il tuo sistema locale, avrai l'esperienza e la conoscenza di come farlo. Anche se originariamente il sistema non è in grado di gestire la modellazione, potrai adattarla alle tue esigenze.

Un'osservazione: i dati possono essere ottenuti utilizzando il codice MQL5, ma per semplificare il lavoro utilizzerò MetaTrader 5 per mostrare dove si trovano i dati.


1.0.1. Attività aziendali (Azioni) negoziate su B3

Dai un'occhiata alle due immagini seguenti:

     

Le parti evidenziate mostrano i dati che ci servono per calcolare come verrà piazzata la posizione.

Se crei una posizione basata su un valore finanziario, avrai bisogno di questi valori per calcolare i valori di stop loss e take profit. Se non utilizzi l'ordine OCO, le cose saranno ancora più semplici, ma qui presupponiamo che tutti gli ordini siano ordini OCO o posizioni.

Importante: se un asset viene scambiato come azioni frazionarie (ci sono differenze tra i mercati su B3), il volume minimo sarà l'1% del valore specificato, ecco perché invece di tradare 100 a 100 scambieremo 1 a 1. Il calcolo sarà diverso, quindi non dimenticarlo.


1.0.2. Contratti future in B3

Le regole per i contratti futures sono diverse da quelle per il trading azionario, il volume cambia a seconda che si stia facendo trading con un contratto pieno o con un mini contratto e anche da un asset all'altro. Ad esempio, per fare trading sul BOI, dovremmo guardare a come viene riempita la leva finanziaria (moltiplicatore), poiché è ciò che faremo qui. Mi concentrerò sui contratti. In alcuni casi, un contratto completo equivarrà a 25 mini contratti, ma questo può variare, quindi dovresti sempre controllare le regole sul volume della borsa.

Ora diamo un'occhiata alle seguenti immagini del mini dollaro:

     

Questi contratti hanno una data di scadenza, ma per questo articolo non è importante, perché nell'articolo Sviluppare un Expert Advisor di trading da zero (Parte 11), abbiamo considerato come creare un sistema di ordini incrociati per negoziare contratti futures direttamente dalla tua cronologia , e se usi questo metodo non devi preoccuparti di quale contratto è attualmente in fase di negoziazione, poiché l’EA lo farà per te. Prestate attenzione ai punti contrassegnati; sono diversi dal sistema azionario. Ciò a volte può causare problemi, ma l'EA ha gestito questo problema, sebbene questa parte non sia molto intuitiva. Ad ogni modo, col tempo ti abituerai ai giusti valori da utilizzare nella leva finanziaria per negoziare volumi finanziari specifici.

Tuttavia, ho deciso di fissare un obiettivo più alto. È qui che iniziano le difficoltà.


1.0.3. FOREX

Il mio problema era legato al sistema Forex e il mio EA non riusciva a risolverlo. Quando sono riuscito a gestire la leva Forex, ho scoperto che non era possibile utilizzare lo stesso codice dell'EA B3. Questo mi ha infastidito perché non vedo perché dovresti avere due EA che differiscono solo in questa parte. Per capire cosa sta succedendo, date un'occhiata alle seguenti immagini:

     

In B3 abbiamo quattro valori, mentre nel Forex ne abbiamo solo due. I calcoli tra i due mercati non corrispondevano a causa dei due valori mancanti.

Per questo motivo, i calcoli eseguiti dall'EA rendevano molto difficile capire cosa stesse realmente accadendo: a volte i valori calcolati erano troppo alti, a volte il moltiplicatore faceva sì che il sistema di trading rifiutasse l'ordine perché il volume era troppo piccolo rispetto al valore del volume minimo previsto e talvolta i limiti OCO non erano accettati a causa di posizioni errate. Quindi c’era una confusione infinita.

Avendo capito questo, ho deciso di modificare l'EA. Quindi, non calcoleremo il valore nel modo precedente, no, utilizzeremo un metodo diverso. In effetti, questo valore verrà ora adeguato in base all’asset con cui lavoriamo, indipendentemente dal fatto che lo facciamo nel mercato azionario o nel mercato Forex. Pertanto, l'EA si adatterà ai dati ed eseguirà i calcoli correttamente. Tuttavia, dobbiamo sapere cosa stiamo tradando per impostare correttamente il moltiplicatore. E anche se ora, per ragioni computazionali, consentiamo l'uso di valori in virgola mobile nel volume, dovresti evitarlo. In effetti, dovresti utilizzare valori interi che indicano la leva finanziaria utilizzata.

Quindi, non diciamo all’EA quanto vogliamo scambiare. Indichiamo invece il moltiplicatore da applicare al volume minimo consentito. Ecco come ho risolto il problema. Puoi testarlo tu stesso e vedere di persona come funziona.

Per facilitarne la comprensione e ridurre il lavoro, nel prossimo argomento fornirò una breve presentazione dei risultati.


2.0. Visualizzazione dei dati

Consideriamo innanzitutto il caso del mercato azionario, in particolare il mercato azionario brasiliano (B3). Ecco come vengono presentati i dati nell'EA in 5.


2.0.1. Attività B3

Nel caso di azioni societarie quotate alla borsa Brasiliana, il volume minimo di negoziazione è 100. Indicando 1, impostiamo l'EA per negoziare il volume minimo consentito. In questo modo è molto più semplice lavorare con il volume — non è necessario conoscere esattamente il lotto minimo, utilizziamo semplicemente il moltiplicatore e l'EA farà i calcoli necessari per creare un ordine corretto.

Se si utilizzano valori frazionari, indica semplicemente il numero di frazioni da utilizzare, ovvero 50 significa che verranno utilizzate 50 frazioni, se si specifica 15 verranno utilizzate 15 frazioni e così via.

Il risultato è mostrato di seguito nella finestra del box strumenti di MetaTrader 5. Mostra come è stato creato un ordine con il valore del lotto minimo. Se analizzi i valori di take e stop, vedrai che corrispondono a quelli indicati nel grafico, il che significa che l'EA ha funzionato qui.


2.0.2. Mini Dollaro

Qui il volume è 1 a 1, ma nel caso di contratti pieni il ​​valore è diverso. Dai un'occhiata al Chart Trade: i valori indicati come Take e Stop sono gli stessi che trovi sopra. Ma l'EA regola correttamente i valori. Quindi, i valori da prendere in considerazione sono i valori trovati nell'indicatore del grafico, i valori del Chart Trade dovrebbero essere ignorati, ma saranno vicini ai valori indicati sul grafico.


Nel box strumenti vengono visualizzati i seguenti dati:

Esattamente come nell'asset precedente, se eseguiamo il calcolo per verificare i livelli di stop loss e take profit, vedremo che corrispondono a quelli specificati dall'EA, cioè anche l'EA ha superato questa fase senza la necessità di ricompilare il codice , ma solo modificando l’asset.


2.0.3. Forex

Questa parte è un po' più complicata. Per coloro che non hanno familiarità con il Forex, i punti sono piuttosto strani, ma l'EA riesce ancora a capirli.


MetaTrader 5 ci informerà su questo trade pendente come segue:


Ricorda che nel Forex i livelli di leva finanziaria sono diversi da quelli sopra indicati. Ma se esegui i calcoli, vedrai che l'EA è riuscito a fornire i punti corretti e l'ordine è stato creato perfettamente.

Tutto questo viene fatto senza alcuna modifica aggiuntiva se non quelle che mostrerò nella parte dell’implementazione, anche se sono state apportate molte altre modifiche oltre a questa, in modo che l'EA sia davvero adatto sia al mercato azionario che al mercato Forex, senza la necessità di ricompilarlo. Quindi, eccoci qui a completare gli articoli precedenti. Vedremo come spostare i livelli di stop loss e take profit direttamente sul grafico.


3.0. Implementazione

Iniziamo osservando alcune modifiche nel codice.

Innanzitutto ho rimosso il sistema di limiti implementato 3 o 4 versioni fa. Questo perché l'EA a volte si adatta in modo errato al calcolo del lotto tra mercati azionari e forex.

Ho aggiunto un nuovo modello di calcolo per consentire all'EA di funzionare altrettanto bene nei mercati forex e azionari. Ciò non era possibile prima di questa versione. All'inizio, l'EA si concentrava sul lavoro nei mercati azionari, ma ho deciso di estendere le sue funzionalità al forex poiché i metodi di trading non differiscono molto.

Ci sono dettagli riguardanti i problemi di calcolo dei lotti che l'EA non poteva gestire nelle versioni precedenti, ma con le modifiche apportate, ora può essere utilizzato sia nel mercato forex che azionario senza importanti modifiche al codice. Tuttavia, per mantenere la compatibilità con i mercati forex e azionari, ho dovuto apportare numerose modifiche.

Uno di questi cambiamenti è all'inizio del codice:

int OnInit()
{
        static string   memSzUser01 = "";
        
        Terminal.Init();
        WallPaper.Init(user10, user12, user11);
        Mouse.Init(user50, user51, user52);
        if (memSzUser01 != user01)
        {
                Chart.ClearTemplateChart();
                Chart.AddThese(memSzUser01 = user01);
        }
        Chart.InitilizeChartTrade(user20 * Terminal.GetVolumeMinimal(), user21, user22, user23);
        VolumeAtPrice.Init(user32, user33, user30, user31);
        TimesAndTrade.Init(user41);
        TradeView.Initilize();
                
        OnTrade();
        EventSetTimer(1);
   
        return INIT_SUCCEEDED;
}

La parte evidenziata non esisteva precedentemente. Ci sono anche molti altri cambiamenti. Tuttavia non ci concentreremo su questa implementazione. Vedremo invece come utilizzare l'EA per spostare direttamente i livelli di take e stop presenti sul grafico, senza utilizzare altri trucchetti. Quindi passiamo a questa parte.


3.0.1 Spostare gli ordini direttamente sul grafico

Questa parte era molto difficile nelle versioni precedenti, poiché presentavano una serie di problemi irrisolti apparsi nel tempo, che rendevano il compito difficile. Uno dei motivi era che il codice era molto scarno, il che rendeva difficile implementare efficacemente il sistema di spostamento degli ordini direttamente sul grafico. Originariamente il sistema non era destinato a farlo.

Per darti un'idea della portata dei cambiamenti che l'EA ha richiesto (in modo da esser in grado di gestire il movimento degli ordini, compresi gli ordini pendenti e le posizioni, così da poter controllare i movimenti degli ordini limite sul grafico usando il mouse) vediamo come l'EA appariva prima.

Il problema è che quando sono stati creati gli oggetti, hanno sostituito la classe C_HLineTrade. Ciò è stato fatto nell'articolo Sviluppare un EA per il trading da zero (Parte 20). Il sistema ora ha una struttura molto più complessa, quindi per non mostrare nuovamente l'intera immagine sopra, guarderemo solo cosa è successo.

La freccia indica il punto di connessione dove la classe C_HLineTrade è stata rimossa per dare spazio a nuove classi. Ciò ha consentito più implementazioni che abbiamo fatto negli articoli precedenti. Ma la presenza della classe C_OrderView ha interferito con lo sviluppo, tanto da doverla escludere. Ma non è tutto. La classe C_TradeGraphics è stata unita alla vecchia classe C_OrderView ed è comparsa una nuova classe denominata C_IndicatorTradeView. Quindi, questa classe ha sostituito due classi e questo ci ha permesso di sviluppare il sistema di movimento degli ordini.

Quella che presenterò qui è la prima versione di questo sistema. Esiste un'altra versione attualmente in fase di sviluppo, ma verrà presentata in un altro articolo.


3.0.1.1 - Scrittura del codice per il nuovo sistema


Dopo la fusione, il nuovo sistema ha la seguente configurazione:


L'area verde indica un insieme di classi che sono libere, ovvero saranno gestite da MetaTrader 5 e non dall’EA. Ma come è fatto? Consideriamo il processo in dettaglio. Infatti, l'EA creerà, posizionerà ed eliminerà solo le classi e tutti gli oggetti creati da queste classi. Guarda all'interno del codice dell’EA e non troverai strutture o variabili che faranno riferimento agli oggetti creati nell'area verde. Ciò consente la creazione di un numero illimitato di oggetti, finchè MetaTrader 5 può allocare memoria nel sistema operativo. Il numero di oggetti non è limitato da strutture o variabili all'interno dell'EA.

Potresti pensare che solo un pazzo può creare una struttura del genere. Ok allora puoi darmi del pazzo, perché l'ho creata io, e funziona. Inoltre, sorprendentemente, non sovraccarica più di tanto il sistema. La gente mi chiama pazzo, quindi non è un grosso problema... Andiamo oltre. Potresti notare una certa lentezza nello spostamento degli ordini pendenti o limite. Ciò non è dovuto ad un errore del codice o ad un problema con il tuo computer o in MetaTrader 5, il problema è che il sistema muoverà gli ordini pendenti o i limite spostandoli sul server di trading stesso, e c'è una latenza tra il movimento e la risposta del server. Ma questo è il modo migliore e più sicuro per operare in alcuni scenari, che tuttavia non ci consente di fare altre cose che voglio che l'EA faccia. Quindi, nei prossimi articoli risolveremo questo problema aggiungendo una nuova funzionalità nell'EA, inoltre renderemo il sistema più fluido, ma questo senza modificare la struttura sopra. Manipoleremo solo il codice correttamente, anche se questo rende il sistema meno sicuro, ma fino ad allora, chissà, potrei trovare una buona soluzione a questo problema.

Diamo uno sguardo ad alcuni punti importanti dell’attuale nuovo codice. Inizieremo con una funzione poco studiata, il suo codice è simile a questo:

void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result)
{
#define def_IsBuy(A) ((A == ORDER_TYPE_BUY_LIMIT) || (A == ORDER_TYPE_BUY_STOP) || (A == ORDER_TYPE_BUY_STOP_LIMIT) || (A == ORDER_TYPE_BUY))

        ulong ticket;
        
        if (trans.symbol == Terminal.GetSymbol()) switch (trans.type)
        {
                case TRADE_TRANSACTION_DEAL_ADD:
                case TRADE_TRANSACTION_ORDER_ADD:
                        ticket = trans.order;
                        ticket = (ticket == 0 ? trans.position : ticket);
                        TradeView.IndicatorInfosAdd(ticket);
                        TradeView.UpdateInfosIndicators(0, ticket, trans.price, trans.price_tp, trans.price_sl, trans.volume, (trans.position > 0 ? trans.deal_type == DEAL_TYPE_BUY : def_IsBuy(trans.order_type)));
                        break;
                case TRADE_TRANSACTION_ORDER_DELETE:
                                if (trans.order != trans.position) TradeView.RemoveIndicator(trans.order);
                                else
                                        TradeView.UpdateInfosIndicators(0, trans.position, trans.price, trans.price_tp, trans.price_sl, trans.volume, trans.deal_type == DEAL_TYPE_BUY);
                                if (!PositionSelectByTicket(trans.position))
                                        TradeView.RemoveIndicator(trans.position);
                        break;
                case TRADE_TRANSACTION_ORDER_UPDATE:
                        TradeView.UpdateInfosIndicators(0, trans.order, trans.price, trans.price_tp, trans.price_sl, trans.volume, def_IsBuy(trans.order_type));
                        break;
                case TRADE_TRANSACTION_POSITION:
                        TradeView.UpdateInfosIndicators(0, trans.position, trans.price, trans.price_tp, trans.price_sl, trans.volume, trans.deal_type == DEAL_TYPE_BUY);
                        break;
        }
        
        
#undef def_IsBuy
}

Questo codice è molto interessante perché ci evita di dover controllare ogni nuova posizione che appare o viene modificata. In realtà, sarà il server stesso ad informarci su ciò che sta accadendo, quindi dobbiamo solo assicurarci che l'EA risponda correttamente agli eventi. Studiate bene questo modo di codificare e utilizzare l'evento OnTradeTransaction , perché se utilizzassi il modello per analizzare le cose come veniva fatto nelle versioni precedenti, spenderemmo molto tempo sui controlli. In questo caso, il server fa tutto il lavoro duro per noi e possiamo sapere con certezza che i valori sul grafico mostrano realmente ciò che vede il server in questo momento.

Prima di arrivare ai punti salienti del codice sopra, diamo un'occhiata ad un altro frammento.

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
        Mouse.DispatchMessage(id, lparam, dparam, sparam);
        switch (id)
        {
                case CHARTEVENT_CHART_CHANGE:
                        Terminal.Resize();
                        WallPaper.Resize();
                        TimesAndTrade.Resize();
        break;
        }
        Chart.DispatchMessage(id, lparam, dparam, sparam);
        VolumeAtPrice.DispatchMessage(id, sparam);
        TradeView.DispatchMessage(id, lparam, dparam, sparam);
        ChartRedraw();
}

Quindi, tutto viene fatto in un unico posto. Possiamo entrare nella classe e vedere cosa succede dentro.


3.1. La classe C_IndicatorTradeView

Questa classe viene utilizzata per presentare e manipolare i dati. Fondamentalmente include le vecchie classi C_OrderView e C_TradeGraphics, come accennato in precedenza. Ma manipola i dati in un modo totalmente differente. Diamo un'occhiata ad alcuni punti di questa classe.

Inizieremo con la funzione di inizializzazione, il cui codice è simile al seguente:

void Initilize(void)
{
        int orders = OrdersTotal();
        ulong ticket;
        bool isBuy;
        long info;
        double tp, sl;

        ChartSetInteger(Terminal.Get_ID(), CHART_SHOW_OBJECT_DESCR, false);
        ChartSetInteger(Terminal.Get_ID(), CHART_SHOW_TRADE_LEVELS, false);
        ChartSetInteger(Terminal.Get_ID(), CHART_DRAG_TRADE_LEVELS, false);
        for (int c0 = 0; c0 <= orders; c0++) if ((ticket = OrderGetTicket(c0)) > 0) if (OrderGetString(ORDER_SYMBOL) == Terminal.GetSymbol())
        {
                info = OrderGetInteger(ORDER_TYPE);
                isBuy = ((info == ORDER_TYPE_BUY_LIMIT) || (info == ORDER_TYPE_BUY_STOP) || (info == ORDER_TYPE_BUY_STOP_LIMIT) || (info == ORDER_TYPE_BUY));
                IndicatorInfosAdd(ticket);
                UpdateInfosIndicators(-1, ticket, OrderGetDouble(ORDER_PRICE_OPEN), OrderGetDouble(ORDER_TP), OrderGetDouble(ORDER_SL), OrderGetDouble(ORDER_VOLUME_CURRENT), isBuy);
        }
        orders = PositionsTotal();
        for (int c0 = 0; c0 <= orders; c0++) if (PositionGetSymbol(c0) == Terminal.GetSymbol())
        {
                tp = PositionGetDouble(POSITION_TP);
                sl = PositionGetDouble(POSITION_SL);
                ticket = PositionGetInteger(POSITION_TICKET);
                IndicatorInfosAdd(ticket);
                UpdateInfosIndicators(1, ticket, PositionGetDouble(POSITION_PRICE_OPEN), tp, sl, PositionGetDouble(POSITION_VOLUME), PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY);
        }
        CreateIndicatorTrade(def_IndicatorTicket0, IT_PENDING);
        CreateIndicatorTrade(def_IndicatorTicket0, IT_TAKE);
        CreateIndicatorTrade(def_IndicatorTicket0, IT_STOP);
}

Fondamentalmente, ciò che stiamo facendo è creare gli indicatori necessari per lavorare e presentare tutto ciò che esiste attualmente nel conto, come posizioni o ordini pendenti. Ma le linee evidenziate sono importanti qui, perché se non stai utilizzando un sistema di ordini incrociati, avrai sul grafico i punti dell'ordine (da MetaTrader 5), e se fai clic e trascini questi punti, l'EA aggiornerà i nuovi punti con le modifiche degli indicatori. Questo non è un grosso ostacolo, ma dobbiamo utilizzare realmente il sistema che stiamo sviluppando, altrimenti che senso ha svilupparlo?

Dopo, prestate attenzione al seguente codice:

void UpdateInfosIndicators(char test, ulong ticket, double pr, double tp, double sl, double vol, bool isBuy)
{
        bool isPending;
                                
        isPending = (test > 0 ? false : (test < 0 ? true : (ticket == def_IndicatorTicket0 ? true : OrderSelect(ticket))));
        PositionAxlePrice(ticket, (isPending ? IT_RESULT : IT_PENDING), 0);
        PositionAxlePrice(ticket, (isPending ? IT_PENDING : IT_RESULT), pr);
        SetTextValue(ticket, (isPending ? IT_PENDING : IT_RESULT), vol);
        PositionAxlePrice(ticket, IT_TAKE, tp);
        PositionAxlePrice(ticket, IT_STOP, sl);
        SetTextValue(ticket, IT_TAKE, vol, (isBuy ? tp - pr : pr - tp));
        SetTextValue(ticket, IT_STOP, vol, (isBuy ? sl - pr : pr - sl));
}

Riceve e aggiorna i dati, presentando i valori corretti in termini di valori finanziari e i punti in cui si trovano gli ordini. Fondamentalmente non vogliamo preoccuparci se c'è un ordine pendente o una posizione — la funzione lo posizionerà in modo da poterla vedere correttamente sul grafico.

Ecco la funzione successiva.

inline double SecureChannelPosition(void)
{
        double Res = 0, sl, profit, bid, ask;
        ulong ticket;
                                
        bid = SymbolInfoDouble(Terminal.GetSymbol(), SYMBOL_BID);
        ask = SymbolInfoDouble(Terminal.GetSymbol(), SYMBOL_ASK);
        for (int i0 = PositionsTotal() - 1; i0 >= 0; i0--) if (PositionGetSymbol(i0) == Terminal.GetSymbol())
        {
                ticket = PositionGetInteger(POSITION_TICKET);
                SetTextValue(ticket, IT_RESULT, PositionGetDouble(POSITION_VOLUME), profit = PositionGetDouble(POSITION_PROFIT), PositionGetDouble(POSITION_PRICE_OPEN));
                sl = PositionGetDouble(POSITION_SL);
                if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                {
                        if (ask < sl) ClosePosition(ticket);
                }else
                {
                        if ((bid > sl) && (sl > 0)) ClosePosition(ticket);
                }
                Res += profit;
        }
        return Res;
};

Viene chiamata dall'evento OnTick, quindi è piuttosto critico in termini di velocità e carico del sistema. L'unica cosa che fa, oltre ai controlli, è aggiornare il valore sul grafico, che è implementato dal codice evidenziato. Tieni presente che il ticket della posizione è molto importante qui.

Diamo uno sguardo più da vicino alla funzione evidenziata sopra.

void SetTextValue(ulong ticket, eIndicatorTrade it, double value0, double value1 = 0.0, double priceOpen = 0.0)
{
        double finance;
                                
        switch (it)
        {
                case IT_RESULT  :
                        PositionAxlePrice(ticket, it, priceOpen);
                        PositionAxlePrice(ticket, IT_PENDING, 0);
                        m_EditInfo2.SetTextValue(MountName(ticket, it, EV_PROFIT), value1);
                case IT_PENDING:
                        m_EditInfo1.SetTextValue(MountName(ticket, it, EV_EDIT), value0 / Terminal.GetVolumeMinimal(), def_ColorVolumeEdit);
                        break;
                case IT_TAKE    :
                case IT_STOP    :
                        finance = (value1 / Terminal.GetAdjustToTrade()) * value0;
                        m_EditInfo1.SetTextValue(MountName(ticket, it, EV_EDIT), finance);
                        break;
        }
}

Ecco come vengono visualizzati i valori corretti. Ma la domanda è: come spostarli? Questo viene fatto da altri tre codici. Naturalmente, potresti evitarli e utilizzare lo stesso sistema MetaTrader 5, che è molto più veloce dell’attuale sistema EA. Ma, come ho detto, preferisco utilizzare l'EA, poiché presto riceverà altri miglioramenti.

La prima funzione responsabile dello spostamento può essere vista di seguito, ma mostra solo i frammenti necessari per spostare i punti, sia i limiti che l'ordine stesso, poiché l'intero codice è molto più esteso e non è necessario per capire come muoversi con i movimenti del mouse.

void DispatchMessage(int id, long lparam, double dparam, string sparam)
{
        ulong   ticket;

// ... Code ....

        switch (id)
        {
                case CHARTEVENT_MOUSE_MOVE:
                        Mouse.GetPositionDP(dt, price);
                        mKeys   = Mouse.GetButtonStatus();
                        bEClick  = (mKeys & 0x01) == 0x01;    //Left mouse click 
                        bKeyBuy  = (mKeys & 0x04) == 0x04;    //SHIFT press 
                        bKeySell = (mKeys & 0x08) == 0x08;    //CTRL press 
                        if (bKeyBuy != bKeySell)
                        {
                                if (!bMounting)
                                {
                                        Mouse.Hide();
                                        bIsDT = Chart.GetBaseFinance(leverange, valueTp, valueSl);
                                        valueTp = Terminal.AdjustPrice(valueTp * Terminal.GetAdjustToTrade() / leverange);
                                        valueSl = Terminal.AdjustPrice(valueSl * Terminal.GetAdjustToTrade() / leverange);
                                        m_TradeLine.SpotLight(MountName(def_IndicatorTicket0, IT_PENDING, EV_LINE));
                                        bMounting = true;
                                }
                                tp = price + (bKeyBuy ? valueTp : (-valueTp));
                                sl = price + (bKeyBuy ? (-valueSl) : valueSl);
                                UpdateInfosIndicators(0, def_IndicatorTicket0, price, tp, sl, leverange, bKeyBuy);
                                if ((bEClick) && (memLocal == 0)) CreateOrderPendent(leverange, bKeyBuy, memLocal = price, tp, sl, bIsDT);
                        }else if (bMounting)
                        {
                                UpdateInfosIndicators(0, def_IndicatorTicket0, 0, 0, 0, 0, false);
                                Mouse.Show();
                                memLocal = 0;
                                bMounting = false;
                        }else if ((!bMounting) && (bKeyBuy == bKeySell))
                        {
                                if (bEClick)
                                {
                                        bIsMove = false;
                                        m_TradeLine.SpotLight();
                                }
                                MoveSelection(price, mKeys);
                        }
                        break;

// ... Code ...
                case CHARTEVENT_OBJECT_CLICK:
                        if (GetIndicatorInfos(sparam, ticket, price, it, ev)) switch (ev)
                        {

// ... Code ...

                                case EV_MOVE:
                                        if (bIsMove)
                                        {
                                                m_TradeLine.SpotLight();
                                                bIsMove = false;
                                        }else
                                        {
                                                m_TradeLine.SpotLight(MountName(ticket, it, EV_LINE));
                                                bIsMove = true;
                                        }
                                        break;
                        }
                        break;
        }
}

Cerchiamo di capire cosa sta succedendo. Alla fine dell'articolo c'è un video che mostra come farlo e cosa accadrà effettivamente. Ma prima cerchiamo di capire.

Ogni indicazione ha un oggetto che ne permette la selezione (ad eccezione del risultato che non può essere spostato). Un clic su questo punto cambierà la linea di indicazione — diventerà più spessa. Quando ciò accade, i movimenti del mouse verranno catturati e convertiti in una nuova posizione per questo oggetto, finché non si farà un nuovo clic all'esterno dell'oggetto di selezione che consente il movimento dell'oggetto. Nota che non è necessario tenere premuto il pulsante del mouse, basta fare clic una volta, trascinare e poi fare nuovamente clic.

Ma in realtà solo una parte del lavoro viene fatta qui. Ci sono altre due funzioni che ci aiutano. Una l’abbiamo già vista sopra, che ha il compito di mostrare i valori calcolati; il successivo è responsabile di essere la pietra che fa sembrare l'EA una lumaca quando si utilizza il sistema di movimento dell'ordine o del livello limite. È mostrata di seguito:

void MoveSelection(double price, uint keys)
{
        static string memStr = NULL;
        static ulong ticket = 0;
        static eIndicatorTrade it;
        eEventType ev;
        double tp, sl, pr;
        bool isPending;
                                
        string sz0 = m_TradeLine.GetObjectSelected();
        
        if (sz0 != NULL)
        {
                if (memStr != sz0) GetIndicatorInfos(memStr = sz0, ticket, pr, it, ev);
                isPending = OrderSelect(ticket);
                switch (it)
                {
                        case IT_TAKE:
                                if (isPending) ModifyOrderPendent(ticket, macroGetPrice(IT_PENDING), price, macroGetPrice(IT_STOP));
                                else ModifyPosition(ticket, price, macroGetPrice(IT_STOP));
                                break;
                        case IT_STOP:
                                if (isPending) ModifyOrderPendent(ticket, macroGetPrice(IT_PENDING), macroGetPrice(IT_TAKE), price);
                                else ModifyPosition(ticket, macroGetPrice(IT_TAKE), price);
                                break;
                        case IT_PENDING:
                                pr = macroGetPrice(IT_PENDING);
                                tp = macroGetPrice(IT_TAKE);
                                sl = macroGetPrice(IT_STOP);
                                ModifyOrderPendent(ticket, price, (tp == 0 ? 0 : price + tp - pr), (sl == 0 ? 0 : price + sl - pr));
                                break;
                }
        };
}

La chiamo funzione pietra perché è responsabile della lentezza del sistema di posizionamento. Se non capisci dai un'occhiata ai punti evidenziati. Ognuna di esse è una funzione che si trova all'interno della classe C_Router e che invierà una richiesta al server di trading, quindi se il server per un motivo o per l'altro impiega un po' di tempo a rispondere (e questo avverrà sempre a causa della latenza), il sistema di posizionamento sarà più o meno lento, ma se il server risponde velocemente il sistema sarà fluido, o meglio, le cose andranno più agevolmente. Successivamente lo modificheremo, perché questo sistema non ci permette di fare altre cose. In ogni caso, dovete tenere presente che in questo modo opererete in modo un po' più sicuro, soprattutto per coloro che amano operare in movimenti altamente volatili, dove i prezzi possono muoversi molto rapidamente, ma anche così si corre il rischio di avere dei limiti di salto. Non c'è modo, qualcosa deve essere sacrificato. Per coloro che accettano di operare sapendo che questo è esattamente ciò che sarà all'interno del server, l'EA è pronto a questo punto. Ma per chi vuole acquisire fluidità nel funzionamento dell'EA, anche a costo di non essere preciso nei punti, nei prossimi articoli le cose cambieranno e diventeranno più interessanti.

Il video qui sotto mostra come funziona effettivamente il sistema, quindi presta attenzione ai valori ​​sul grafico e nella casella strumenti.


Conclusioni

Anche se ora abbiamo un Expert Advisor molto interessante per il trading, ti consiglio di utilizzarlo su un conto demo per un po' per abituarti a come funziona. Prometto che non ci saranno più grandi cambiamenti nel modo in cui funziona. Ci saranno solo miglioramenti e nel prossimo articolo aggiungeremo alcune cose che mancano a questo EA, a scapito della sicurezza che fornisce. Ad ogni modo, questa sarà un'ottima fonte per imparare come funziona il sistema di trading e come manipolare la piattaforma per ottenere qualunque tipo di modellazione dei dati abbiamo bisogno.

Non dimenticare, se ritieni che spostare gli ordini o i livelli limite sia troppo lento, puoi rimuovere i punti che ho mostrato nell'articolo e utilizzare MetaTrader 5 stesso per spostare ordini o limiti e utilizzare un EA come supporto per aiutare a interpretare i dati. Che tu lo faccia o no è una tua scelta...


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

File allegati |
Sviluppare un Expert Advisor per il trading da zero (Parte 23): Nuovo sistema di ordini (VI) Sviluppare un Expert Advisor per il trading da zero (Parte 23): Nuovo sistema di ordini (VI)
Renderemo il sistema degli ordini più flessibile. Qui prenderemo in considerazione le modifiche al codice che lo renderanno più flessibile, il che ci permetterà di modificare i livelli di stop della posizione molto più velocemente.
Avvio di MetaTrader VPS per la prima volta: Istruzioni passo-passo Avvio di MetaTrader VPS per la prima volta: Istruzioni passo-passo
Tutti coloro che hanno utilizzato robot di trading o abbonamenti a segnali prima o poi riconoscono la necessità di noleggiare un server di hosting affidabile 24/7 per la loro piattaforma di trading. Consigliamo di utilizzare MetaTrader VPS per una serie di motivi. Potete pagare comodamente il servizio e gestire l'abbonamento attraverso il vostro account MQL5.community.
Come utilizzare i modelli ONNX in MQL5 Come utilizzare i modelli ONNX in MQL5
ONNX (Open Neural Network Exchange) è un formato aperto creato per rappresentare modelli di machine learning. In questo articolo considereremo come creare un modello CNN-LSTM per prevedere le serie temporali finanziarie. Mostreremo anche come utilizzare il modello ONNX creato in un Expert Advisor MQL5.
Impara come progettare un sistema di trading tramite Awesome Oscillator Impara come progettare un sistema di trading tramite Awesome Oscillator
In questo nuovo articolo della nostra serie, impareremo a conoscere un nuovo strumento tecnico che può essere utile per il nostro trading. Si tratta dell'indicatore Awesome Oscillator (AO). Impareremo a progettare un sistema di trading con questo indicatore.