文章 "交易者生活窍门: 利用 defines (#define) 融合 ForEach" - 页 6

 

您如何想象一篇文章?我从知识库中提取源代码,然后开始在文章中描述为什么我决定在这个地方应用宏,为什么它就是这样的?

KB 中的每项工作都有一个讨论主题。您可以在那里提出有关源代码的问题。

 
fxsaber:

您如何想象一篇文章?我从知识库中提取源代码,然后开始在文章中描述为什么我决定在这个地方应用宏,为什么它完全是这样的?

KB 中的每项工作都有一个讨论主题。您可以在那里提出有关源代码的问题。

例如,在这里我根本没有打空)。

#define  MT4_ORDERFUNCTION(NAME,T,A,B,C)                               \
  static T MT4Order##NAME( void )                                     \
  {                                                                   \
    return(POSITION_ORDER((T)(A), (T)(B), MT4ORDERS::Order.NAME, C)); \
  }

描述一下这些事情也不错!

 
Vitaly Muzichenko:

例如,在这里我完全不掏空)。

最好能描述一下这些东西!

这是一个多行宏,有五个输入参数。看看文本,哪些参数被调用。

它创建了名为 MT4OrderTicket、MT4OrderClosePrice 等相应方法。这些方法的文本 95% 相同,而且数量众多。为了避免大量复制粘贴,造成错误,我们制作了一个宏。所有内容都非常紧凑,一目了然。

此外,该代码强调功能 95% 相同。也就是说,在阅读时,你会立刻意识到这一点。但是,如果你采用经典的编写方式,你只能通过阅读和分析 20 个方法的代码(方法太多了)才能得出这样的结论。而这是一件非常令人头疼的事情。因此,我们将所有 20 个方法都放在一个屏幕上,并强调这些方法几乎是重合的。只有宏的输入参数才会显示出不同之处。您在阅读时只需注意这些不同之处,而不必在意那些花哨的东西。也就是说,代码一次性显示了主要内容--核心,而不是平凡的外壳。

 
Vasiliy Sokolov:

他所做的一切都超越了常规,是应该与公众分享的宝贵知识!

他正在分享。他在 KB 中发表的一些文章和对代码的描述比这里一半的文章信息量都要大。

我也不明白,如果他能现场回答所有问题,为什么还要出一本人工参考书。

如果 Renat 能够改掉每次发表刺耳言论就封禁他的习惯,那就更好了。

 

开发人员能否在编辑器的 "编译 "按钮上增加一个命令 "复制文件,替换宏而不进行编译并打开文件"。尤其是在研究来自 fxsaber 的宏时。

也可以使用右键菜单中的命令。将鼠标放在宏调用上,选择命令,宏替换后得到的代码将复制到缓冲区。

 

一般来说,宏可以这样理解:

1.必须将宏名称与其值分开。首先是 #define,然后是一个空格,之后是这个名称(可以带参数),然后是另一个空格或过渡到新的一行 以及宏的值。

2.我们可以看到代码中是如何调用宏的,它的参数是什么。复制一份宏值,并将参数替换为代码中调用宏时使用的参数。

在代码中调用宏的地方,用第 2 步中得到的参数替换。

大概是这样。

有些事情你需要知道:\ - 表示在新行上继续。 ## - 表示行与行之间的连接。
 
我最常用的宏观

关于交易、自动交易系统和交易策略测试的论坛

mql5 语言的特点、精妙之处和工作技巧

fxsaber, 2017.12.05 11:39 pm.

在调试模式下,无法找出函数或表达式返回的值。

例如

void OnStart()
{
  double Angle = 1;
  double d = MathSin(Angle / 2) * MathSin(Angle * 2);
}

例如,高亮显示的函数返回了什么。


我使用(不仅在调试模式下)这种方法

template <typename T>
T MyPrint( const T Value, const string Str )
{
  static const bool IsDebug = MQLInfoInteger(MQL_DEBUG);

// 如果 (IsDebug)
  {
// DebugBreak(); // 如果你想通过调试手段查看

    Print(Str + " = " + (string)Value);
  }
  
  return(Value);
}

#define _P(A) MyPrint(A, __FUNCSIG__ ", Line = " + (string)__LINE__ + ": " + #A)

void OnStart()
{
  double Angle = 1;
  double d = _P(MathSin(Angle / 2)) * _P(MathSin(Angle * 2));
}


结果

void OnStart(), Line = 21: MathSin(Angle/2) = 0.479425538604203
void OnStart(), Line = 21: MathSin(Angle*2) = 0.9092974268256817

我将其格式化为 mqh。

跨平台脚本示例

#include <MT4Orders.mqh>

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

