記事"トレーディングにおけるOLAPの適用(その4)。テスターレポートの定量的・視覚的分析"についてのディスカッション

 

新しい記事 トレーディングにおけるOLAPの適用(その4)。テスターレポートの定量的・視覚的分析 はパブリッシュされました:

この記事では、シングルパスや最適化結果に関連するテスターレポートのOLAP分析のための基本的なツールを提供しています。 このツールは標準フォーマットのファイル(tstとopt)を扱うことができ、グラフィカルなインターフェイスも提供します。 最後にMQLのソースコードを添付します。

レベル別の利益の一般的な分布を100刻みで表示するには、X軸に沿った統計から「利益」フィールドを選択し、「カウント」アグリゲータを選択します。

100台単位でのレンジ別利益配分

100台単位でのレンジ別全利益配分

「アイデンティティ」アグリゲータを使用することで、利益を得るためのトレード数の影響を評価することができます。 一般的に、このアグリゲータは、他の多くの依存関係を視覚的に評価することを可能にします。

利益対取引数

利益対取引数

作者: Stanislav Korotky

 
クールだね!試してみないとね。ありがとう。
 

記事のコードを解析しているとき、私にはこのような高度な技術には到底及ばないだろうという思いが常にあった。残念ながら、私の力不足で理解できなかった。


この機能を提示されたツールキットに追加する方法を、例として示す(準備ができたコード)ことを著者にお願いしたい。

取引、自動取引システム、取引戦略のテストに関するフォーラム。

ライブラリ: SingleTesterCache

fxsaber, 2020.01.14 11:42 AM

  uchar Bytes2[];
  
  if (MTTESTER::GetLastTstCache(Bytes2) != -1) // 1回の実行の最後のキャッシュ・レコードを読むことができる場合
  {
    const SINGLETESTERCACHE SingleTesterCache(Bytes2); // それを対応するオブジェクトに打ち込む。

取引、自動取引システム、取引戦略のテストに関するフォーラム

ライブラリ: TesterCache

fxsaber, 2019.11.11 04:45 PM.

  uchar Bytes[];
  
  MTTESTER::GetLastOptCache(Bytes);
  
// TESTERCACHE<TestCacheSymbolRecord> Cache; // シンボルの最適化
  TESTERCACHE<ExpTradeSummary> Cache;         // 標準的な最適化

  if (Cache.Load(Bytes)) // 最適化キャッシュを読む。
 
質問を明確にしてください。SingleTesterCacheとTesterCacheは記事の中ですでに接続されています。
 
Stanislav Korotky:
質問を明確にしてください。SingleTesterCacheとTesterCacheは記事中で既に接続されています。

EX5を実行し、自動的に最後のopt/tstファイル(Testerで最後に実行された対応するタスク)を解析のためにピックアップしたいのです。

 
fxsaber:

EX5を実行し、最後のopt/tstファイル(Testerで最後に実行された対応するジョブ)を自動的にピックアップして解析したい。

これは別の実行のための変形です。

//+------------------------------------------------------------------+
//|TSTcube.mqh
//|Copyright (c) 2020, Marketeer || マーケティア・ジャパン
//|https://www.mql5.com/en/users/marketeer
//| トレーディング・ハイパーキューブのオンライン分析処理
//|https://www.mql5.com/ja/articles/6602
//|https://www.mql5.com/ja/articles/6603
//|https://www.mql5.com/ja/articles/7656
//|rev.5.03.2020 |
//+------------------------------------------------------------------+

#include "ReportCubeBase.mqh"
#include <fxsaber/SingleTesterCache/SingleTesterCache.mqh>
#include <fxsaber/MultiTester/MTTester.mqh>                 // +


class TesterDeal: public Deal
{
  public:
    TesterDeal(const TradeDeal &td)
    {
      time = (datetime)td.time_create + TimeShift;
      price = td.price_open;
      string t = dealType(td.action);
      type = t == "buy" ? +1 : (t == "sell" ? -1 : 0);
      t = dealDir(td.entry);
      direction = 0;
      if(StringFind(t, "in") > -1) ++direction;
      if(StringFind(t, "out") > -1) --direction;
      volume = (double)td.volume;
      profit = td.profit;
      deal = (long)td.deal;
      order = (long)td.order;
      comment = td.comment[];
      symbol = td.symbol[];
      commission = td.commission;
      swap = td.storage;
      
      // バランス - SingleTesterCache.Deals[i].reserve
    }

    static string dealType(const ENUM_DEAL_TYPE type)
    {
      return type == DEAL_TYPE_BUY ? "buy" : (type == DEAL_TYPE_SELL ? "sell" : "balance");
    }

    static string dealDir(const ENUM_DEAL_ENTRY entry)
    {
      string result = "";
      if(entry == DEAL_ENTRY_IN) result += "in";
      else if(entry == DEAL_ENTRY_OUT || entry == DEAL_ENTRY_OUT_BY) result += "out";
      else if(entry == DEAL_ENTRY_INOUT) result += "in out";
      return result;
    }
};

template<typename T>
class TesterReportAdapter: public BaseReportAdapter<T>
{
  protected:
    SINGLETESTERCACHE *ptrSingleTesterCache;

    virtual bool fillDealsArray() override
    {
      for(int i = 0; i < ArraySize(ptrSingleTesterCache.Deals); i++)
      {
        if(TesterDeal::dealType(ptrSingleTesterCache.Deals[i].action) == "balance")
        {
          balance += ptrSingleTesterCache.Deals[i].profit;
        }
        else
        {
          array << new TesterDeal(ptrSingleTesterCache.Deals[i]);
        }
      }
      return true;
    }

  public:
    ~TesterReportAdapter()
    {
      if(CheckPointer(ptrSingleTesterCache) == POINTER_DYNAMIC) delete ptrSingleTesterCache;
    }

    virtual bool load(const string file) override
    {
      if(StringFind(file, ".tst") > 0)
      {
        BaseReportAdapter<T>::load(file);

        if(CheckPointer(ptrSingleTesterCache) == POINTER_DYNAMIC) delete ptrSingleTesterCache;

        bool loaded = true;                                                // +
        ptrSingleTesterCache = new SINGLETESTERCACHE();
        if(file == "*.tst")                                                // +
        {                                                                  // +
          uchar Bytes2[];                                                  // +
          // なぜ MTTESTER::GetLastTstCacheFileName() はプライベートなのですか?
          // Print("Loading ", MTTESTER::GetLastTstCacheFileName()); // 「読み込み中です。 +
          if(MTTESTER::GetLastTstCache(Bytes2) != -1)                      // +
          {                                                                // +
            loaded = ptrSingleTesterCache.Load(Bytes2);                    // +
          }                                                                // +
        }
        else
        {
          loaded = ptrSingleTesterCache.Load(file);                        // *
        }
        
        if(!loaded)                                                        // *
        {
          delete ptrSingleTesterCache;
          ptrSingleTesterCache = NULL;
          return false;
        }
        size = generate();
        
        Print("Tester cache import: ", size, " trades from ", ArraySize(ptrSingleTesterCache.Deals), " deals");
      }
      return true;
    }
};

TesterReportAdapter<RECORD_CLASS> _defaultTSTReportAdapter;

最後のtstファイルの名前をログに出力したかったのですが、対応するメソッドは非公開です。

設定では、ファイル "*.tst "を選択する必要があります(空の名前でもオンラインアカウント履歴の分析は開始されます)。

ファイル:
TSTCube.mqh  5 kb
 

最適化の結果について

#include <fxsaber/MultiTester/MTTester.mqh>                 // +

...

template<typename T>
class OptCacheDataAdapter: public DataAdapter
{
  private:
    TESTERCACHE<ExpTradeSummary> Cache;
    ...
    
  public:
    OptCacheDataAdapter()
    {
      reset();
    }
    
    void load(const string optName)
    {
      bool loaded = true;                                       // +
      if(optName == "")                                         // +
      {                                                         // +
        uchar Bytes[];                                          // +
        // なぜ GetLastOptCacheFileName() はプライベートなのですか?
        // Print("Loading ", MTTESTER::GetLastOptCacheFileName()); // +
        MTTESTER::GetLastOptCache(Bytes);                       // +
        loaded = Cache.Load(Bytes);                             // +
      }
      else
      {
        loaded = Cache.Load(optName);                           // *
      }
      if(loaded)                                                // *
      {
        customize();
        reset();
      }
      else
      {
        cursor = -1;
      }
    }
...
ファイル:
OLAPOpts.mqh  11 kb
 

OLAP技術に関するすべての記事と同様に、この記事も気に入った。

個人的には、思考の飛翔、つまり本質の哲学的な定式化、アプローチ全体のアイデアを与えること、タスクとポテンシャルのカバーされた空間が欠けていた。そしてその可能性は非常に大きい。私は、読者の時間を浪費させるような、取るに足らない細部がいくつもあることに悲しみを覚える。そこにはこんな変数があり、ここにはこんな変数がある......という。解決策をコピーする初心者には必要なことだとは思うが、それでも......。どんな技術も静的なものではないし、もしあなたのクラスやメソッドが今使われているとしたら、将来、誰かが自分のためにすべてを変えたいと思うだろうし、彼にとって記事の有用性は私的な実体の数に比例して減少するだろう。アプローチ全体について、つまりその現在と未来についてもっと書いてください。そのようなアプローチでは、もっとグローバルになる必要がある。

しかし、これは私の主観的な意見である。記事をありがとうございました。

 
Stanislav Korotky:

最後のtstファイルの名前をログに出力したかったのですが、対応するメソッドはprivateです。

誰かがそれを必要とするかもしれないとは思いもしなかった。private->publicについてもっとコメントがあれば、教えてください。そうします。

 

こんにちは、

OLAPGUI_Opts.mq5'をコンパイルしようとしましたが、いくつかのインクルードファイルに17のエラーがあります。


Ben

 
Szabo Bence #:

こんにちは、

OLAPGUI_Opts.mq5'をコンパイルしようとしましたが、いくつかのインクルードファイルに17のエラーがあります。


Ben

常に正確なエラーを表示する必要があります。