新人对MQL4和MQL5的任何问题,对算法和代码的帮助和讨论 - 页 522

 
PolarSeaman:

好一个转折!))))。

订单1(从#不,到#2)-->订单2(从#1,到#3)-->订单3(从#2,到#不)。

从这里你可以找到整个链条。

我们看一下开放的评论,如果有从#XXX,这意味着它以前是部分关闭的 - 从评论中寻找票据XXX,并在历史中寻找它。看看那里的评论--如果有来自#YYY--这意味着它早些时候也被部分关闭了--从评论中寻找票据YYY并在历史中搜索它。看看评论--如果有来自#ZZZZ--这意味着它在早些时候也被部分关闭--重复搜索。如果没有from#...,那么它就是整个链条的第一个。

 
Artyom Trishkin:

订单1(从#不,到#2)-->订单2(从#1,到#3)-->订单3(从#2,到#不)。

从这里你可以找到整个链条。

我们看一下开放的评论,如果有从#XXX,这意味着它以前是部分关闭的--从评论中寻找票据XXX,并在历史中寻找它。看看那里的评论 - 如果有从#YYY - 这意味着它在早些时候也被部分关闭了 - 从评论中寻找票据YYY并在历史中搜索它。看一下评论--如果有来自#ZZZZ--这意味着它在早些时候也被部分关闭了--重复搜索。如果没有from#...,那么它就是整个链条的第一个。

谢谢你,可能有一个相反方向的订单,我也会砍掉。我怕被搞糊涂。我认为使用某个日期的Profit订单会更容易,当然,如果我们能够找到开仓的 时间,因为部分平仓时,日期会改变。

 
Artyom Trishkin:

订单1(从#不,到#2)-->订单2(从#1,到#3)-->订单3(从#2,到#不)。

从这里你可以找到整个链条。

观察开放的评论,如果有从#XXX,这意味着它早些时候已经部分关闭 - 从评论中寻找票据XXX,并在历史中寻找它。查看那里的评论--如果有从#YYY--那么它早些时候也是部分关闭的--从评论中查看票据YYY,并在历史中寻找它。看看评论--如果有来自#ZZZZ--这意味着它在早些时候也被部分关闭--重复搜索。如果没有from#...,那么它就是整个链条的第一个。

Artyom你知道,情况并非总是如此。而为了不追踪一个链条,不对终端进行三次询问--历史都是在自己的数组和结构中驱动。它与维护你自己的数据库没有什么不同,只是多了一些步骤

终端和它的API是最低级别的。而为了实现机器人的逻辑,用它的术语(贸易、连锁、集团、交易--每个人的叫法都不一样)做会计是合乎逻辑的。只是理智的做法是将其分开,而不是每次打喷嚏(打勾/打条)都试图恢复它。

 
Maxim Kuznetsov:

你知道情况并非总是如此,阿尔乔姆。因此,你在追踪链的时候不必三次询问终端--故事仍然被驱动到它自己的数组和结构中。这与维护你自己的数据库没有什么不同,只是多了一些步骤

终端和它的API是最低级别的。而对于机器人逻辑的实现,按其术语记账是合乎逻辑的(贸易、连锁、集团、交易--每个人的叫法不同)。只是理智的做法是将其分开,而不是在每次打喷嚏(打勾/打条)时都试图重新构建它。

我已经做了很长时间了--我不是每次都读历史--但它总是最新的,而且我可以很容易、非常迅速地在那里找到我需要的一切。但要建议别人做同样的事,我至少需要几篇文章。于是我写下了寻找整个链条的逻辑。

 
PolarSeaman:

谢谢你,可能有一个相反方向的订单,我也会把它粉碎。我怕被搞糊涂。我认为使用盈利功能从某个日期开始平仓会更容易,当然,如果你能找到开仓的 时间,因为在部分平仓中,日期会发生变化。

要搜索一个链条,只需知道订单的票据,你想知道的整个链条--将票据作为参数传给搜索函数,输出--一个填充的数组或结构数组,包含整个链条的每个订单的所有数据。

 
Artyom Trishkin:

一个充满的数组或一个结构数组,包含了整个链条中每个订单的所有数据。

我甚至不知道你刚才说的大概是什么。

至少给我看一个应该如何的例子。

 
PolarSeaman:

我甚至不知道你刚才说的大概是什么。

至少给我一个例子,说明应该如何。

我以下列方式解决这个问题:我通过历史寻找链条。那么,为了让历史毫不含糊,我使用了两种变体。

  1. 如果没有DLL,那么在程序描述中的24号黑体)))),我指定账户历史必须始终完整加载(终端窗口的账户历史标签,上下文菜单- 所有历史)。
  2. 有了DLL - Expert Advisor,无论用户的任何行为,"账户历史 "标签都会保持最新。

如果当前订单不是主要订单,则有函数来确定父订单。

