Un'altra classe OOP MQL5
Introduzione
Costruire un EA completo orientato agli oggetti che funzioni davvero è a mio modesto parere un compito impegnativo che richiede molte abilità: ragionamento logico, pensiero divergente, capacità di analisi e sintesi, immaginazione, ecc. Diciamo che se il sistema di trading automatizzato che dobbiamo risolvere fosse una partita a scacchi, la sua idea di trading sarebbe la strategia degli scacchi. E l'esecuzione della strategia scacchistica attraverso le tattiche sarebbe la programmazione del robot con l'uso di indicatori tecnici, figure grafici, idee economiche fondamentali e assiomi concettuali.
Figura 1. Particolare della Scuola di Atene di Raffaello Sanzio. In questa immagine vediamo i filosofi Platone e Aristotele impegnati in una profonda discussione.
Platone rappresenta qui il mondo concettuale e Aristotele il mondo empirista.
Sono consapevole della difficoltà di questo esercizio. Un OO EA non è estremamente difficile da programmare, ma è vero che presenta un certo grado di difficoltà per le persone con poca esperienza nello sviluppo di applicazioni. Come in ogni altra disciplina, questo è, a sua volta, dovuto alla mancanza di esperienza stessa, ecco perché cerco di insegnarti questo argomento attraverso un esempio specifico che sono sicuro che capirai. Non scoraggiarti se ti senti ancora insicuro nel gestire i concetti OOP, troverai le cose molto più facili una volta implementati i tuoi primi cinque EA, diciamo. Non devi costruire nulla da zero per ora, basta capire cosa spiego qui!
L'intero processo di ideazione e implementazione di un sistema di trading può essere semplificato in molti sensi quando viene eseguito da più persone, anche se questo fatto pone il problema della comunicazione. Voglio dire che la persona che concepisce la strategia di investimento non è tenuta a gestire i concetti di programmazione che gestisce il programmatore. E lo sviluppatore MQL5 potrebbe non capire all'inizio alcuni aspetti importanti della strategia di trading dei propri clienti.
Questo è un problema classico nell'ingegneria del software che ha portato alla creazione di molte metodologie di sviluppo software come Scrum, Test Driven Development (TDD), Extreme programming (XP), etc. È fondamentale essere consapevoli delle insidie del linguaggio. A proposito, per quanto ne sarà a tua conoscenza, Wikipedia afferma: "la metodologia di sviluppo del software o la metodologia di sviluppo del sistema nell'ingegneria del software è un quadro che viene utilizzato per strutturare, pianificare e controllare il processo di sviluppo di un sistema informativo".
Assumeremo di essere in grado di concepire e implementare rapidamente idee di trading di successo. Possiamo anche supporre di essere alla fine di un processo di sviluppo iterativo in cui il sistema di trading pensato dal nostro cliente è già stato ben definito e compreso da tutti. Come preferisci. A proposito, d'ora in poi farò riferimento in questo testo ad alcuni articoli educativi disponibili in ARTICOLI DI PROGRAMMAZIONE MQL5 in modo da poter controllare e ricordare rapidamente alcune idee, quando necessario, per eseguire con successo questo esercizio. Sei pronto?
1. I tuoi primi passi nell'adozione del nuovo paradigma
1.1. Perché OOP è buono per programmare i tuoi EA Forex?
Forse ti stai chiedendo a questo punto perché devi fare questa cosa. Lascia che ti dica prima di tutto che non sei costretto ad essere OOP. In ogni caso sarebbe bene essere un OOP per poter fare un ulteriore passo avanti nella tua conoscenza della programmazione dei sistemi di trading automatizzati.
Il modo classico di sviluppare applicazioni, la cosiddetta programmazione procedurale, presenta questi inconvenienti:
- Rende difficile modellare i problemi. Sotto questo vecchio paradigma la soluzione del problema principale è ridotta e divisa in più semplici sottoproblemi risolti da moduli funzionali, vale a dire: funzioni e procedure.
- Rende difficile il riutilizzo del codice, il che a sua volta ostacola i costi, l'affidabilità, la flessibilità e la manutenzione.
Il riutilizzo del codice è più semplice con il nuovo stile orientato agli oggetti. Questo è molto importante! Molti esperti ritengono che il riutilizzo del codice sia la vera soluzione alla maggior parte dei problemi di sviluppo software.
A questo punto dobbiamo menzionare tipi di dati astratti (ADT). OOP consente la creazione di ADT. Un ADT è un'astrazione del concetto tradizionale di tipo di dati che è presente in tutti i linguaggi di programmazione. Il suo uso principale è quello di comodamente definire il dominio dati delle applicazioni. Include\Arrays\Array.mqh, Include\Arrays\List.mqh e Include\Arrays\Tree.mqh sono alcuni esempi di tipi di dati astratti MQL5.
In in breve, il paradigma di programmazione orientato agli oggetti vuole che tu progetti le applicazioni a livello concettuale per consentirti di trarre vantaggio dal riutilizzo del codice, dall’affidabilità, dalla flessibilità e dalla facilità di manutenzione.
1.2. Sei un ragionatore concettuale? UML viene in soccorso
Hai mai sentito parlare di UML? UML è l'acronimo di Unified Modeling Language. È un linguaggio grafico per la progettazione di sistemi orientati agli oggetti. Noi umani dovremmo prima pensare ai nostri sistemi nella fase di analisi e poi codificarli con un linguaggio di programmazione. Andare dall'alto verso il basso è meno folle per gli sviluppatori. Tuttavia, la mia esperienza come analista dice che a volte questo non è possibile a causa di diverse cose: l'app deve essere fatta in un tempo molto breve, non c'è nessuno nel team che possa applicare rapidamente la propria conoscenza di UML, o forse alcune persone del team non conoscono alcune parti di UML.
UML è a mio parere un buon strumento di analisi che puoi usare se ti senti a tuo agio con esso e se le circostanze che circondano il progetto sono ok. Per favore, leggi Come sviluppare un Expert Advisor utilizzando UML Tools se sei interessato ad esplorare l'argomento UML. Quell'articolo è forse un po 'travolgente, ma serve a ottenere un quadro generale su come gli ingegneri del software professionisti lavorano la loro analisi. Dovresti completare un corso di diverse settimane per comprendere appieno UML! Per ora va bene sapere cos'è UML. Secondo la mia esperienza questo strumento di analisi non viene sempre utilizzato in tutti i progetti software a causa di diverse circostanze presenti nel mondo reale.
Figura 2. Logo UML.
1.3. Salve, mondo! La tua prima classe OO
Se sei un principiante completo della programmazione orientata agli oggetti, ti consiglio di leggere prima la documentazione ufficiale su OO disponibile in MQL5 Reference e quindi dare un'occhiata a Scrivere un expert advisor utilizzando l'approccio di programmazione orientato agli oggetti MQL5 per ottenere le basi. Assicurati di integrare queste letture con altri materiali. D'ora in poi presumo che tu conosca già qualche OOP, quindi capirai facilmente il classico esempio della classe Person che in MQL5 è il seguente:
//+------------------------------------------------------------------+ //| CPerson Class | //+------------------------------------------------------------------+ class CPerson { protected: string m_first_name; string m_surname; datetime m_birth; public: //--- Constructor and destructor methods CPerson(void); ~CPerson(void); //--- Getter methods string GetFirstName(void); string GetSurname(void); datetime GetBirth(void); //--- Setter methods void SetFirstName(string first_name); void SetSurname(string surname); void SetBirth(datetime birth); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CPerson::CPerson(void) { Alert("Hello world! I am run when an object of type CPerson is created!"); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CPerson::~CPerson(void) { Alert("Goodbye world! I am run when the object is destroyed!"); } //+------------------------------------------------------------------+ //| GetFirstName | //+------------------------------------------------------------------+ string CPerson::GetFirstName(void) { return m_first_name; } //+------------------------------------------------------------------+ //| GetSurname | //+------------------------------------------------------------------+ string CPerson::GetSurname(void) { return m_surname; } //+------------------------------------------------------------------+ //| GetBirth | //+------------------------------------------------------------------+ datetime CPerson::GetBirth(void) { return m_birth; } //+------------------------------------------------------------------+ //| SetFirstName | //+------------------------------------------------------------------+ void CPerson::SetFirstName(string first_name) { m_first_name=first_name; } //+------------------------------------------------------------------+ //| SetSurname | //+------------------------------------------------------------------+ void CPerson::SetSurname(string surname) { m_surname=surname; } //+------------------------------------------------------------------+ //| SetBirth | //+------------------------------------------------------------------+ void CPerson::SetBirth(datetime birth) { m_birth=birth; } //+------------------------------------------------------------------+
Quanto segue è per gli sviluppatori puristi ossessionati dalla scrittura di codice di qualità. A differenza di alcuni esempi disponibili in MQL5 Programming Articles e molti altri software disponibili in Code Base, la classe precedente utilizza le stesse convenzioni di programmazione applicate da MetaQuotes Software Corp. per codificare il loro framework MQL5. Ti incoraggio a scrivere il tuo codice proprio come fa MetaQuotes. A proposito, il thread intitolato Informazioni sulle convenzioni nei programmi OOP MQL5tratta di questo argomento.
In poche parole, alcune importanti convenzioni applicate nella scrittura person.mqh sono:
- Il nome della classe CPerson inizia con la lettera C maiuscola.
- I nomi dei metodi sono camel cased e iniziano con una lettera maiuscola, ad esempio, GetFirstName, SetSurname, ecc.
- I nomi delle proprietà protette sono preceduti dal prefisso m_,, ad esempio m_first_name, m_surname e m_birth .
- La parola riservata questo non viene utilizzata per fare riferimento ai membri della classe all'interno della classe stessa.
Per favore, dai un'occhiata ad alcuni file framework MQL5, ad esempio Include\Arrays\Array.mqh, Include\Arrays\List.mqh, Include\Trade\Trade.mqh, e guarda come viene scritto il codice MQL5 originale.
2. Programmiamo il nostro primo EA orientato agli oggetti
2.1. L'idea del sistema di trading
La nostra idea di trading è semplice: "Le tendenze brevi dei mercati volatili sono quasi casuali". Questo è tutto! Questo è stato osservato da diversi esperti in alcune circostanze. Se questa ipotesi è vera, il nostro robot Forex deve funzionare per necessità. Dato un punto casuale su un grafico il movimento successivo può ovviamente andare sia su che giù, non lo sappiamo. Il fatto è che se la differenza tra i livelli SL e TP stabiliti è sufficientemente piccola, allora quella differenza non è significativa in termini assoluti, e abbiamo quindi raggiunto l'aspettativa matematica. Questo sistema lascerà che funzioni l'aspettativa matematica. Una volta ottenuto il codice EA in questo articolo ed eseguito il backtest, vedrai che richiede una politica di gestione del denaro molto semplice.
2.2. Lo scheletro OOP del robot
In questa sezione stiamo sviluppando la strategia di cui sopra attraverso il ragionamento astratto richiesto dalla programmazione orientata agli oggetti. Allora perché non iniziamo a pensare al nostro EA come se fosse una creatura vivente? Sotto questa visione la nostra macchina Forex può essere composta da tre parti principali: un cervello, qualcosa che chiameremo evoluzione e un grafico.
Il cervello è la parte del robot che contiene i dati necessari per operare, qualcosa come una memoria di sola lettura (ROM). Il grafico è il pezzo di informazione che emula il grafico su cui opera il robot. Infine, la cosiddetta evoluzione è un dato contenente informazioni temporali come lo stato del robot in un dato momento, la storia delle operazioni eseguite, ecc. È come se stessimo progettando un essere umano attraverso i suoi organi, qualcosa come un Frankenstein, perché dobbiamo sviluppare un'app per il settore sanitario. Ogni organo è in questo contesto un concetto semantico unico associato ad alcune altre parti del tutto.
Prima di tutto creiamo la cartella MQL5\Include\Mine per memorizzare le nostre cose personalizzate. Questa è solo un'idea per organizzare il tuo codice. È bene sapere che puoi farlo nei tuoi sviluppi, ma ovviamente non sei costretto a farlo. Creeremo quindi il file MQL5\Include\Mine\Enums.mqh per memorizzare gli enum creati da noi:
//+------------------------------------------------------------------+ //| Status enumeration | //+------------------------------------------------------------------+ enum ENUM_STATUS_EA { BUY, SELL, DO_NOTHING }; //+------------------------------------------------------------------+ //| Lifetime enumeration | //+------------------------------------------------------------------+ enum ENUM_LIFE_EA { HOUR, DAY, WEEK, MONTH, YEAR }; //+------------------------------------------------------------------+
Successivamente, è il momento di creare l'embrione del nostro EA che si chiamerà ExpertSimpleRandom.mq5! Quindi, per favore, crea la cartella MQL5\Experts\SimpleRandom e poi crea all'interno il file ExpertSimpleRandom.mq5 con questo codice:
//+------------------------------------------------------------------+ //| ExpertSimpleRandom.mq5 | //| Copyright © 2013, Jordi Bassagañas | //+------------------------------------------------------------------+ #property copyright "Copyright © 2013, laplacianlab" #property link "https://www.mql5.com/it/articles" #property version "1.00" #include <Trade\Trade.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\PositionInfo.mqh> #include <Indicators\Indicators.mqh> #include <Mine\Enums.mqh> #include <..\Experts\SimpleRandom\CSimpleRandom.mqh> input int StopLoss; input int TakeProfit; input double LotSize; input ENUM_LIFE_EA TimeLife; MqlTick tick; CSimpleRandom *SR=new CSimpleRandom(StopLoss,TakeProfit,LotSize,TimeLife); //+------------------------------------------------------------------+ //| Initialization function | //+------------------------------------------------------------------+ int OnInit(void) { SR.Init(); return(0); } //+------------------------------------------------------------------+ //| Deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { SR.Deinit(); delete(SR); } //+------------------------------------------------------------------+ //| OnTick event function | //+------------------------------------------------------------------+ void OnTick() { SymbolInfoTick(_Symbol,tick); SR.Go(tick.ask,tick.bid); } //+------------------------------------------------------------------+
Questo è solo uno dei tanti approcci possibili. Tutto questo è fondamentalmente per illustrare come funziona OOP in MQL5. Come vedi, la classe principale di Expert Advisor si chiama CSimpleRandom.mqh, per favore, salvala in MQL5\Experts\SimpleRandom\CSimpleRandom.mqh:
//+------------------------------------------------------------------+ //| ExpertSimpleRandom.mq5 | //| Copyright © 2013, Jordi Bassagañas | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> #include <Mine\Enums.mqh> #include <..\Experts\SimpleRandom\CBrain.mqh> #include <..\Experts\SimpleRandom\CEvolution.mqh> #include <..\Experts\SimpleRandom\CGraphic.mqh> //+------------------------------------------------------------------+ //| CSimpleRandom Class | //+------------------------------------------------------------------+ class CSimpleRandom { protected: CBrain *m_brain; CEvolution *m_evolution; CGraphic *m_graphic; CTrade *m_trade; CPositionInfo *m_positionInfo; public: //--- Constructor and destructor methods CSimpleRandom(int stop_loss,int take_profit,double lot_size,ENUM_LIFE_EA time_life); ~CSimpleRandom(void); //--- Getter methods CBrain *GetBrain(void); CEvolution *GetEvolution(void); CGraphic *GetGraphic(void); CTrade *GetTrade(void); CPositionInfo *GetPositionInfo(void); //--- Specific methods of CSimpleRandom bool Init(); void Deinit(void); bool Go(double ask,double bid); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CSimpleRandom::CSimpleRandom(int stop_loss,int take_profit,double lot_size,ENUM_LIFE_EA time_life) { int lifeInSeconds; switch(time_life) { case HOUR: lifeInSeconds=3600; break; case DAY: lifeInSeconds=86400; break; case WEEK: lifeInSeconds=604800; break; case MONTH: lifeInSeconds=2592000; break; // One year default: lifeInSeconds=31536000; break; } m_brain=new CBrain(TimeLocal(),TimeLocal()+lifeInSeconds,lot_size,stop_loss,take_profit); m_evolution=new CEvolution(DO_NOTHING); m_graphic=new CGraphic(_Symbol); m_trade=new CTrade(); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CSimpleRandom::~CSimpleRandom(void) { delete(m_brain); delete(m_evolution); delete(m_graphic); delete(m_trade); } //+------------------------------------------------------------------+ //| GetBrain | //+------------------------------------------------------------------+ CBrain *CSimpleRandom::GetBrain(void) { return m_brain; } //+------------------------------------------------------------------+ //| GetBrain | //+------------------------------------------------------------------+ CEvolution *CSimpleRandom::GetEvolution(void) { return m_evolution; } //+------------------------------------------------------------------+ //| GetGraphic | //+------------------------------------------------------------------+ CGraphic *CSimpleRandom::GetGraphic(void) { return m_graphic; } //+------------------------------------------------------------------+ //| GetTrade | //+------------------------------------------------------------------+ CTrade *CSimpleRandom::GetTrade(void) { return m_trade; } //+------------------------------------------------------------------+ //| GetPositionInfo | //+------------------------------------------------------------------+ CPositionInfo *CSimpleRandom::GetPositionInfo(void) { return m_positionInfo; } //+------------------------------------------------------------------+ //| CSimpleRandom initialization | //+------------------------------------------------------------------+ bool CSimpleRandom::Init(void) { // Initialization logic here... return true; } //+------------------------------------------------------------------+ //| CSimpleRandom deinitialization | //+------------------------------------------------------------------+ void CSimpleRandom::Deinit(void) { // Deinitialization logic here... delete(m_brain); delete(m_evolution); delete(m_graphic); delete(m_trade); } //+------------------------------------------------------------------+ //| CSimpleRandom Go | //+------------------------------------------------------------------+ bool CSimpleRandom::Go(double ask,double bid) { double tp; double sl; int coin=m_brain.GetRandomNumber(0,1); // Is there any open position? if(!m_positionInfo.Select(_Symbol)) { // If not, we open one if(coin==0) { GetEvolution().SetStatus(BUY); } else { GetEvolution().SetStatus(SELL); } } // If so, let it work the mathematical expectation. else GetEvolution().SetStatus(DO_NOTHING); switch(GetEvolution().GetStatus()) { case BUY: tp = ask + m_brain.GetTakeProfit() * _Point; sl = bid - m_brain.GetStopLoss() * _Point; GetTrade().PositionOpen(_Symbol,ORDER_TYPE_BUY,m_brain.GetSize(),ask,sl,tp); break; case SELL: sl = ask + m_brain.GetStopLoss() * _Point; tp = bid - m_brain.GetTakeProfit() * _Point; GetTrade().PositionOpen(_Symbol,ORDER_TYPE_SELL,m_brain.GetSize(),bid,sl,tp); break; case DO_NOTHING: // Nothing... break; } // If there is some error we return false, for now we always return true return(true); } //+------------------------------------------------------------------+
2.3. Associazione di CSimpleRandom a oggetti di tipo complesso
Si noti come gli oggetti personalizzati di tipo CBrain, CEvolution e CGraphic siano collegati a CSimpleRandom.
Per prima cosa definiamo le proprietà protette corrispondenti:
protected:
CBrain *m_brain;
CEvolution *m_evolution;
CGraphic *m_graphic;
E subito dopo instanziamo quegli oggetti all'interno del costruttore:
m_brain=new CBrain(TimeLocal(), TimeLocal() + lifeInSeconds, lot_size, stop_loss, take_profit); m_evolution=new CEvolution(DO_NOTHING); m_graphic=new CGraphic(_Symbol);
Quello che facciamo è creare dinamicamente oggetti di tipo complesso proprio come spiegano i documenti ufficiali in Object Pointers. Con questo schema possiamo accedere alle funzionalità di CBrain, CEvolution and CGraphic direttamente da CSimpleRandom. Potremmo eseguire ad esempio il seguente codice in ExpertSimpleRandom.mq5:
//+------------------------------------------------------------------+ //| OnTick event function | //+------------------------------------------------------------------+ void OnTick() { // ... int randNumber=SR.GetBrain().GetRandomNumber(4, 8); // ... }
Scrivo ora il codice di CBrain,, CEvolution e CGraphic per concludere questa sezione. Si prega di notare che ci sono alcune parti che non sono codificate perché non sono strettamente necessarie per eseguire il backtest di SimpleRandom. È lasciato come esercizio per te per codificare le parti mancanti di queste classi, sentiti libero di svilupparle come vuoi. Ad esempio, m_death non viene effettivamente utilizzato, anche se l'idea alla base è quella di sapere fin dall'inizio la data in cui il robot terminerà la sua attività.
//+------------------------------------------------------------------+ //| ExpertSimpleRandom | //| Copyright © 2013, Jordi Bassagaсas | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| CBrain Class | //+------------------------------------------------------------------+ class CBrain { protected: ENUM_TIMEFRAMES m_period; // period must always be initialized to PERIOD_M1 to fit the system's idea datetime m_birth; // The datetime in which the robot is initialized for the first time datetime m_death; // The datetime in which the robot will die double m_size; // The size of the positions int m_stopLoss; // Stop loss int m_takeProfit; // Take profit public: //--- Constructor and destructor methods CBrain(datetime birth,datetime death,double size,int stopLoss,int takeProfit); ~CBrain(void); //--- Getter methods datetime GetBirth(void); datetime GetDeath(void); double GetSize(void); int GetStopLoss(void); int GetTakeProfit(void); //--- Setter methods void SetBirth(datetime birth); void SetDeath(datetime death); void SetSize(double size); void SetStopLoss(int stopLoss); void SetTakeProfit(int takeProfit); //--- Brain specific logic int GetRandomNumber(int a,int b); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CBrain::CBrain(datetime birth,datetime death,double size,int stopLoss,int takeProfit) { MathSrand(GetTickCount()); m_period=PERIOD_M1; m_birth=birth; m_death=death; m_size=size; m_stopLoss=stopLoss; m_takeProfit=takeProfit; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CBrain::~CBrain(void) { } //+------------------------------------------------------------------+ //| GetBirth | //+------------------------------------------------------------------+ datetime CBrain::GetBirth(void) { return m_birth; } //+------------------------------------------------------------------+ //| GetDeath | //+------------------------------------------------------------------+ datetime CBrain::GetDeath(void) { return m_death; } //+------------------------------------------------------------------+ //| GetSize | //+------------------------------------------------------------------+ double CBrain::GetSize(void) { return m_size; } //+------------------------------------------------------------------+ //| GetStopLoss | //+------------------------------------------------------------------+ int CBrain::GetStopLoss(void) { return m_stopLoss; } //+------------------------------------------------------------------+ //| GetTakeProfit | //+------------------------------------------------------------------+ int CBrain::GetTakeProfit(void) { return m_takeProfit; } //+------------------------------------------------------------------+ //| SetBirth | //+------------------------------------------------------------------+ void CBrain::SetBirth(datetime birth) { m_birth=birth; } //+------------------------------------------------------------------+ //| SetDeath | //+------------------------------------------------------------------+ void CBrain::SetDeath(datetime death) { m_death=death; } //+------------------------------------------------------------------+ //| SetSize | //+------------------------------------------------------------------+ void CBrain::SetSize(double size) { m_size=size; } //+------------------------------------------------------------------+ //| SetStopLoss | //+------------------------------------------------------------------+ void CBrain::SetStopLoss(int stopLoss) { m_stopLoss=stopLoss; } //+------------------------------------------------------------------+ //| SetTakeProfit | //+------------------------------------------------------------------+ void CBrain::SetTakeProfit(int takeProfit) { m_takeProfit=takeProfit; } //+------------------------------------------------------------------+ //| GetRandomNumber | //+------------------------------------------------------------------+ int CBrain::GetRandomNumber(int a,int b) { return(a+(MathRand()%(b-a+1))); } //+------------------------------------------------------------------+
//+------------------------------------------------------------------+ //| ExpertSimpleRandom | //| Copyright © 2013, Jordi Bassagaсas | //+------------------------------------------------------------------+ #include <Indicators\Indicators.mqh> #include <Mine\Enums.mqh> //+------------------------------------------------------------------+ //| CEvolution Class | //+------------------------------------------------------------------+ class CEvolution { protected: ENUM_STATUS_EA m_status; // The current EA's status CArrayObj* m_operations; // History of the operations performed by the EA public: //--- Constructor and destructor methods CEvolution(ENUM_STATUS_EA status); ~CEvolution(void); //--- Getter methods ENUM_STATUS_EA GetStatus(void); CArrayObj *GetOperations(void); //--- Setter methods void SetStatus(ENUM_STATUS_EA status); void SetOperation(CObject *operation); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CEvolution::CEvolution(ENUM_STATUS_EA status) { m_status=status; m_operations=new CArrayObj; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CEvolution::~CEvolution(void) { delete(m_operations); } //+------------------------------------------------------------------+ //| GetStatus | //+------------------------------------------------------------------+ ENUM_STATUS_EA CEvolution::GetStatus(void) { return m_status; } //+------------------------------------------------------------------+ //| GetOperations | //+------------------------------------------------------------------+ CArrayObj *CEvolution::GetOperations(void) { return m_operations; } //+------------------------------------------------------------------+ //| SetStatus | //+------------------------------------------------------------------+ void CEvolution::SetStatus(ENUM_STATUS_EA status) { m_status=status; } //+------------------------------------------------------------------+ //| SetOperation | //+------------------------------------------------------------------+ void CEvolution::SetOperation(CObject *operation) { m_operations.Add(operation); } //+------------------------------------------------------------------+
//+------------------------------------------------------------------+ //| ExpertSimpleRandom.mq5 | //| Copyright © 2013, Jordi Bassagaсas | //+------------------------------------------------------------------+ #include <Trade\SymbolInfo.mqh> #include <Arrays\ArrayObj.mqh> //+------------------------------------------------------------------+ //| CGrapic Class | //+------------------------------------------------------------------+ class CGraphic { protected: ENUM_TIMEFRAMES m_period; // Graphic's timeframe string m_pair; // Graphic's pair CSymbolInfo* m_symbol; // CSymbolInfo object CArrayObj* m_bars; // Array of bars public: //--- Constructor and destructor methods CGraphic(string pair); ~CGraphic(void); //--- Getter methods string GetPair(void); CSymbolInfo *GetSymbol(void); CArrayObj *GetBars(void); //--- Setter methods void SetPair(string pair); void SetSymbol(CSymbolInfo *symbol); void SetBar(CObject *bar); }; //+------------------------------------------------------------------+ //| Constuctor | //+------------------------------------------------------------------+ CGraphic::CGraphic(string pair) { m_period=PERIOD_M1; m_pair=pair; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CGraphic::~CGraphic(void) { } //+------------------------------------------------------------------+ //| GetPair | //+------------------------------------------------------------------+ string CGraphic::GetPair(void) { return m_pair; } //+------------------------------------------------------------------+ //| GetSymbol | //+------------------------------------------------------------------+ CSymbolInfo *CGraphic::GetSymbol(void) { return m_symbol; } //+------------------------------------------------------------------+ //| GetBars | //+------------------------------------------------------------------+ CArrayObj *CGraphic::GetBars(void) { return m_bars; } //+------------------------------------------------------------------+ //| SetPair | //+------------------------------------------------------------------+ void CGraphic::SetPair(string pair) { m_pair=pair; } //+------------------------------------------------------------------+ //| SetSymbol | //+------------------------------------------------------------------+ void CGraphic::SetSymbol(CSymbolInfo *symbol) { m_symbol=symbol; } //+------------------------------------------------------------------+ //| SetBar | //+------------------------------------------------------------------+ void CGraphic::SetBar(CObject *bar) { m_bars.Add(bar); } //+------------------------------------------------------------------+
3. Backtesting ExpertSimpleRandom.mq5
Questo sistema di trading casuale ha dimostrato di essere valido solo per determinati livelli di stop loss e take profit, come previsto. Naturalmente, questi intervalli SL/TP vincitori non sono gli stessi per tutti i simboli. Questo perché ogni simbolo mostra la propria personalità in un dato momento, o in altre parole, tutte le coppie di valute si muovono in modo diverso rispetto al resto. Quindi si prega di identificare prima questi livelli nel backtesting prima di eseguire ExpertSimpleRandom.mq5 in un ambiente reale.
Condivido qui alcuni dati di esempio per i quali l'idea esposta in questo articolo sembra essere vincente. Questo può essere dedotto dopo aver eseguito molte volte ExpertSimpleRandom.mq5 in MetaTrader 5 Strategy Tester.
Alcuni input dei vincitori per EURUSD, gennaio 2012, sono:
- StopLoss: 400
- TakeProfit: 600
- LotSize: 0.01
- TimeLife: MONTH
Corsa numero 1:
Corsa numero 2:
Corsa numero 3:
Conclusione
Abbiamo imparato ad applicare la programmazione orientata agli oggetti nei nostri sistemi di trading automatizzati. Per fare questo abbiamo dovuto prima definire una strategia di trading meccanico. La nostra idea di trading è stata molto semplice: "Le tendenze brevi dei mercati volatili sono quasi casuali". Questo è stato osservato da diversi esperti in alcune circostanze.
Subito dopo abbiamo pensato al nostro EA in termini reali come se fosse una creatura vivente. Grazie a questa visione abbiamo visto che la nostra macchina Forex può essere composta da tre parti principali: un cervello, qualcosa che abbiamo chiamato evoluzione e un grafico.
E infine abbiamo programmato l'expert advisor del sistema che incorpora la logica necessaria per eseguire il backtest, abbiamo eseguito molte volte il robot nel gennaio 2012 e abbiamo scoperto che la maggior parte delle volte il sistema vince. L'idea alla base di questo sistema si è dimostrata vera, ma la sua efficacia non è molto elevata a causa della sua semplicità.
Tradotto dall’inglese da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/en/articles/703
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso