初心者の方からの質問 MQL5 MT5 MetaTrader 5 - ページ 575

 

ここでは、私の変形版として、繰り返し探索問題の解法を紹介します。

//+------------------------------------------------------------------+
//|                                              FindRetryPrices.mq5 |
//|                                 Copyright 2016, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#property version   "1.00"
#include <Dictionary.mqh>

input int RatesPeriod = 10;                        // Период за который ищутся повторения
input int RoundPoints = 10;                        // Загрубление цены в прайсстепах
class CBar : public CObject
{
private:
   MqlRates m_bar;
public:
            CBar(MqlRates& bar){m_bar = bar;}
   datetime Date(){return m_bar.time;}
   double Open(){return m_bar.open;}
   double High(){return m_bar.high;}
   double Low(){return m_bar.low;}
   double Close(){return m_bar.close;}
};
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   // Нахождение повторяющихся баров
   MqlRates rates[];
   int total = CopyRates(Symbol(), Period(), 0, RoundPoints, rates);
   CDictionary* BarsCollections = new CDictionary(total);
   for(int i = 0; i < total; i++)
   {
      double price = PriceToLevel(rates[i].high);
      CBar* bar = new CBar(rates[i]);
      if(!BarsCollections.ContainsKey(price))
         BarsCollections.AddObject(price, new CList());
      CList* equal_bars = BarsCollections.GetObjectByKey(price);
      equal_bars.Add(bar);
   }
   // Вывод повторов
   FOREACH_DICT(BarsCollections)
   {
      CList* list = node;
      if(list.Total() < 2)continue;
      string retry_bars = "";
      for(CBar* bar = list.GetFirstNode(); bar != NULL; bar = list.GetNextNode())
         retry_bars += " [" + TimeToString(bar.Date()) + ", " + DoubleToString(bar.High(), Digits()) + "]";
      printf("Обнаружено совпадение баров:" + retry_bars);
   }
   delete BarsCollections;
}
//+------------------------------------------------------------------+
//| Округляет цену в соответствии с параметром RoundPoints           |
//+------------------------------------------------------------------+
double PriceToLevel(double price)
{
   double price_step = RoundPoints*Point();
   double mn = MathFloor(price/price_step);
   return mn * price_step;
}

//+------------------------------------------------------------------+

スクリプトを動作させるためには、DictionaryファイルをMQL5 Indecludeにコピーする必要があります。

検索は、黄色で示したワンパスforループで行われる。結果として得られるリストには繰り返しが含まれない(AがBを繰り返し、BがAを繰り返す場合、2つのセット{A, B}と{B, A}ではなく、1つのセット{A, B}が出力される)。).

このスクリプトの出力は次のようなものであった。

2016.05.10 11:09:06.730 FindRetryPrices (Si Splice,M1)  Обнаружено совпадение баров: [2016.05.10 11:02, 67149] [2016.05.10 11:03, 67147] [2016.05.10 11:04, 67144]
2016.05.10 11:09:06.730 FindRetryPrices (Si Splice,M1)  Обнаружено совпадение баров: [2016.05.10 11:01, 67160] [2016.05.10 11:05, 67161]
2016.05.10 11:09:06.730 FindRetryPrices (Si Splice,M1)  Обнаружено совпадение баров: [2016.05.10 11:00, 67132] [2016.05.10 11:06, 67139]
ファイル:
Dictionary.mqh  18 kb
 
Artyom Trishkin:

参考文献より

ワシリー・ソコロフ

ここで、私なりの繰り返し探索問題の解決策を紹介します。


皆さん、本当にありがとうございました!!!今日中に全部把握するようにします。ただExpert Advisorにコードをコピーするだけでなく、なぜこのように書かれているのかを理解することが重要なので、もっと質問してみようかな。
 

標準RSIを計算する関数を見つけるのを助けてください、要件は簡単です。

1.指定したバーでのRSI値を返す

2.要求された(望ましい)バーだけ(必要なら)インデックスを計算する。

3.指定されたTFで計算できるようになること

4.インジケータより速く、ポイント2を犠牲にして働く

Expert Advisorにこの機能を組み込みたいのですが、どなたか準備されている方がいらっしゃいましたら、教えてください。

ごく一般的な指標であり、不思議なことではないので質問させていただきました。

 
-Aleks-:

標準RSIを計算する関数を見つけるのを助けてください、要件は簡単です。

1.指定したバーでのRSI値を返す

2.要求された(望ましい)バーだけ(必要なら)インデックスを計算する。

3.指定されたTFで計算できるようになること

4.インジケータより速く、ポイント2を犠牲にして働く

Expert Advisorにこの機能を組み込みたいのですが、どなたか準備されている方がいらっしゃいましたら、教えてください。

ごく一般的な指標であり、不思議なことではないので質問させていただきました。

なぜ標準のiRSIが気に入らないのですか?秘密が足りない?
 
Vasiliy Sokolov:
標準のiRSIの何が問題なのでしょうか?秘密が足りない?
関数に必要な私の変更があるのですが...。
 
-Aleks-:
関数に必要な私の変更があるのですが...。

既成のものを使って、自分の要求に合わせて修正する。

//+------------------------------------------------------------------+
//|                                                          RSI.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "2009, MetaQuotes Software Corp."
#property link        "http://www.mql5.com"
#property description "Relative Strength Index"
//--- indicator settings
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 100
#property  indicator_level1 30
#property  indicator_level2 70
#property indicator_buffers 3
#property indicator_plots   1
#property  indicator_type1   DRAW_LINE
#property  indicator_color1  DodgerBlue
//--- input parameters
input int InpPeriodRSI=14; // Period
//--- indicator buffers
double    ExtRSIBuffer[];
double    ExtPosBuffer[];
double    ExtNegBuffer[];
//--- global variable
int       ExtPeriodRSI;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- check for input
   if(InpPeriodRSI<1)
     {
      ExtPeriodRSI=12;
      Print("Incorrect value for input variable InpPeriodRSI =",InpPeriodRSI,
            "Indicator will use value =",ExtPeriodRSI,"for calculations.");
     }
   else ExtPeriodRSI=InpPeriodRSI;
//--- indicator buffers mapping
   SetIndexBuffer(0,ExtRSIBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,ExtPosBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,ExtNegBuffer,INDICATOR_CALCULATIONS);
//--- set accuracy
   IndicatorSetInteger(INDICATOR_DIGITS,2);
//--- sets first bar from what index will be drawn
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPeriodRSI);
//--- name for DataWindow and indicator subwindow label
   IndicatorSetString(INDICATOR_SHORTNAME,"RSI("+string(ExtPeriodRSI)+")");
//--- initialization done
  }
//+------------------------------------------------------------------+
//| Relative Strength Index                                          |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
   int    i;
   double diff;
//--- check for rates count
   if(rates_total<=ExtPeriodRSI)
      return(0);
//--- preliminary calculations
   int pos=prev_calculated-1;
   if(pos<=ExtPeriodRSI)
     {
      //--- first RSIPeriod values of the indicator are not calculated
      ExtRSIBuffer[0]=0.0;
      ExtPosBuffer[0]=0.0;
      ExtNegBuffer[0]=0.0;
      double SumP=0.0;
      double SumN=0.0;
      for(i=1;i<=ExtPeriodRSI;i++)
        {
         ExtRSIBuffer[i]=0.0;
         ExtPosBuffer[i]=0.0;
         ExtNegBuffer[i]=0.0;
         diff=price[i]-price[i-1];
         SumP+=(diff>0?diff:0);
         SumN+=(diff<0?-diff:0);
        }
      //--- calculate first visible value
      ExtPosBuffer[ExtPeriodRSI]=SumP/ExtPeriodRSI;
      ExtNegBuffer[ExtPeriodRSI]=SumN/ExtPeriodRSI;
      if(ExtNegBuffer[ExtPeriodRSI]!=0.0)
         ExtRSIBuffer[ExtPeriodRSI]=100.0-(100.0/(1.0+ExtPosBuffer[ExtPeriodRSI]/ExtNegBuffer[ExtPeriodRSI]));
      else
        {
         if(ExtPosBuffer[ExtPeriodRSI]!=0.0)
            ExtRSIBuffer[ExtPeriodRSI]=100.0;
         else
            ExtRSIBuffer[ExtPeriodRSI]=50.0;
        }
      //--- prepare the position value for main calculation
      pos=ExtPeriodRSI+1;
     }