void OnStart()
{
  // 打开并关闭买入头寸
  if (OrderSelect(OrderSend(_Symbol, OP_BUY, 1, Ask, 100, 0, 0), SELECT_BY_TICKET))
    OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 100);
}


假设我们想知道 OrderClosePrice() 在此代码中的返回值。让我们这样做

OrderClose(OrderTicket(), OrderLots(), _P(OrderClosePrice()), 100);


如果你想知道几乎所有内容,这里就是代码(当你完全不明白自己或别人代码中的问题所在时,就会出现这种情况)。

#include <MT4Orders.mqh>

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

#include <Debug.mqh> //https://c.mql5.com/3/173/Debug.mqh

void OnStart()
{
  // 打开并关闭买入头寸
  if (_P(OrderSelect(_P(OrderSend(_P(_Symbol), _P(OP_BUY), 1, _P(Ask), 100, 0, 0)), _P(SELECT_BY_TICKET))))
    _P(OrderClose(_P(OrderTicket()), _P(OrderLots()), _P(OrderClosePrice()), 100));
}

也就是说,你想看的任何地方的值,我们都把它放到 _P()中。结果

void OnStart(), Line = 10: SELECT_BY_TICKET = 1
void OnStart(), Line = 10: Ask = 1.16688
void OnStart(), Line = 10: OP_BUY = 0
void OnStart(), Line = 10: _Symbol = EURUSD
void OnStart(), Line = 10: OrderSend(_P(_Symbol),_P(OP_BUY),1,_P(Ask),100,0,0) = 293785198
void OnStart(), Line = 10: OrderSelect(_P(OrderSend(_P(_Symbol),_P(OP_BUY),1,_P(Ask),100,0,0)),_P(SELECT_BY_TICKET)) = true
void OnStart(), Line = 11: OrderClosePrice() = 1.16678
void OnStart(), Line = 11: OrderLots() = 1.0
void OnStart(), Line = 11: OrderTicket() = 293785198
void OnStart(), Line = 11: OrderClose(_P(OrderTicket()),_P(OrderLots()),_P(OrderClosePrice()),100) = true


例如,有这样一个表达式

void OnStart()
{
  int a = 137;
  double b = 1.37;
  
  int Num = ((a = (int)(a / b)) << 1) * a; // 19602
}

我们需要快速找出输出 19602 的原因。我们将想要快速找出的部分放入宏中

int Num = _P(_P(((a = _P((int)(_P(a / b)))) << 1)) * _P(a));


我们就能一步步看到计算结果了

void OnStart(), Line = 8: a/b = 99.99999999999999
void OnStart(), Line = 8: (int)(_P(a/b)) = 99
void OnStart(), Line = 8: ((a=_P((int)(_P(a/b))))<<1) = 198
void OnStart(), Line = 8: a = 99
void OnStart(), Line = 8: _P(((a=_P((int)(_P(a/b))))<<1))*_P(a) = 19602


ZY 而不是一篇文章...

 
#define  ForEachSymbol(s,i)  string s=SymbolName(0,true); int os_total=SymbolsTotal(true); for(int i=1;i<os_total;i++,s=SymbolName(i,true))

有一个错误,第一个符号进程的位置索引为 0,下一个符号进程的位置索引为 2。由于缺少 position_index 1,您的循环只执行了 os_total-1 次。

#define  ForEachOrder(ticket,i)    HistorySelect(0,TimeCurrent());  ulong ticket=OrderGetTicket(0); int or_total=OrdersTotal();   for(int i=1;i<or_total;i++,ticket=OrderGetTicket(i))
//+------------------------------------------------------------------+
//| 脚本程序启动功能|
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachOrder(orderticket,index)
     {
      Print(index,": #",orderticket," ",OrderGetString(ORDER_SYMBOL)," ",
            EnumToString((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE)));
     }
/* 输出示例
 1: 13965457 CADJPY ORDER_TYPE_SELL_LIMIT
 2: 14246567 AUDNZD ORDER_TYPE_SELL_LIMIT
*/ 
  }

这个错误与之前的错误相同。

此外,您还混合使用了处理未结订单和历史选择的函数。如果您的目的是处理未结订单,就没有必要使用 HistorySelect()。


顺便说一下,这些错误很好地说明了不使用宏的问题。这很难甚至不可能调试。

The most strongest criticism of using #define is the fact that macro substitutions do not allow for code debugging. I agree with this, although, as fxsaber says, "A reliably fixed patient requires no anesthesia debugged macro requires no debugging".

之后我就不读了,抱歉。

 
也许您可以考虑为 mql4 增加两个定义,OrderCalcProfit() 和 OrderCalcMargin()
 
daengrani #:
也许您考虑为 mql4 增加两个定义,即 OrderCalcProfit() 和 OrderCalcMargin()
不,旧终端已经很久不支持了。