CopyTicks」のテスト - ページ 18

 
fxsaber:
リボン(COPY_TICKS_TRADE - time_msc、last、volume、flags)だけが必要な場合、このソリューションは完全に適しており、バグは検出されません。
バグは見つかりませんでしたもう一つのバグが判明

トレーディング、自動売買システム、トレーディング戦略のテストに関するフォーラム

謎の株価指標

fxsaber さん 2016.09.27 18:32

CopyTicksからの入力が0でないとき、すべてのブレーキがかかっているようです。

このモードでは、最後の呼び出しからのティックが要求されても、CopyTicksの実装が非常に曲者であるように思えます。飛ぶように見えるが、飛ばない。

 
今週のベータ版では、ティックとタンブラーの更新に 多くの改良を加えましたので、お待ちください。
 
Renat Fatkhullin:
今週のベータ版では、ティックとタンブラーのアップデートに多くの改良を加えましたので、お待ちください。
1432 - 多くのバグを解決しました。ありがとうございました。
 
fxsaber:
1432 - 多くのバグを解決しました。ありがとうございました。

しかし、すべてではありません。

追加した履歴を実際の履歴と比較すると、COPY_TICKS_ALLモードでは不一致があります(TRADEとINFOは問題ありません)。電子ブック

#include <TypeToBytes.mqh> // https://www.mql5.com/ru/code/16280

string GetTickFlag( uint tickflag )
{
  string flag = "";

#define  TICKFLAG_MACRO(A) flag += ((bool)(tickflag & TICK_FLAG_##A)) ? " TICK_FLAG_" + #A : "";
  TICKFLAG_MACRO(BID)
  TICKFLAG_MACRO(ASK)
  TICKFLAG_MACRO(LAST)
  TICKFLAG_MACRO(VOLUME)
  TICKFLAG_MACRO(BUY)
  TICKFLAG_MACRO(SELL)
#undef  TICKFLAG_MACRO

  if (flag == "")
    flag = " FLAG_UNKNOWN (" + (string)tickflag + ")";
     
  return(flag);
}

#define  TOSTRING(A) " " + #A + " = " + (string)Tick.A

string TickToString( const MqlTick &Tick )
{
  return(TOSTRING(time) + "." + (string)IntegerToString(Tick.time_msc %1000, 3, '0') +
         TOSTRING(bid) + TOSTRING(ask) + TOSTRING(last)+ TOSTRING(volume) + GetTickFlag(Tick.flags));
}

// Дописывает свежие тики после предыдущего запуска
int AddFreshTicks( MqlTick &Ticks[], const string Symb = NULL, const uint flags = COPY_TICKS_ALL )
{
  int Res = 0;
  const int Amount = ArraySize(Ticks);
  
  MqlTick NewTicks[];  
  const int NewAmount = (Amount == 0) ? CopyTicks((Symb == NULL)? Symbol() : Symb, NewTicks, flags, (ulong)(TimeCurrent() - 100) * 1000) :
                                        CopyTicks((Symb == NULL)? Symbol() : Symb, NewTicks, flags, Ticks[Amount - 1].time_msc);
  
  if (NewAmount > 0)
  {
    if (Amount > 0)
    {
      // Взяли крайнее время из предыдущей истории
      const long LastTime = Ticks[Amount - 1].time_msc;
      
      int Count = 1;
      
      // Находим (Count) в предыдушей истории количество тиков со временем LastTime
      for (int i = Amount - 2; i >= 0; i--)
      {
        if (Ticks[i].time_msc < LastTime)
          break;
          
        Count++;
      }

      if ((Count < Amount) && (Count < NewAmount))      
        Res = ArrayCopy(Ticks, NewTicks, Amount, Count);
    }
    else
      Res = ArrayCopy(Ticks, NewTicks);
  }
  
  return(Res);
}

#define  TOSTRING2(A) #A + " = " + (string)(A) + " "

template <typename T>
bool ArrayEqual( const T &Array1[], const T &Array2[] )
{
  const int Amount = MathMin(ArraySize(Array1), ArraySize(Array2));
  bool Res = (Amount > 0);

  if (Res)
    for (int i = 0; i < Amount; i++)
      if (_R(Array1[i]) != Array2[i]) // https://www.mql5.com/ru/code/16280
      {
        Print(TOSTRING2(i) + TOSTRING2(ArraySize(Array1)) +TOSTRING2(ArraySize(Array2)));
        Print(TOSTRING2(TickToString(Array1[i])) + "\n" + TOSTRING2(TickToString(Array2[i])) + "\n");
        
        Res = false;

        break;
      }

  return(Res);
}

void OnTick( void )
{
 static MqlTick PrevTicks[];
  
  // Дописываем свежие тики после предыдущего вызова
  AddFreshTicks(PrevTicks, _Symbol, COPY_TICKS_ALL);
  
  MqlTick Ticks[];
  
  if (ArraySize(PrevTicks) > 0)
  {
    // Взяли историю тиков
    Print(CopyTicks(_Symbol, Ticks, COPY_TICKS_ALL, PrevTicks[0].time_msc, 100000));
    
    // Проверка на совпадение собираемой истории с самой историей
    Print(ArrayEqual(Ticks, PrevTicks) ? "Equal" : "Not Equal");
  }
}

結果

2016.09.29 10:36:23.722 Test10 (Si-12.16,M1)    Not Equal
2016.09.29 10:36:23.722 Test10 (Si-12.16,M1)    
2016.09.29 10:36:23.722 Test10 (Si-12.16,M1)    TickToString(Array2[i]) =  time = 2016.09.29 10:36:20.547 bid = 64353.0 ask = 64354.0 last = 64353.0 volume = 4 TICK_FLAG_BID 
2016.09.29 10:36:23.722 Test10 (Si-12.16,M1)    TickToString(Array1[i]) =  time = 2016.09.29 10:36:20.546 bid = 64353.0 ask = 64354.0 last = 64353.0 volume = 1 TICK_FLAG_LAST TICK_FLAG_VOLUME TICK_FLAG_SELL 
2016.09.29 10:36:23.722 Test10 (Si-12.16,M1)    i = 57 ArraySize(Array1) = 59 ArraySize(Array2) = 58 
2016.09.29 10:36:23.722 Test10 (Si-12.16,M1)    59
 
fxsaber:

しかし、すべてではありません。

追加した履歴を実際の履歴と比較すると、COPY_TICKS_ALLモードでは不一致があります(TRADEとINFOは問題ありません)。電子ブック

結果

上記のコードをログに記録し、理由が判明しました。CopyTicks (from > 0) が最も新しいものまでのティックを受け取る場合、いくつかのティックを見逃す可能性があります。

from = 2016.09.29 11:05:55.564で要求されたティックです。返信で3ティック獲得

2016.09.29 11:05:58.724 Test10 (Si-12.16,M1)    2:  time = 2016.09.29 11:05:55.580 bid = 64380.0 ask = 64382.0 last = 64381.0 volume = 4 TICK_FLAG_BID TICK_FLAG_ASK
2016.09.29 11:05:58.724 Test10 (Si-12.16,M1)    1:  time = 2016.09.29 11:05:55.576 bid = 64379.0 ask = 64381.0 last = 64381.0 volume = 4 TICK_FLAG_LAST TICK_FLAG_VOLUME TICK_FLAG_BUY
2016.09.29 11:05:58.724 Test10 (Si-12.16,M1)    0:  time = 2016.09.29 11:05:55.564 bid = 64379.0 ask = 64381.0 last = 64380.0 volume = 1 TICK_FLAG_BID TICK_FLAG_ASK

しばらくして、遠くからティック履歴を 要求したところ、以前はCopyTicksが見逃していたティックが表示されました。

2016.09.29 11:05:58.732 Test10 (Si-12.16,M1)    time = 2016.09.29 11:05:55.579 bid = 64380.0 ask = 64382.0 last = 64381.0 volume = 16 TICK_FLAG_LAST TICK_FLAG_VOLUME TICK_FLAG_BUY 

こんな虫がいたのか!?

tickデータベースへの書き込みと読み込みが並行して行われるため、何らかのコンフリクトが発生しているようです。

 
もう一つのバグ、すべてのモードで COPY_TICKS_* になりました。

トレーディング、自動売買システム、トレーディング戦略のテストに関するフォーラム

謎の株価指標

fxsaber さん 2016.09.30 15:09

インジケーターの発散を引き起こすバグの1つを特定することができた。またCopyTicksの話です。

ダニの歴史を 部分的に集めても、本当の歴史と一致しない場合があることがわかった。Expert Advisorに表示されます。

#include <TypeToBytes.mqh> // https://www.mql5.com/ru/code/16280

long LastTime = 0; // time_msc-время последнего тика (самого свежего), полученного из истории
int Count = 0;     // Количество тиков в последенем запросе, у которых time_msc == LastTime

// Возвращает следующие тики (после предыдущего вызова)
int GetFreshTicks( MqlTick &Ticks[], const uint flags = COPY_TICKS_TRADE, const uint count = 100000 )
{
  int Res = 0;

  MqlTick NewTicks[];
  const int NewAmount = CopyTicks(Symbol(), NewTicks, flags, LastTime, count);

  if ((NewAmount > 0) && (Count < NewAmount))
  {
    Res = ArrayCopy(Ticks, NewTicks, 0, Count);

    // Взяли крайнее время из текущей истории
    LastTime = Ticks[Res - 1].time_msc;
    Count = 1;

    // Находим (Count) в текущей истории количество тиков со временем LastTime
    for (int i = Res - 2; i >= 0; i--)
    {
      if (Ticks[i].time_msc < LastTime)
        break;

      Count++;
    }
  }
  
  return(ArrayResize(Ticks, Res));
}

// Сравнение двух массивов
template <typename T>
bool ArrayEqual( const T &Array1[], const T &Array2[] )
{
  const int Amount = MathMin(ArraySize(Array1), ArraySize(Array2));
  bool Res = (Amount > 0);

  if (Res)
    for (int i = 0; i < Amount; i++)
      if (_R(Array1[i]) != Array2[i]) // https://www.mql5.com/ru/code/16280
      {
        Res = false;
        
        ExpertRemove();

        break;
      }

  return(Res);
}

void OnTick()
{
  // возьмем тики с начала утренней сессии
  Count = 0;
  LastTime = (TimeCurrent() - (TimeCurrent() % (24 * 3600))) * 1000;
  
  MqlTick Ticks[];    // История, собранная по частям
  MqlTick NewTicks[]; // массив для следующей части тиков
  
  // Собираем историю по частям  
  while (GetFreshTicks(NewTicks, COPY_TICKS_TRADE, 100000) > 0)
    ArrayCopy(Ticks, NewTicks, ArraySize(Ticks));
    
  if (ArraySize(Ticks) > 0)    
  {
    // Взяли ВСЮ историю тиков
    Print(CopyTicks(_Symbol, NewTicks, COPY_TICKS_TRADE, Ticks[0].time_msc, 10000000)); // 10000000 - большое число, чтобы все выкачать.
    
    // Проверка на совпадение собранной по частям истории с самой историей
    Print(ArrayEqual(NewTicks, Ticks) ? "Equal" : "Not Equal");
  }    
}

結果

2016.09.30 16:02:54.661 Test (Si-12.16,M1)      Not Equal
2016.09.30 16:02:54.661 Test (Si-12.16,M1)      ExpertRemove() function called
2016.09.30 16:02:54.621 Test (Si-12.16,M1)      333740
2016.09.30 16:02:54.121 Test (Si-12.16,M1)      Equal
2016.09.30 16:02:54.071 Test (Si-12.16,M1)      333736
2016.09.30 16:02:53.791 Test (Si-12.16,M1)      Equal
2016.09.30 16:02:53.741 Test (Si-12.16,M1)      333723

このEAでも、弱いバグが見られます。部分的に集められた歴史は、数分間続く部分が欠落している可能性があることがわかりました。ただ、コードという形で簡潔かつ明確に再現することは発明されていない。また、複雑なものを掲載しても、誰も見ないので意味がありません。

一般的に、CopyTicksのバグを打ち消す方法はありません。また、Expert Advisorはリボンモード(COPY_TICKS_TRADE)で動作することに留意してください。そのため、リボンとの連携もできません。


 
fxsaber:
もう一つのバグ、すべてのモードで COPY_TICKS_* になりました。

ある時点から始まるティックと、ある一定数などからのティックの両方を取得してみましたか?

コードを見る限りでは、最後の瞬間からある数字(100000)のようです。そして、ちょうどNダニが出た場合はどうするか。スキップもあるのでしょうか?

さっそくですが、私自身はまだあまりダニの実験をしていないのですが...。

 
Alexey Kozitsyn:

ある時点から始まるティックと、ある一定数などからのティックの両方を取得してみましたか?

コードを見る限りでは、最後の瞬間からある数字(100000)のようです。そして、ちょうどNダニが出た場合はどうするか。スキップもあるのでしょうか?

さっそくですが、私自身はまだあまりダニの実験をしていないのですが...。

試してみました。

今日、彼らはデモのための新しいビルドを約束しています。だから、待つしかないのです。

 
fxsaber:

試してみました。

今日、彼らはデモのために新しいビルドを約束します。だから、待たされるんです。

CopyTicks()が修正されることを期待します。

ところで、CopyTicks()が登場して以来、私は開発者に、他のCopy...()関数と同様にオーバーロード機能を追加してほしいとお願いしてきました。そうすると言われたんです。И...黙

 
Alexey Kozitsyn:

ところで、CopyTicks()が登場して以来、私は開発者に、他のCopy...()関数と同様にオーバーロード機能を追加してほしいとお願いしてきました。そうすると言われたんです。И...黙

独自のオーバーロードを追加することも可能です。