Meno codice, più azione... scrivere un EA

 

Cercherò (o cercheremo, se qualcuno è interessato) di fare una struttura per gli Expert Advisors. Il più adatto possibile solo per cose semplici e che non richiedono alcuna conoscenza sostanziale da parte del programmatore applicato.

In contrasto con la pratica accettata a livello locale, la progettazione sarà condotta dall'alto verso il basso. In altre parole, prima scriviamo il file principale (e l'unico) dell'EA per l'utente finale, rimuoviamo tutto ciò che ovviamente non è necessario, e scriviamo una libreria per far funzionare il tutto. Poi aggiungiamo un nuovo caso d'uso e aggiorniamo la libreria.

Come contro-tesi e polemica con https://www.mql5.com/ru/articles/5654 e i consiglieri di Karputov

Naturalmente, prima di procedere, è necessario impostare la "linea del partito" e il "target-comunismo":

- 100 linee sono sufficienti all'utente per implementare la strategia. (a parte i commenti, l'input e altre #proprietà).

- Il numero di nuove "entità" (funzioni/classi/metodi/costanti) dovrebbe essere ridotto al minimo.

- La libreria deve contenere un numero contato di file.

- Potenzialmente adatto per la GUI

- espandibile da plugin

Obiettivi raggiungibili ? difficile, ma in linea di principio SI. Ci sono alcuni modi per farlo e alcune idee. Ma non c'è ancora una soluzione pronta :-)

Il passo attuale è quello di organizzare l'acquisizione dei dati da parte dell'esperto. In modo tale che sia facile per l'utente descriverli, ma allo stesso tempo ci sono ancora "piste" per metadati e ulteriori estensioni. (Andando avanti - la parte GUI, almeno quella di debug, dovrebbe già essere implementata su ulteriore codice)


Come iniziatore, ho creato un semplice caso d'uso - facciamo trading sull'incrocio di due MA

Corrispondentemente, la parte di input assomiglia a questa

/** ------- ПАРАМЕТРЫ СОВЕТНИКА ------
**/
input ENUM_APPLIED_PRICE FAST_MA_PRICE=PRICE_CLOSE;
input ENUM_MA_METHOD FAST_MA_METHOD=MODE_EMA;
input int FAST_MA_PERIOD=14;
input int FAST_MA_SHIFT=0;

input ENUM_APPLIED_PRICE SLOW_MA_PRICE=PRICE_CLOSE;
input ENUM_MA_METHOD SLOW_MA_METHOD=MODE_SMA;
input int SLOW_MA_PERIOD=54;
input int SLOW_MA_SHIFT=0;

La prossima cosa che un utente deve fare - descrivere quali dati riceve dall'input. Elencateli almeno:

// просто перечисляем идентификаторы данных
// всех которые нужны для принятия решений
enum ENUM_SERIES {
   FAST_MA,       // id. значений FAST_MA
   SLOW_MA,       // id. значений SLOW_MA
   TOTAL_SERIES   // последний элемент перечисления = кол-во элементов
};

e spiegare come calcola/riceve questi dati (è lungo, ma vale per entrambi i terminali).

/// вычисление данных
/// эксперт будет обращаться к функции каждый раз когда ему необходимы данные
/// управление кешированием и очерёдность(взаимозависимость) вычислений лежит на верхнем уровне
/// @arg ea - эксперт
/// @arg id - ид.серии данных
/// @arg shift - сдвиг в серии
/// @arg data[] - кешированные результаты
/// @return double - конкретное значение для [id][shift] или EMPTY_VALUE если не может быть вычилено
/// если данные могут быть кешированы, они должны быть сохраненны в массиве data
double GetData(EA *ea,int id,int shift,double &data[])
{
#ifdef __MQL4__
   // для 4-ки всё просто - по идентификаторам серии и бара получить данные
   switch ((ENUM_SERIES)id) {
      case FAST_MA:
         return data[shift]=iMA(ea.Symbol,ea.Period,FAST_MA_PERIOD,0,FAST_MA_METHOD,FAST_MA_PRICE,shift);
      case SLOW_MA:
         return data[shift]=iMA(ea.Symbol,ea.Period,SLOW_MA_PERIOD,0,SLOW_MA_METHOD,SLOW_MA_PRICE,shift);
   }
   return EMPTY_VALUE;
#else
   // для 5-ки несколко сложнее (и кстати не проверено) - надо ещё заводить хендлы стандартных индикаторов
   // и проводить (возможно)лишнее копирование
   static d_fast_ma=0;
   static d_slow_ma=0;
   if (d_fast_ma==0) d_fast_ma=iMA(ea.Symbol,ea.Period,FAST_MA_PERIOD,0,FAST_MA_METHOD,FAST_MA_PRICE,shift);
   if (d_slow_ma==0) d_slow_ma=iMA(ea.Symbol,ea.Period,SLOW_MA_PERIOD,0,SLOW_MA_METHOD,SLOW_MA_PRICE,shift);  
   double tmp[1];
   switch((ENUM_SERIES)id) {
      case FAST_MA: CopyBuffer(d_fast_ma,0,shift,1,tmp); return data[shift]=tmp[0];
      case SLOW_MA: CopyBuffer(d_slow_ma,0,shift,1,tmp); return data[shift]=tmp[0];
   }
   return EMPTY_VALUE;
#endif
}

e infine descrivere il segnale commerciale:

/// генерация(вычисление) сигнала при открытии бара
/// @arg ea - эксперт
/// @arg shift - номер бара в таймсерии. Типично будет 0
/// @return int - сигнал OP_BUY или OP_SELL или -1 если сигнала нет 
int SignalOfCross(EA *ea,int shift)
{
   if (FAST_MA_PRICE!=PRICE_OPEN || SLOW_MA_PRICE!=PRICE_OPEN) shift++;
   if (ea.CrossedUp(FAST_MA,SLOW_MA,shift)) {
      return OP_BUY;
   }
   if (ea.CrossedDn(FAST_MA,SLOW_MA,shift)) {
      return OP_SELL;
   }
   return -1;
}

QUESTO È FONDAMENTALMENTE TUTTO. Questo è sufficiente per implementare un EA e ovviamente non richiede all'utente di leggere tonnellate di documentazione. L'utente ha solo bisogno di una conoscenza di base di MQL. Tutto il resto dovrebbe essere fatto dalla libreria (o qui, la parola di fantasia - motore). Dovrebbe essere costruito per l'utente, non perché l'utente impari un'altra API multi-volume.

A proposito, ecco OnInit :

int OnInit()
{
   ea = new EA();
   // настраиваем таймфрейм "по умолчанию"
   //   символ и период - текущие
   //   TOTAL_SERIES наборов данных и кешируем по 30 в каждом
   //   для получения данных служит GetData
   ea.SetupTimeframe(_Symbol,_Period,TOTAL_SERIES,30,GetData);
   // настраиваем сигнал "по умолчанию"
   ea.SetupSignal(SignalOfCross);
   // ------ настройки завершены ------
   // остальная часть одинакова для всех советников
   int ret;
   if ((ret=ea.OnInit())!=INIT_SUCCEEDED) {
      return ret;
   }
   EventSetTimer(60);

   return(INIT_SUCCEEDED);
}
  

..

Библиотека для простого и быстрого создания программ для MetaTrader (Часть I). Концепция, организация данных, первые результаты
Библиотека для простого и быстрого создания программ для MetaTrader (Часть I). Концепция, организация данных, первые результаты
  • www.mql5.com
Разбирая огромное количество торговых стратегий, множество заказов на изготовление программ для терминалов MT5 и MT4, просматривая огромное разнообразие различных сайтов по тематике скриптов, индикаторов и роботов для MetaTrader, я пришёл к выводу, что всё это многообразие в подавляющем своём большинстве строится на фактически одних и тех же...
 
Inserite correttamente tutti i vostri codici: è impossibile guardare questo grigiore opaco. C'è un chiaro piano d'azione: cliccare sul pulsante nell'editor, inserire il codice nel campo risultante. Ma tu ostinatamente inserisci una tela di testo e poi cerchi di applicare lo stile "codice" a questa tela
 
Vladimir Karputov:
Inserite correttamente tutti i vostri codici: è impossibile guardare questo grigiore. C'è un chiaro piano d'azione: cliccare sul pulsante nell'editor, inserire il codice nel campo risultante. Si inserisce ostinatamente una tela di testo e poi si cerca di applicare lo stile "codice" a questa tela

Un frammento può ancora essere trattato, ma un po' di più è già un dolore...

Voglio dire, non dipende da me - dipende dai webmaster. Come, nel 2019, con l'abbondanza di fondi, abbiano ottenuto questo - un mistero :-)

Ma per renderlo più divertente in futuro, scriverò prima post più o meno grandi nel wiki, e poi li copierò qui e ridurrò il volume del codice pubblicato.

 
Maxim Kuznetsov:

Un frammento può ancora essere trattato, ma un po' di più è già un dolore...

Voglio dire, non dipende da me - dipende dai webmaster. Come, nel 2019, con l'abbondanza di fondi, ci siano riusciti - è un mistero :-)

Ma per divertirsi di più in futuro, i post più o meno grandi saranno scritti prima sul wiki, e poi trasferiti qui tramite copia-incolla e ridurre il volume del codice pubblicato.

A quanto pare ora devi copiare il blocco di codice e incollarlo in Notepad

Poi copiate da Notepad e incollate di nuovo, ma prima create un nuovo blocco per il "nuovo" codice

 

Ho creato un modello di base per l'EA e ho fatto il file delle strategie separatamente.

Pensi che sia facile per l'utente?

Avete ancora bisogno di un minimo di conoscenza della programmazione!

E nessun "aiuto" istruzioni, video, niente ti salva.

L'utente avrà poi bisogno di te per pedalare strategie gratis.

E non leggeranno la guida.

 
Vitaly Muzichenko:

A quanto pare ora dovresti copiare il blocco di codice e incollarlo in Notepad

Poi copiate dal blocco note e incollate di nuovo, ma prima create un nuovo blocco per il "nuovo" codice

Ci sono voluti un po' di problemi, ma l'ho "colorato". :-)

Un sassolino (o meglio un sassolino) ai webmaster di cui sopra: quando si incolla nell'editor inline, o meglio ovviamente alla prima "colorazione", l'editor morde involontariamente una parte di codice che non gli piace. In particolare, ha modificato arbitrariamente "if ((ret=ea.OnInit())!=INIT_SECEED) {..}" . Apparentemente, l'algoritmo di evidenziazione crede che OnInit sia l'unico e non può essere sovraccaricato nella classe.

 
È uno pseudocodice o è già per l'applicazione? La funzioneGetData non può usare "statiche" per gli "handle" degli indicatori(d_fast_ma,d_slow_ma), perché l'utente prenderà un altro paio di "handle" per il filtraggio o qualcos'altro con parametri diversi (su un altro simbolo, per esempio). Si dovrebbe o mettere in cache gli "handle" in qualche oggetto o (se non si guarda all'efficienza) ottenere di nuovo gli "handle" ogni volta - dovrebbero essere messi in cache dal terminale stesso quando i parametri sono uguali.
 
Maxim Kuznetsov:

Naturalmente, prima di procedere, è necessario stabilire la "linea di partito" e il "target-comunismo":

1) l'utente ha bisogno solo di 100 linee per implementare la strategia. (a parte i commenti, l'input e altre #proprietà).

2) Il numero di nuove "entità" (funzioni/classi/metodi/costanti) per esso dovrebbe essere ridotto al minimo.

3) la biblioteca deve contenere un numero contato di file.

4) potenzialmente adatto alla GUI

5) espandibile tramite plugin


3) Che differenza fa quanti file contiene una libreria? 1, 10, 100, 1000? Tutto dovrebbe essere fatto per la comodità dello sviluppatore. Se si sente a suo agio a mettere tutto in piccole cartelle, si senta libero. Se lui/lei è abituato a codificare tutto in un unico file, si senta libero. In generale non è difficile assemblare un mega-file da un mucchio di mezzi automatici disparati. Quindi non insisterei su questo punto.

4) GUI utilizzabile - non è del tutto chiaro come sia. La libreria è un livello isolato di logica di business in modo maturo. Questo livello non dovrebbe dipendere dalla GUI esterna in alcun modo. La sua interfaccia grafica dovrebbe dipendere da questo livello.

 
Maxim Kuznetsov:
if (d_fast_ma==0) d_fast_ma=iMA(ea.Symbol,ea.Period,FAST_MA_PERIOD,0,FAST_MA_METHOD,FAST_MA_PRICE,shift);
if (d_slow_ma==0) d_slow_ma=iMA(ea.Symbol,ea.Period,SLOW_MA_PERIOD,0,SLOW_MA_METHOD,SLOW_MA_PRICE,shift);  


Il tuo approccio è puramente procedurale fin dall'inizio: quello che vedo è quello che dico. E se la media non dovesse essere calcolata sui prezzi, ma, diciamo, sul volume o su un altro indicatore? Dobbiamo riscrivere di nuovo l'utente? Il calcolo della media è un algoritmo. Ciò a cui volete applicare l'algoritmo sono i dati. Stai mescolando l'algoritmo con i dati, invece di separarli subito (come questo pseudo codice):

int period_ma = 12;
int shift = 3;
double fast_ma = SMA(Close, period, shift);

Oh, ho dimenticato l'indice della serie. - In realtà non dovrebbe essercene uno. Devi calcolare tutto in un ring buffer combinando gli algoritmi in pipeline.

 
Maxim Kuznetsov:

Come contro-tesi e polemica a https://www.mql5.com/ru/articles/5654 e ai consiglieri di Karputov

Ilmio è stato immeritatamente dimenticato. E invano, c'è molto.

 
Vasiliy Sokolov:

Il tuo approccio è puramente procedurale fin dall'inizio: quello che vedo è quello che dico. E se la media non dovesse essere calcolata sui prezzi, ma, diciamo, sul volume o su un altro indicatore? Dobbiamo riscrivere di nuovo l'utente? Il calcolo della media è un algoritmo. Ciò a cui volete applicare l'algoritmo sono i dati. Stai mescolando l'algoritmo con i dati, invece di separarli subito (come questo pseudo codice):

Ops, ho dimenticato l'indice della serie. - In realtà non dovrebbe essercene uno. Devi calcolare tutto in un ring buffer combinando gli algoritmi in pipeline.

Gran parte di tutto è fatto per questo. In modo che tu possa calcolare tutto e l'Expert Advisor possa capire da solo le sequenze e le interrelazioni. Una volta ho fatto un foglio di calcolo a la micro-excel su MT4, e l'organizzazione dei calcoli è basata su questo modello.

Lo stile del caso d'uso è fondamentalmente procedurale, poiché è il più comune. I potenziali utenti(programmatori principianti) scrivono in questo modo.