MQL5中的OOP问题 - 页 28

 
Dmitry Fedoseev:

如果你不使用类,你会厌倦不断地写类似SymbolInfoDouble(_Symbol,MODE_BID)的东西。 这样的舞蹈每次都有--括号和下划线都有,你不知道是按下大写字母锁(然后在别的地方不看,打出整个大写的字符串并重新输入)还是一直按着换档器。至少这就是OOP的用武之地。如果至少为所有这些功能做类,那么是的--它们是巨大的。如果你是为自己写的,这不是问题。至于与订单有关的工作,没有那么多经常使用的函数,我们可以简单地把一些函数放到一个库中。但总的来说,还没有找到一个理想的方法。

这是我对可以开仓/平仓/设置止损并随后显示订单状态 的类的设想。

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

并注意到在一个符号上的使用--特别是一个静态类来使用

总而言之,一切按计划进行....。但我不喜欢它,正如我在上面写的那样,它很麻烦,很多余。

 
Dmitry Fedoseev:

而且,如果你不使用类,你会厌倦不断地写类似SymbolInfoDouble(_Symbol,SYMBOL_BID)的东西。 这种舞蹈每次都会...

你可以为这些函数制作更方便、更简洁的封装器,同时保持它们的程序化风格。 特别是考虑到在最近的构建中,他们终于添加了命名空间,一切都很好。 以前你必须把它们作为静态方法来实现,但现在一切都容易多了。

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

你可以为这些函数制作更方便、更简洁的包装,同时仍然保持程序化的风格。 特别是他们终于在最新的构建中加入了命名空间,这真是太好了。 以前,你必须把它们作为静态方法来实现,但现在一切都简单多了。

保持在限制范围内真的很重要吗?如果保持在限制范围内很重要,你可以编写函数。

 
Igor Makanu:

嗯,不多,我想说的是,设置一个订单的动作相当多,以下是我对一个知道如何开仓/平仓/设置止损/并进一步输出订单状态 的类的设想。

并注意到在一个符号上的使用--特别是一个静态类来使用

总而言之,一切按计划进行....。但我不喜欢它,就像我在上面写的那样,它很累赘,而且是多余的。

是的,这里还有一个不断出现的问题,没有一个明确的答案。当你需要继承自己的类时--怎么做比较好,是继承它还是为你的类写一个新的扩展版本。

 
Alexey Navoykov:

有可能为这些函数制作更方便、更简洁的包装,同时仍然保持程序化的风格。 特别是他们终于在最新的构建中添加了命名空间,这很好。 以前,你必须把它们作为静态方法来实现,现在事情就简单多了。

你没有一个简洁的记号,如果没有检查,那就更容易按原样写。

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

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

并注意到,要在单个字符上使用--特别是用于静态类的

是什么阻止了你将符号名称传递给构造函数,使该类灵活多变? 你不考虑组合交易的可能性,这是一个原则问题?
 
Igor Makanu:

你的条目并不简练,如果没有检查,按原样写比较容易。

有很多类似SymbolInfoDouble 的函数。把它们集合成类,你就完全不必担心名字的独特性了。

 

我有以下电路,在那里我没有遇到问题。

  1. 我写TC只是为了Tester。没有日志、错误处理程序或任何其他废话。如果通过OOP(但不是基本的)来完成的话,代码是非常简洁的,可以理解的,并且可以进行修改。我已经把这个例子贴在KB上了。奖金是快速优化
  2. 最主要的是,它应该供测试者使用,并在独立的区块中。交易信号的产生--一个街区。信号交易--另一个街区。
  3. 向真实账户的转账总是在几个相同的动作中完成。TS被放置在一个虚拟环境中,没有任何代码变化。几个TS可以放在一个环境中,或者每个TS放在自己的环境中,那么OOP就变得特别方便。然后我们用一台复印机(市场上到处都是复印机,所以人们很擅长复印机的逻辑),它只是把交易/订单从虚拟环境复制到真实环境。
  4. 有了这个方案,编写TS就变得快速而简单。转移到真实(事实上很少)总是以统一、快速和清晰的方式进行。
 
Igor Makanu:

你没有一个简明的条目,如果没有检查,按原样写比较容易。

不是这样做的。你至少需要同时调用Bid()和Ask()。 你的条目看起来只是一个变量,给人的感觉是它的值没有变化,而实际上它不是。
 
Alexey Navoykov:
是什么阻止了你将符号的名称传递给构造函数,使该类灵活多变? 你从根本上没有考虑到组合交易的可能性吗?

阻碍这一点的是,大多数情况下都是写一个字符的EA,在大多数情况下,传递一个符号将是一个不必要的(而且很累))的动作。另一件事是使图表符号在默认情况下被自动选择,如果有必要,你可以暂时覆盖该符号。但问题又来了,哪种方式更好--使用一个类的实例并根据需要覆盖符号,还是为每个符号创建一个单独的实例。