int GetSignOfPartialOrCloseByClose()
{
   string comment = OrderComment();
   if (comment == "")
      return 0;
   
   // Ордер образовался вследствии частичного закрытия
   int fromStart = StringFind(comment, "from #");
   if (fromStart >= 0)
      return GetTicketByPartialClose(comment, fromStart, OrderType(), OrderOpenTime());
   
   // Ордер образовался вследствии встречного закрытия
   if (StringFind(comment, "partial close") >= 0)
   {
      datetime openTime = OrderOpenTime();
      int type = OrderType();
      for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
      {
         if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
            continue;
            
         if (OrderOpenTime() != openTime)
            continue;
            
         if (OrderType() != type)
            continue;
            
         if (StringFind(OrderComment(), "partial close") < 0)
            continue;
            
         return OrderTicket();
      }
   }
   
   return 0;
}


int GetTicketByPartialClose(string comment, int fromStart, int orderType, datetime openTime)
{
   string sTicket = StringSubstr(comment, fromStart + 6);
   int iTicket = (int)StringToInteger(sTicket);
   int type = OrderType();
   if (!OrderSelect(iTicket, SELECT_BY_TICKET))
      return 0;
      
   if (OrderType() == type)                                                                        // Дочерний ордер указывает на родителя - уходим
      return iTicket;
      
   // Дочерний ордер указывает на противоположный ордер. Необходимо искать родительский
   for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
   {
      if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
         continue;
         
      if (OrderType() != orderType || OrderOpenTime() != openTime)
         continue;
         
      int iFind = StringFind(OrderComment(), "close hedge by #");
      if (iFind < 0)
         continue;
         
      sTicket = StringSubstr(OrderComment(), iFind + 16);
      int iNewTicket = (int)StringToInteger(sTicket);
      if (iNewTicket != iTicket)
         continue;
         
      return OrderTicket();
   }
   
   return 0;
}

易于使用。

   for (int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if (!OrderSelect(i, SELECT_BY_POS))
         continue;

      ....         

      int nFromTicket = GetSignOfPartialOrCloseByClose();                // Обязательно последней строкой в теле цикла, т. к. может измениться текущий выбранный ордер
   }


 
Ihor Herasko:

这里最粗暴的错误是在OrderDelete()参数中指定数值100而不是ticket。

下一个错误不是那么粗糙,但它与检查止损的计算值而不是其实际值有关。

订单类型也不被检查。如果我们选择了一个市场订单,怎么办?如何删除它?没有检查过订单符号。

考虑到这些错误,我们得到的代码 在价格达到止损时删除挂单

另外,在你的代码中,止损是在订单打开后立即检查的。似乎在打开一个挂单后,这段代码不再被执行。也就是说,你需要将执行分支分开。一个人负责设置顺序,第二个人负责其伴奏。

谢谢你的详细答复

按照你的建议,我已经分离了分支,一切正常。

然后我遇到了同时打开10-15个挂单的问题,我通过在你的代码后添加它解决了这个问题。

if (OrdersTotal ()>0) return;

我相信有一个更好的方法。

通过你的代码,请你解释一下1; i >=0; --i是什么意思?

for (int i = OrdersTotal() - 1; i >= 0; --i)
 

请帮助我了解如何写一个指标。我画了这样一个假人,如何使指标的长度 在当前买入价之上的大小 点上画出来,从指标放在图表上的那一刻 开始?也许错误在于我把这个数组移到了错误的方向?

我知道它是 "规范的",没有任何prev_calculated等,但我需要它像这样


#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
//---- plot 
#property indicator_label1  "myInd"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

double buff[], Bid;
input int lenght = 50, size = 5;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

   ArrayResize(buff, 50);
   ArrayInitialize(buff, 0);
   SetIndexBuffer(0, buff, INDICATOR_DATA);
   //--- установим метку для отображения в DataWindow
   PlotIndexSetString(0,PLOT_LABEL,"myInd");   
//--- установим имя для показа в отдельном подокне и во всплывающей подсказке
   IndicatorSetString(INDICATOR_SHORTNAME,"myInd");
//--- укажем точность отображения значений индикатора
   IndicatorSetInteger(INDICATOR_DIGITS, _Point);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   for(int i = lenght-1; i>0; i--){
      buff[i] = buff[i-1];
   }
   buff[0] = Bid+size;
   


   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
Roman Sharanov:

请帮助我了解如何写一个指标。我画了这样一个假人,如何使指标的长度 在当前买入价之上的大小 点上画出来,从指标放在图表上的那一刻 开始?也许错误在于我把这个数组移到了错误的方向?

我知道它是 "正统 "的,没有prev_calculated之类的东西。


有一个官方文件--它和你的一模一样。

1.你应该对你在OnCalculate中使用的所有数组进行序列化设置。

2.在进入循环之前,把buff[length]=Bid+size;--你会得到你想要的大约结果。一条弯曲的线,最后是一个Bid+size的 "面罩"。

3.注意阵列的边界。当然Rates_total很难<长度,但你不能出错 :-)

4.
buff[i] = buff[i+1]; // если тайм-серия (а вы подразумеваете их) то +
原因: