Preguntas sobre POO en MQL5 - página 28

 
Dmitry Fedoseev:

Y si no usas clases, te cansarás de escribir constantemente algo como SymbolInfoDouble(_Symbol,MODE_BID). Siempre bailan los corchetes y los guiones bajos, y no sabes si pulsar el bloqueo de mayúsculas (y luego, en algún lugar sin mirar, escribir toda una cadena en mayúsculas y volver a escribirla) o mantener pulsada la palanca de cambios. Al menos ahí es donde la POO es útil. Si al menos se hacen clases para todas estas funciones, entonces sí - son enormes. Si lo escribes para ti, no hay problema. En cuanto al trabajo con las órdenes, no hay tantas funciones de uso frecuente, podemos simplemente poner algunas funciones en una biblioteca. Pero, en general, aún no se ha encontrado un enfoque ideal.

Esta es mi visión de la clase que puede abrir/cerrar/establecer el stop loss y posteriormente mostrar elestado de la orden

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();};
//________________________________

y nota el uso en un símbolo - especialmente una clase estática para usar

En definitiva, todo funciona como se pretende.... pero no me gusta, como escribí arriba es engorroso y superfluo

 
Dmitry Fedoseev:

Y si no usas clases, te cansarás de escribir constantemente algo como SymbolInfoDouble(_Symbol,SYMBOL_BID). Esto baila cada vez ...

Podrías hacer envoltorios más convenientes y concisos para estas funciones, mientras las mantienes en el estilo procedimental. Especialmente teniendo en cuenta el hecho de que en los últimos builds finalmente agregaron namespace, todo es genial. Antes tenías que implementarlos como métodos estáticos, pero ahora todo es mucho más fácil:

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

Puedes hacer envoltorios más convenientes y concisos para estas funciones, mientras te mantienes dentro del estilo procedimental. Especialmente desde que finalmente agregaron el espacio de nombres en los últimos builds, eso es genial. Antes, tenías que implementarlos como métodos estáticos, pero ahora todo es mucho más simple:

¿Es realmente importante mantenerse dentro de los límites? Si es importante mantenerse dentro de los límites, puede escribir funciones.

 
Igor Makanu:

Bueno, no mucho, yo diría que un montón de acciones para establecer una orden, aquí está mi visión para una clase que sabe cómo abrir / cerrar / establecer stoploss / y más estado de la orden de salida

y nota el uso en un símbolo - especialmente una clase estática para usar

En definitiva, todo funciona como se pretende.... pero no me gusta, como he escrito arriba es engorroso y superfluo

Sí, esta es otra pregunta que sigue surgiendo y que no tiene una respuesta inequívoca. Cuando necesites heredar tu propia clase - qué es mejor hacer, heredarla o escribir una nueva versión extendida de tu clase.

 
Alexey Navoykov:

Es posible hacer envoltorios más convenientes y concisos para estas funciones, sin dejar de estar dentro del estilo procedimental. Especialmente desde que finalmente agregaron el espacio de nombres en las últimas compilaciones, eso es genial. Antes, tenías que implementarlos como métodos estáticos, ahora las cosas son mucho más simples:

No tienes una notación sucinta, si no hay controles, es más fácil escribir tal cual:

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

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

y tenga en cuenta que para ser utilizado en un solo carácter - específicamente una clase estática utilizada

¿Qué le impide pasar el nombre del símbolo al constructor, haciendo que la clase sea flexible y versátil? ¿No considera la posibilidad de negociar la cartera como una cuestión de principios?
 
Igor Makanu:

Tu entrada no es tersa, si no hay controles, es más fácil escribir tal cual:

Hay muchas funciones como SymbolInfoDouble. Es una molestia pensar en nombres cortos para todos ellos. Al reunirlos en clases, no hay que preocuparse en absoluto por la unicidad de los nombres.

 

Tengo el siguiente circuito en el que no he tenido problemas.

  1. Escribo TC sólo para Tester. No hay registros, manejadores de errores o cualquier otra basura. El código es muy conciso, comprensible y susceptible de ser editado, si se hace mediante POO (pero no es fundamental). Ya he publicado el ejemplo en KB. La ventaja es la rápida optimización.
  2. Lo principal es que esté disponible para el probador y en bloques independientes. La generación de señales de trading - un bloque. Comercio de señales: otro bloque.
  3. La transferencia a la cuenta real se realiza siempre en varios movimientos. El ST se coloca en un entorno virtual sin necesidad de cambiar el código. Se pueden colocar varias TS en un entorno o cada TS en su propio entorno, entonces la OOP se vuelve especialmente conveniente. Entonces cogemos una copiadora (el Mercado está lleno de ellas, así que la gente es buena en la lógica de las copiadoras), que simplemente copia las ofertas/órdenes del entorno virtual al real.
  4. Con este esquema, escribir TS es rápido y fácil. El traspaso a real (que es poco frecuente, de hecho) se hace siempre de manera uniforme, rápida y clara.
 
Igor Makanu:

su entrada no es sucinta, si no hay controles, es más fácil escribirla tal cual:

No es así como se hace. Necesitas al menos llamar tanto a Bid() como a Ask(). Tu entrada parece sólo una variable, dando la apariencia de que su valor no cambia, cuando en realidad no es así.
 
Alexey Navoykov:
¿Qué le impide pasar el nombre del símbolo al constructor, haciendo que la clase sea flexible y versátil? ¿No considera fundamentalmente la posibilidad de operar con la cartera?

Lo que dificulta esto es que la mayoría de los EAs son de un solo carácter, y pasar un símbolo sería una acción innecesaria (y agotadora)) en la mayoría de los casos. Otra cosa es hacer que el símbolo del gráfico se seleccione automáticamente por defecto, y si es necesario, se puede anular el símbolo durante un tiempo. Pero de nuevo se plantea la cuestión de qué es mejor: utilizar una instancia de la clase y anular el símbolo según sea necesario, o crear una instancia distinta para cada símbolo.