//--- the main loop of calculations
   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      diff=price[i]-price[i-1];
      ExtPosBuffer[i]=(ExtPosBuffer[i-1]*(ExtPeriodRSI-1)+(diff>0.0?diff:0.0))/ExtPeriodRSI;
      ExtNegBuffer[i]=(ExtNegBuffer[i-1]*(ExtPeriodRSI-1)+(diff<0.0?-diff:0.0))/ExtPeriodRSI;
      if(ExtNegBuffer[i]!=0.0)
         ExtRSIBuffer[i]=100.0-100.0/(1+ExtPosBuffer[i]/ExtNegBuffer[i]);
      else
        {
         if(ExtPosBuffer[i]!=0.0)
            ExtRSIBuffer[i]=100.0;
         else
            ExtRSIBuffer[i]=50.0;
        }
     }
//--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
Vasiliy Sokolov:

既成のものを使って、自分の要求に合わせて修正する。

コードにインジケーターがあるのは知っているのですが・・・。問題は、誰がすでに変えているかもしれないということだった...。
 
Vasiliy Sokolov:

ここでは、繰り返しの検索という問題を解決するための私のバリエーションを紹介します。

Vasilyさん、#include <Dictionary.mqh>を 開くと、EA本体と同じように開く んですね。このようになるはずです。それとも、中に他のコードがあるのでしょうか?

なぜなら、私が見たコードでは、どのように繰り返しを検索しているのかが明確でないからです((

 
Artyom Trishkin:

// строку int searchPeriod=(Search_Period<1)?1:Search_Period;
// можно расписать так:

input int Search_Period=10; // Количество копируемых свечей ... эту строку вы видите в настройках
int searchPeriod;           // Сюда будем записывать входной параметр
if(Search_Period<1) searchPeriod=1; // Если во входном параметре ввели ноль или меньше нуля, то параметр будет равен нулю
else searchPeriod=Search_Period;    // иначе примем входной параметр

// соответственно и строку int delta=(Delta<0)?0:Delta;
// можно расписать точно так же

1ではなく、0であるべきです。

このようにint searchPeriod=(Search_Period<1)?0:Search_Period;

で、さらに実行スクリプトで

int copy_bars=(int)fmin(Search_Period,Bars(Symbol(),Period())); // コピーするローソク足の本数

この場合、すでにsearchPeriodという 変数を使うべきでしょう。

------

もうひとつ、この線はどうなっているのでしょうか?構造体の各要素がゼロにリセットされることがわかりました。そして、このデータを書いただけで、さらにそれを使うべきと思われるのであれば、ここで何をゼロにしているのか理解できない。

ZeroMemory(dataCandle); // 構造体のデータをゼロにする。

 
Andrey Koldorkin:

1ではなく、0であるべきです。

このようにint searchPeriod=(Search_Period<1)?0:Search_Period;

で、さらに実行スクリプトで

int copy_bars=(int)fmin(Search_Period,Bars(Symbol(),Period())); // コピーするローソク足の本数

この場合、すでにsearchPeriodという 変数を使うべきでしょう。

------

もうひとつ、この線はどうなっているのでしょうか?構造体の各要素がゼロにリセットされることがわかりました。そして、このデータを書いただけで、さらにそれを使うべきと思われるのであれば、ここで何をゼロにしているのか理解できない。

ZeroMemory(dataCandle); // 構造体内部のデータを消去する.


"こんな感じ "で。int searchPeriod=(Search_Period<1)?0:Search_Period;"

いいえ、そんなことはありません。このように(文字通り)、ユーザーが設定で設定したSearch_Periodが 1より小さい場合は、 searchPeriodは 0に等しくなり、それ以外の場合は、ユーザーが設定で設定したSearch_Periodの 値に等しくなる、ということです。これは正しくありません。ゼロに等しい検索範囲は必要ない。そこで、この範囲がユーザーによって0または0未満(1未満)に設定されている場合、この範囲を最小値-1に等しく設定することにします。


"int copy_bars=(int)fmin(Search_Period,Bars(Symbol(),Period())); // ローソク足の数だけコピーする。
ここで、searchPeriodという 変数をすでに使っているはずです。"

はい、その通りです、タイプミスです。


"もうひとつの質問、この線は何のためにあるのですか?構造体の各要素をゼロにリセットすることがわかりました。そして、このデータを書き込んだだけで、さらにそれを使うべきなのに、なぜ、何をゼロにしているのかが理解できない。ZeroMemory(dataCandle); // 構造体のデータをゼロにする".

これは、構造 体にデータを入れる前に行う。まずゼロにし、次に埋める。見てください。ループの前にゼロにするんです。そして、ループの中で構造体をデータで埋めていく。

理由: