Domande su OOP in MQL5 - pagina 28

 
Dmitry Fedoseev:

E se non usi le classi, ti stanchi di scrivere costantemente qualcosa come SymbolInfoDouble(_Symbol,MODE_BID). Questo balla ogni volta - sia parentesi che underscore, e non sai se premere il capslock (e poi da qualche altra parte senza guardare, digitare un'intera stringa maiuscola e riscriverla) o tenere premuto lo shifter. Almeno è qui che l'OOP è utile. Se almeno fanno delle classi per tutte queste funzioni, allora sì - sono enormi. Se lo scrivi per te stesso, non è un problema. Per quanto riguarda il lavoro con gli ordini, non ci sono molte funzioni di uso frequente, possiamo semplicemente mettere alcune funzioni in una libreria. Ma in generale, un approccio ideale non è ancora stato trovato.

Ecco la mia visione della classe che può aprire/chiudere/impostare lo stop loss e poi visualizzarelo stato dell'ordine

class CConstVolume
{
protected:
   static const double  VolumeMAX;
   static const double  VolumeMIN;
   static const double  VolumeSTEP;
   static const double  ZerroPrice;
   static const int     VolumeDIGITS;
   static int           GetDigitsInVolumeStep(); };
//___________________________________________________________________________
static int CConstVolume::GetDigitsInVolumeStep()
{  int result = 0;
   long i = 10000000, k = long(::SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP) / 0.0000001);
   while(result < 7 && k % i > 0)
   {  i /= 10;
      result++; }
   return(result); }
//____________________________________________________________________
static const double CConstVolume::VolumeMAX = ::SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
//____________________________________________________________________
static const double CConstVolume::VolumeMIN = ::SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
//____________________________________________________________________
static const double CConstVolume::VolumeSTEP = ::SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
static const double CConstVolume::ZerroPrice = ::NormalizeDouble(0.0, _Digits);
//____________________________________________________________________
static const int CConstVolume::VolumeDIGITS = CConstVolume::GetDigitsInVolumeStep();
//____________________________________________________________________




//+------------------------------------------------------------------+
//|   class COrder                                                   |
//+------------------------------------------------------------------+
class COrder : private CConstVolume
{
private:
   SOrderInfo        m_info;        //структура для инициализации класса, и хранения информации о ордере, тип, цена отркытия, лот, и состояние ордера
   CError            error;         //класс с описание ошибок на 2-х языках
   int               sl_error_count;//счетчик ошибок установки стоплосса/тейка
   bool              m_needstoploss;//флаг для установки стоплосса, сбросим когда все ОК
   bool              CheckMarginRequirements();
   bool              ServerDisable();
   int               Ordersend();
   int               CheckOrderByMagicnumber(int magic_);   //метод нужен для поиска открытого ордера по магику, использую в конструкторе
   void              SetStoploss();
   void              NULLOrder()             { ZeroMemory(m_info); m_info.cmd = -1; m_info.status = ErrorOrder; m_needstoploss = false;   }
   void              PrintError(string func) { Print(func); error.GetLastError();                                                         }
public:
                     COrder():m_needstoploss(false) { NULLOrder();                                                                        }
                     COrder(SOrderInfo &ordersetting);
   SOrderInfo        GetOrderInfo(); 
   bool              Orderclose();};
//________________________________

e notare l'uso su un simbolo - specialmente una classe statica da usare

tutto sommato, tutto funziona come previsto.... ma non mi piace, come ho scritto sopra è ingombrante e superfluo

 
Dmitry Fedoseev:

E se non usate le classi, vi stancherete di scrivere costantemente qualcosa come SymbolInfoDouble(_Symbol,SYMBOL_BID). Questo balla ogni volta ...

Si potrebbero fare wrapper più convenienti e concisi per queste funzioni, pur mantenendole in stile procedurale. Soprattutto tenendo conto del fatto che nelle ultime build hanno finalmente aggiunto il namespace, tutto è fantastico. Prima bisognava implementarle come metodi statici, ma ora è tutto molto più facile:

namespace SymbolInfo
{
  double Bid(string symbol) { return SymbolInfoDouble(symbol, SYMBOL_BID); }
  double Ask(string symbol) { return SymbolInfoDouble(symbol, SYMBOL_ASK); }
};
 
Alexey Navoykov:

Si possono fare wrapper più convenienti e concisi per queste funzioni, pur rimanendo all'interno dello stile procedurale. Specialmente da quando hanno finalmente aggiunto lo spazio dei nomi nelle ultime build, è fantastico. Prima bisognava implementarli come metodi statici, ma ora tutto è diventato molto più semplice:

È davvero importante rimanere nei limiti? Se è importante rimanere nei limiti, si possono scrivere delle funzioni.

 
Igor Makanu:

beh, non molto, direi un bel po' di azioni per impostare un ordine, ecco la mia visione per una classe che sa come aprire/chiudere/impostare lo stoploss/ed emettere ulteriormente lo stato dell'ordine

e notare l'uso su un simbolo - specialmente una classe statica da usare

tutto sommato, tutto funziona come previsto.... ma non mi piace, come ho scritto sopra è ingombrante e superfluo

Sì, ecco un'altra domanda che continua a sorgere e che non ha una risposta univoca. Quando hai bisogno di ereditare la tua classe - cosa è meglio fare, ereditarla o scrivere una nuova versione estesa della tua classe.

 
Alexey Navoykov:

È possibile fare wrapper più convenienti e concisi per queste funzioni, pur rimanendo all'interno dello stile procedurale. Specialmente da quando hanno finalmente aggiunto il namespace nelle ultime build, è fantastico. Prima, dovevi implementarli come metodi statici, ora le cose sono molto più semplici:

Non hai una notazione sintetica, se non ci sono controlli, è più facile scrivere così com'è:

#define  Ask SymbolInfoDouble(_Symbol,SYMBOL_ASK)
#define  Bid SymbolInfoDouble(_Symbol,SYMBOL_BID)

void OnStart()
  {
   Print("Ask = ",Ask);
   Print("Bid = ",Bid);
  }
 
Igor Makanu:

e notate che per essere usato su un singolo carattere - in particolare una classe statica usata

Cosa ti impedisce di passare il nome del simbolo al costruttore, rendendo la classe flessibile e versatile? Non consideri la possibilità del trading di portafoglio come una questione di principio?
 
Igor Makanu:

La tua voce non è succinta, se non ci sono controlli, è più facile scrivere così com'è:

Ci sono molte funzioni come SymbolInfoDouble. È una seccatura trovare dei nomi brevi per tutti loro, ma assemblandoli in classi, non ci si deve preoccupare dell'unicità dei nomi.

 

Ho il seguente circuito dove non ho avuto problemi.

  1. Scrivo TC solo per Tester. Nessun log, gestori di errori o altre stronzate. Il codice è molto conciso, comprensibile e suscettibile di revisioni, se fatto tramite OOP (ma non fondamentale). Ho già postato l'esempio in KB. Il bonus è l'ottimizzazione veloce.
  2. La cosa principale è che dovrebbe essere disponibile per il tester e in blocchi indipendenti. La generazione di segnali di trading - un blocco. Trading di segnali - un altro blocco.
  3. Il trasferimento al conto reale è sempre fatto in diverse mosse una e una sola. Il TS è inserito in un ambiente virtuale senza alcun cambiamento di codice. Diversi TS possono essere messi in un ambiente o ogni TS nel proprio ambiente, allora l'OOP diventa particolarmente conveniente. Poi prendiamo una fotocopiatrice (il mercato ne è pieno, quindi la gente è brava nella logica delle fotocopiatrici), che semplicemente copia le offerte/ordini dall'ambiente virtuale a quello reale.
  4. Con questo schema, scrivere TS è facile e veloce. Il trasferimento al reale (che è raro in effetti) è sempre fatto in modo uniforme, rapido e chiaro.
 
Igor Makanu:

non hai una voce concisa, se non ci sono controlli, è più facile scrivere così com'è:

Non è così che si fa. Hai bisogno almeno di chiamare sia Bid() che Ask(). La tua voce sembra solo una variabile, dando l'impressione che il suo valore sia invariato, quando in realtà non lo è.
 
Alexey Navoykov:
Cosa vi impedisce di passare il nome del simbolo al costruttore, rendendo la classe flessibile e versatile? Fondamentalmente non considerate la possibilità del trading di portafoglio?

Ciò che ostacola questo è che la maggior parte degli EA di un solo carattere sono scritti, e passare un simbolo sarebbe un'azione non necessaria (ed estenuante)) nella maggior parte dei casi. Un'altra cosa è fare in modo che il simbolo del grafico sia selezionato automaticamente per impostazione predefinita, e se necessario, si può sovrascrivere il simbolo per un po'. Ma ancora una volta la domanda sorge, che cosa è meglio - usare un'istanza della classe e sovrascrivere il simbolo come necessario, o creare un'istanza separata per ogni simbolo.

Motivazione: