トレード履歴のカスタム表示とレポート図の作成

Andrey Azatskiy | 11 10月, 2018

イントロダクション

金融トレードにおける重要な側面に、パフォーマンスを監視し、トレード履歴を分析するというものがあります。 過去のデータでトレードのダイナミクスを追跡し、使用する戦略の全体的なパフォーマンスを評価することができます。 これは、裁量トレーダーにもシステムトレーダーにも、すべてのトレーダーにとって非常に便利です。 この記事では、このような機能を実装するツールを作成することをお勧めします。 

トレーディングの中核部分は、損益曲線を形成するトレーディングアルゴリズムです。 このようなアルゴリズムは、合成資産と比較することができます。その値は、元になる資産 (すなわち、トレードされたツール) に対して相対的に形成されます。 たとえば、オプショントレードで、ブラックショールズモデル式は、原資産価格に基づいてそのような合成資産を計算するために使用します。 しかし、トレードアルゴリズムのような式はありません。 したがって、アルゴリズムは、合成シンボルのロングポジションと比較することができます。そのうちの PL 曲線は、アルゴリズムのプログラムされたロジックによって形成されます。 この "アセット " によって形成される利益は、ある期間に不安定になる可能性があります。 計量モデルで評価できても、このモデルを統一することはできません。 しかし、どうすれば資産とトレード段階を追跡することができるでしょうか? 適切な解決策の1つは、アルゴリズムトレードのこれまでを監視し、予想される結果からの逸脱を検出することです。

アルゴリズムを分析するメソッドについてアドバイスはありませんが、トレード履歴の完全な詳解を可能にする方法を提供します。 得られたデータに基づいて、複雑な計量モデルを構築し、確率特性を計算し、さまざまな結論を出すことができます。

この記事は、2つのセクションに分かれています。 最初の (技術) セクションでは、ターミナルに格納されている情報の大部分に基づいてトレードレポートを生成するためのメソッドについて説明します。 このセクションでは、分析に使用するソースデータを扱います。 2番目のセクションでは、選択したデータのトレード結果を評価することによって、主な値を処理します。 データサンプリングは、すべての資産または選択したシンボル、利用可能な履歴全体、または一定期間にわたって変化させることができます。 解析結果は別のファイルに表示され、ターミナルで視覚化できます。

分析の例の実際のトレード履歴からデータを使用していました。 コードの実装例は、意図的にデモ口座のトレードで蓄積されたテスト期間を使用して作成されました。



第1章 トレード統計分析のデータの準備

すべての分析は、ソースデータの準備から始まります。 ここでは、特定の期間のトレード履歴を扱います。 MetaTrader5 ターミナルには詳細なレポートが保存されています。 しかし、時としてあまりにも多くの情報は邪魔になることがあります。 このセクションでは、さらに情報を処理し、分析することができます。トレード履歴の読み取り、簡単かつ有益なサンプルを作成します。

MetaTrader5 のトレード履歴と関連する処理メソッド

通常、トレード履歴をアンロードするときに大量のレコードが作成されます。 各ポジションは、順番に段階で実行することができます。エントリ/決済のトレードで構成されています。 また、緩やかなポジションのスケーリングと再ポジションの状況があります。 さらに、ヒストリーは "疑惑の情報 " の特別ラインがあります。 そのような取引があるかもしれません。

レポートの不都合な点には、トレード開始時刻によって履歴がソートされているという事実とも結びついています。 トレードの有効期間が異なる場合があるため、実際のポジションの決済に関連する情報の表示オーダーが歪んでいる可能性があります。 たとえば、最初のトレードは6月1日に開かれ、6月5日に決済されます。 2回目は6月2日にオープンし、同日に決済します。 最初のトレードよりも早くこの取引の利益/損失が出ます。しかし、時間的に後に開かれたので、テーブル上では後にあるでしょう。

したがって、この形式で記録されたトレード履歴はトレード分析には適していません。 ただし、分析されたアカウントに対する操作の履歴全体が反映されます。 MQL5 は、記述されたデータ配列を扱うための便利なツールセットを備えています。 このツールを使用して、データを読み取り可能な形式で表示します。 まず、すべてのデータをトレード履歴として整理し、トレードされた資産とトレードでソートする必要があります。 このために、次の構造体を作成しましょう:

//+------------------------------------------------------------------+
//| Data structure of one selected deal                              |
//+------------------------------------------------------------------+
struct DealData
  {
   long              ticket;            //取引のチケット
   long              order;             //トレードを開始するオーダーの番号
   datetime          DT;                //ポジション開始価格レート日付
   long              DT_msc;            //ポジション開始価格レートの日付 (ミリ秒)
   ENUM_DEAL_TYPE    type;              //開始価格レートポジションタイプ
   ENUM_DEAL_ENTRY   entry;             //ポジションエントリの種類
   long              magic;             //ポジションの一意の番号
   ENUM_DEAL_REASON  reason;            //オーダーの配置メソッド
   long              ID;                //ポジション ID
   double            volume;            //ポジションボリューム (ロット)
   double            price;             //ポジションエントリー価格
   double            comission;         //コミッション
   double            swap;              //スワップ
   double            profit;            //損益
   string            symbol;            //シンボル
   string            comment;           //開始時に指定されたコメント
   string            ID_external;       //外部 ID
  };
//+------------------------------------------------------------------+
//|特定のポジションのすべての取引を貯える構造体                          、|
//|ID で選択                                                          |
//+------------------------------------------------------------------+
struct DealKeeper
  {
   DealData の情報 [];          /* このポジションのすべてのトレードのリスト (またはポジションの反転の場合にはポジション) */
   string            symbol;            //シンボル
   long              ID;                //ポジションの ID
   datetime          DT_min;            //オープン日時
   datetime          DT_max;            //クローズ日時
  };

DealData 構造体には、トレードパラメータの過剰な記述が含まれていることをコードから確認できます。

主な構造体は DealKeeperです。 ポジションの説明と、含まれるすべてのトレードが含まれます。 ターミナル内のポジションの主なフィルタは、そのポジション内のすべてのトレードに変更されないままです。 したがって、ポジションが逆の場合、ID は保持されますが、方向は反対に変更され、DealKeeper 構造体に2つのポジションが含まれるのはそのためです。 コード内の DealKeeper は、ポジション ID に基づいてフィルタリングされます。

構造体がどのように満たされるかを詳しく検討してみましょう。 CDealHistoryGetter クラスによって行われます。すなわち、getHistory 関数:です。

//+-----------------------------------------------------------------------+
//|ターミナルからトレード履歴を抽出するクラス                                  |
//|分析しやすいビューに変換                                                  |
//+-----------------------------------------------------------------------+
class CDealHistoryGetter
  {
public:
   bool              getHistory(DealKeeper &deals[],datetime from,datetime till);                //すべてのヒストリー的なトレードに関するデータを返す  
   bool              getIDArr(ID_struct &ID_arr[],datetime from,datetime till);                  //トレード id の一意の配列を返します。
   bool              getDealsDetales(DealDetales &ans[],datetime from,datetime till);            //各行が1つの特定のトレードを表すトレードの配列を返します。
private:

   void              addArray(ID_struct &Arr[],const ID_struct &value);                          //動的配列に追加する
   void              addArray(DealKeeper &Arr[],const DealKeeper &value);                        //動的配列に追加する
   void              addArray(DealData &Arr[],const DealData &value);                            //動的配列に追加する
   void              addArr(DealDetales &Arr[],DealDetales &value);                              //動的配列に追加する
   void              addArr(double &Arr[],double value);                                         //動的配列に追加する

/*
    InOutがある場合、inputParam は複数のポジションを持つことになります。 
    InOutがない場合は、inputParam は1つだけのポジションがあります! 
*/
   void              getDeals_forSelectedKeeper(DealKeeper &inputParam,DealDetales &ans[]);      //inputParam 内のすべてのポジションに対して選択したポジションに基づいて単一のエントリを形成する
   double            MA_price(double &prices[],double &lots[]);                                  //加重平均開始価格レート価格の計算
   bool              isBorderPoint(DealData &data,BorderPointType &type);                        //境界点であるかどうか、およびその点の型に関する情報を取得します。
   ENUM_DAY_OF_WEEK  getDay(datetime DT);                                                        //日付から日を取得する
   double            calcContracts(double &Arr[],GetContractType type);                          //最後のポジションのボリュームの情報
  };

実装してみましょう:

//+------------------------------------------------------------------+
//|ヒストリー的な情報のすべてのデータを返す                               |
//+------------------------------------------------------------------+
bool CDealHistoryGetter::getHistory(DealKeeper &deals[],datetime from,datetime till)
  {
   ArrayFree(deals);                                     //結果の配列をクリアする
   ID_struct ID_arr[];
   if(getIDArr(ID_arr,from,till))                        //一意の id を取得する
     {
      int total=ArraySize(ID_arr);
      for(int i=0;i<total;i++)                           //ループスルー ID
        {
         DealKeeper keeper;                              //ポジションの取引のキーパー
         keeper.ID=ID_arr[i].ID;
         keeper.symbol=ID_arr[i].Symb;
         keeper.DT_max = LONG_MIN;
         keeper.DT_min = LONG_MAX;
         if(HistorySelectByPosition(ID_arr[i].ID))       //指定した ID を持つすべてのトレードを選択
           {

まず、ポジションの一意の ID を取得する必要があります。このために、連続ループ内のトレード id を通過し、2つのフィールドを持つ構造体を形成します。つまり、シンボルポジション IDです。 getHistory関数の操作には、取得したデータが必要になります。 

MQL5 言語には非常に有用な関数HistorySelectByPositionがあり、渡された ID を持つトレードの履歴全体を選択します。 これは、不必要な操作 (アカウント処理、デポジット処理等) を省いてくれます。 その結果、ポジションの全ての変化の履歴が記録されます。 データは日付と時刻によって並べ替えられます。 指定された ID を持つ以前に書かれたトレードの合計数を返すHistoryDealsTotal関数を使用する必要があります。

int total_2=HistoryDealsTotal();
            for(int n=0;n<total_2;n++)                        //選択したトレードをループ
              {
               long ticket=(long)HistoryDealGetTicket(n);
               DealData data;
               data.ID=keeper.ID;
               data.symbol=keeper.symbol;
               data.ticket= ticket;

               data.DT=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);
               keeper.DT_max=MathMax(keeper.DT_max,data.DT);
               keeper.DT_min=MathMin(keeper.DT_min,data.DT);
               data.order= HistoryDealGetInteger(ticket,DEAL_ORDER);
               data.type = (ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket,DEAL_TYPE);
               data.DT_msc=HistoryDealGetInteger(ticket,DEAL_TIME_MSC);
               data.entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY);
               data.magic = HistoryDealGetInteger(ticket,DEAL_MAGIC);
               data.reason= (ENUM_DEAL_REASON)HistoryDealGetInteger(ticket,DEAL_REASON);
               data.volume= HistoryDealGetDouble(ticket,DEAL_VOLUME);
               data.price = HistoryDealGetDouble(ticket,DEAL_PRICE);
               data.comission=HistoryDealGetDouble(ticket,DEAL_COMMISSION);
               data.swap=HistoryDealGetDouble(ticket,DEAL_SWAP);
               data.profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
               data.comment=HistoryDealGetString(ticket,DEAL_COMMENT);
               data.ID_external=HistoryDealGetString(ticket,DEAL_EXTERNAL_ID);

               addArray(keeper.deals,data);                  //情報の追加
              }

            if(ArraySize(keeper.deals)>0)
               addArray(deals,keeper);                       //ポジションを追加する
           }
        }
      return ArraySize(deals) > 0;
     }
   else
      return false;                                          //一意の id がない場合
  }

したがって、ユニークな ID を通過することによって、ポジションを記述するデータの配列を形成します。 構造体の DealKeeper 配列は、リクエストされた期間について、現在のアカウントの詳細なトレード履歴を反映しています。

分析のデータの準備

前のセクションでは、データを取得しました。 ファイルにデータをエクスポートしてみましょう。 下記は、分析されたポジションの1つのトレードのリストです:

Ticket Order DT DT msc Type Entry Magic Reason ID Volume Price Comission Swap Profit Symbol Comment ID external
10761601 69352663 23.11.2017 17:41 1,51146E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 506789 DEAL_REASON_EXPERT 69352663 1 58736 -0,5 0 0 Si-12.17 Open test position 23818051
10761602 69352663 23.11.2017 17:41 1,51146E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 506789 DEAL_REASON_EXPERT 69352663 1 58737 -0,5 0 0 Si-12.17 Open test position 23818052
10766760 0 24.11.2017 13:00 1,51153E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58682 0 0 -109 Si-12.17 [variation margin close]
10766761 0 24.11.2017 13:00 1,51153E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58682 0 0 0 Si-12.17 [variation margin open]
10769881 0 24.11.2017 15:48 1,51154E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58649 0 0 -66 Si-12.17 [variation margin close]
10769882 0 24.11.2017 15:48 1,51154E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58649 0 0 0 Si-12.17 [variation margin open]
10777315 0 27.11.2017 13:00 1,51179E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58420 0 0 -458 Si-12.17 [variation margin close]
10777316 0 27.11.2017 13:00 1,51179E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58420 0 0 0 Si-12.17 [variation margin open]
10780552 0 27.11.2017 15:48 1,5118E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58417 0 0 -6 Si-12.17 [variation margin close]
10780553 0 27.11.2017 15:48 1,5118E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58417 0 0 0 Si-12.17 [variation margin open]
10790453 0 28.11.2017 13:00 1,51187E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58589 0 0 344 Si-12.17 [variation margin close]
10790454 0 28.11.2017 13:00 1,51187E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58589 0 0 0 Si-12.17 [variation margin open]
10793477 0 28.11.2017 15:48 1,51188E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58525 0 0 -128 Si-12.17 [variation margin close]
10793478 0 28.11.2017 15:48 1,51188E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58525 0 0 0 Si-12.17 [variation margin open]
10801186 0 29.11.2017 13:00 1,51196E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58515 0 0 -20 Si-12.17 [variation margin close]
10801187 0 29.11.2017 13:00 1,51196E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58515 0 0 0 Si-12.17 [variation margin open]
10804587 0 29.11.2017 15:48 1,51197E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58531 0 0 32 Si-12.17 [variation margin close]
10804588 0 29.11.2017 15:48 1,51197E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58531 0 0 0 Si-12.17 [variation margin open]
10813418 0 30.11.2017 13:00 1,51205E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58843 0 0 624 Si-12.17 [variation margin close]
10813419 0 30.11.2017 13:00 1,51205E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58843 0 0 0 Si-12.17 [variation margin open]
10816400 0 30.11.2017 15:48 1,51206E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58609 0 0 -468 Si-12.17 [variation margin close]
10816401 0 30.11.2017 15:48 1,51206E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58609 0 0 0 Si-12.17 [variation margin open]
10824628 0 01.12.2017 13:00 1,51213E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58864 0 0 510 Si-12.17 [variation margin close]
10824629 0 01.12.2017 13:00 1,51213E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58864 0 0 0 Si-12.17 [variation margin open]
10828227 0 01.12.2017 15:48 1,51214E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58822 0 0 -84 Si-12.17 [variation margin close]
10828228 0 01.12.2017 15:48 1,51214E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58822 0 0 0 Si-12.17 [variation margin open]
10838074 0 04.12.2017 13:00 1,51239E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59093 0 0 542 Si-12.17 [variation margin close]
10838075 0 04.12.2017 13:00 1,51239E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59093 0 0 0 Si-12.17 [variation margin open]
10840722 0 04.12.2017 15:48 1,5124E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59036 0 0 -114 Si-12.17 [variation margin close]
10840723 0 04.12.2017 15:48 1,5124E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59036 0 0 0 Si-12.17 [variation margin open]
10848185 0 05.12.2017 13:00 1,51248E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58793 0 0 -486 Si-12.17 [variation margin close]
10848186 0 05.12.2017 13:00 1,51248E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58793 0 0 0 Si-12.17 [variation margin open]
10850473 0 05.12.2017 15:48 1,51249E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58881 0 0 176 Si-12.17 [variation margin close]
10850474 0 05.12.2017 15:48 1,51249E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58881 0 0 0 Si-12.17 [variation margin open]
10857862 0 06.12.2017 13:00 1,51257E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59181 0 0 600 Si-12.17 [variation margin close]
10857863 0 06.12.2017 13:00 1,51257E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59181 0 0 0 Si-12.17 [variation margin open]
10860776 0 06.12.2017 15:48 1,51258E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59246 0 0 130 Si-12.17 [variation margin close]
10860777 0 06.12.2017 15:48 1,51258E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59246 0 0 0 Si-12.17 [variation margin open]
10869047 0 07.12.2017 13:00 1,51265E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59325 0 0 158 Si-12.17 [variation margin close]
10869048 0 07.12.2017 13:00 1,51265E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59325 0 0 0 Si-12.17 [variation margin open]
10871856 0 07.12.2017 15:48 1,51266E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59365 0 0 80 Si-12.17 [variation margin close]
10871857 0 07.12.2017 15:48 1,51266E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59365 0 0 0 Si-12.17 [variation margin open]
10879894 0 08.12.2017 13:01 1,51274E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59460 0 0 190 Si-12.17 [variation margin close]
10879895 0 08.12.2017 13:01 1,51274E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59460 0 0 0 Si-12.17 [variation margin open]
10882283 0 08.12.2017 15:48 1,51275E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59421 0 0 -78 Si-12.17 [variation margin close]
10882284 0 08.12.2017 15:48 1,51275E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59421 0 0 0 Si-12.17 [variation margin open]
10888014 0 11.12.2017 13:00 1,513E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59318 0 0 -206 Si-12.17 [variation margin close]
10888015 0 11.12.2017 13:00 1,513E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59318 0 0 0 Si-12.17 [variation margin open]
10890195 0 11.12.2017 15:48 1,51301E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59280 0 0 -76 Si-12.17 [variation margin close]
10890196 0 11.12.2017 15:48 1,51301E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59280 0 0 0 Si-12.17 [variation margin open]
10895808 0 12.12.2017 13:00 1,51308E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58920 0 0 -720 Si-12.17 [variation margin close]
10895809 0 12.12.2017 13:00 1,51308E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58920 0 0 0 Si-12.17 [variation margin open]
10897839 0 12.12.2017 15:48 1,51309E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58909 0 0 -22 Si-12.17 [variation margin close]
10897840 0 12.12.2017 15:48 1,51309E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58909 0 0 0 Si-12.17 [variation margin open]
10903172 0 13.12.2017 13:00 1,51317E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59213 0 0 608 Si-12.17 [variation margin close]
10903173 0 13.12.2017 13:00 1,51317E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59213 0 0 0 Si-12.17 [variation margin open]
10905906 0 13.12.2017 15:48 1,51318E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 59072 0 0 -282 Si-12.17 [variation margin close]
10905907 0 13.12.2017 15:48 1,51318E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 59072 0 0 0 Si-12.17 [variation margin open]
10911277 0 14.12.2017 13:00 1,51326E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 2 58674 0 0 -796 Si-12.17 [variation margin close]
10911278 0 14.12.2017 13:00 1,51326E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 2 58674 0 0 0 Si-12.17 [variation margin open]
10912285 71645351 14.12.2017 14:48 1,51326E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 506789 DEAL_REASON_EXPERT 69352663 1 58661 -0,5 0 -13 Si-12.17 PartialClose position_2 25588426
10913632 0 14.12.2017 15:48 1,51327E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58783 0 0 109 Si-12.17 [variation margin close]
10913633 0 14.12.2017 15:48 1,51327E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58783 0 0 0 Si-12.17 [variation margin open]
10919412 0 15.12.2017 13:00 1,51334E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58912 0 0 129 Si-12.17 [variation margin close]
10919413 0 15.12.2017 13:00 1,51334E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58912 0 0 0 Si-12.17 [variation margin open]
10921766 0 15.12.2017 15:48 1,51335E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58946 0 0 34 Si-12.17 [variation margin close]
10921767 0 15.12.2017 15:48 1,51335E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58946 0 0 0 Si-12.17 [variation margin open]
10927382 0 18.12.2017 13:00 1,5136E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58630 0 0 -316 Si-12.17 [variation margin close]
10927383 0 18.12.2017 13:00 1,5136E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58630 0 0 0 Si-12.17 [variation margin open]
10929913 0 18.12.2017 15:48 1,51361E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58664 0 0 34 Si-12.17 [variation margin close]
10929914 0 18.12.2017 15:48 1,51361E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58664 0 0 0 Si-12.17 [variation margin open]
10934874 0 19.12.2017 13:00 1,51369E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58635 0 0 -29 Si-12.17 [variation margin close]
10934875 0 19.12.2017 13:00 1,51369E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58635 0 0 0 Si-12.17 [variation margin open]
10936988 0 19.12.2017 15:48 1,5137E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58629 0 0 -6 Si-12.17 [variation margin close]
10936989 0 19.12.2017 15:48 1,5137E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58629 0 0 0 Si-12.17 [variation margin open]
10941561 0 20.12.2017 13:00 1,51377E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58657 0 0 28 Si-12.17 [variation margin close]
10941562 0 20.12.2017 13:00 1,51377E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58657 0 0 0 Si-12.17 [variation margin open]
10943405 0 20.12.2017 15:48 1,51378E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58684 0 0 27 Si-12.17 [variation margin close]
10943406 0 20.12.2017 15:48 1,51378E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58684 0 0 0 Si-12.17 [variation margin open]
10948277 0 21.12.2017 13:00 1,51386E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_VMARGIN 69352663 1 58560 0 0 -124 Si-12.17 [variation margin close]
10948278 0 21.12.2017 13:00 1,51386E+12 DEAL_TYPE_BUY DEAL_ENTRY_IN 0 DEAL_REASON_VMARGIN 69352663 1 58560 0 0 0 Si-12.17 [variation margin open]
10949780 0 21.12.2017 15:45 1,51387E+12 DEAL_TYPE_SELL DEAL_ENTRY_OUT 0 DEAL_REASON_CLIENT 69352663 1 58560 0 0 0 Si-12.17 [instrument expiration] 26163141

この使用例は、USDRUR 先物トレードのヒストリーに基づいています。(デモ口座 FORTSで実行) このテーブルから、ポジションエントリが等しいロットで2つのオーダーに分割されたことがわかります。 決済も2つのトレードで行われました。 各エントリと決済のトレードを開いたオーダーの id (変動マージンを除く) は、ゼロ以外でした。 しかし、ポジションを閉じた最後のトレードは、ゼロの ID を持つオーダーから始まりました。 これは、ポジションが裁量で閉じられずに、有効期限切れになったために発生しました。

1つのポジションで実行された (いわゆる "疑惑 " オーダーを含む) トレードを反映して視覚的に表された履歴です。 しかし、まだ最終的なポジション分析には不便であり、さらなる改善が必要です。 各行のポジションの結果を反映し、関連する情報を提供するテーブルが必要です。

次の構造体を作成してみましょう。

//+------------------------------------------------------------------+
//|結果を保存する構造体                                                |
//|選択したポジションに関する主な情報                                    |
//+------------------------------------------------------------------+
struct DealDetales
  {
   string            symbol;                //シンボル
   datetime          DT_open;               //開始価格レート日付
   ENUM_DAY_OF_WEEK  day_open;              //ポジションの開始曜日
   datetime          DT_close;              //決済日付
   ENUM_DAY_OF_WEEK  day_close;             //ポジションの決済曜日
   double            volume;                //ボリューム (ロット)
   bool              isLong;                //ロング/ショートのサイン
   double            price_in;              //ポジションエントリー価格
   double            price_out;             //ポジションの決済の価格
   double            pl_oneLot;             //1ロットがトレードされた場合の損益
   double            pl_forDeal;            //実際の損益は、コミッションを考慮して、取得されます
   string            open_comment;          //オープニング時のコメント
   string            close_comment;         //決済時のコメント
  };

この構造体は、 getDealsDetalesメソッドによって形成されます。 3つの主要な用メソッドを使用する: 

MA_priceメソッドについて詳しく見てみましょう。 たとえば、開始価格レートのポジションが異なる価格で複数の取引を結んだ場合、最初のトレードの価格をポジション開始価格として使用することは不適切です。 さらなる計算でエラーが発生します。 加重平均値を使用します。 オープン/クローズ価格のポジションを平均し、オープントレードの量によって加重します。 これがロジックをコードに実装する方法です。

//+------------------------------------------------------------------+
//|加重平均開始価格レート価格の計算                                      |
//+------------------------------------------------------------------+
double CDealHistoryGetter::MA_price(double &prices[],double &lots[])
  {
   double summ=0;                           //加重価格の合計
   double delemetr=0;                       //重みの合計
   int total=ArraySize(prices);
   for(int i=0;i<total;i++)                 //総和ループ
     {
      summ+=(prices[i]*lots[i]);
      delemetr+=lots[i];
     }
   return summ/delemetr;                    //平均の計算
  }
トレードロットについては: より複雑なケースですが、理解することは困難ではありません。 動的ポジション管理の例を考えてみましょう: 徐々に追加したり、ロットの数を減らします:

In Out
Open (t1) 1 0
t2 2 0
t3 5 3
t4 1 0
t5 0 1
t6 1 0
t7 0 1
t8 1 0
t9 0 1
Close (t10) 0 5
Total  11  11 

ポジションのライフタイムの間に、さらに複数回売買しました。 したがって、11買いの買いと無数の売りがあります。 しかし、これは最大到達ポジションのボリュームが11ロットに等しいことを意味するものではありません。 すべてのエントリと決済を書き留めてみましょう。ポジションの増加とエントリは、+符号を持つことになります。 ポジションの減少は、ー符号を持つことになります。PL 曲線と同様に和を算出します。


トレード量 ポジションのボリューム
deal 1 1 1
deal  2 2 3
deal 3 5 8
deal 4 -3 5
deal 5 1 6
deal 6 -1 5
deal 7 1 6
deal 8 -1 5
deal 9 1 6
deal 10 -1 5
deal 11  -5  0

このテーブルから、最大到達ボリュームが8ロットであったことがわかります。 これは、必須の値です。

ロット数を反映した関数のコードを以下に示します。

//+------------------------------------------------------------------+
//|ポジションの実際のボリュームを計算し、                                 |
//|最後のポジションのボリュームについての情報を得る                        |
//+------------------------------------------------------------------+
double CDealHistoryGetter::calcContracts(double &Arr[],GetContractType type)
  {
   int total;

   if((total=ArraySize(Arr))>1)                        //配列のサイズが1より大きい場合
     {
      double lotArr[];
      addArr(lotArr,Arr[0]);                           //配列に最初のロットを追加する
      for(int i=1;i<total;i++)                         //2番目の配列要素からのループ
         addArr(lotArr,(lotArr[i-1]+Arr[i]));          //配列に前と現在のロットの合計を追加する (lotArr [i-1] + Arr [i]))

      if(type==GET_REAL_CONTRACT)
         return lotArr[ArrayMaximum(lotArr)];          //実際の最大トレードロットを返す
      else
         return lotArr[ArraySize(lotArr)-1];           //最後にトレードされたロットを返す
     }
   else
      return Arr[0];
  }

ロットのシンプルなカウントに加えて、この関数は最後のアクティブロット (例では5に等しい) を示します。

不必要な取引をフィルタリングするために作成されたisBorderPoint関数を考えてみましょう。 データ構造体に基づいて、4つの変数を使用してトレードの重要性を判断することができます:

列挙体の作成:

//+--------------------------------------------------------------------+
//|特定のレコードの種類を示す補助列挙体                                    |
//|レコードは DealData 構造体によって表されます                            |
//+--------------------------------------------------------------------+
enum BorderPointType
  {
   UsualInput,          //通常のエントリタイプ (DEAL_ENTRY_IN)-取引の始まり
   UsualOutput,         //通常決済のタイプ (DEAL_ENTRY_OUT)-取引の終わり
   OtherPoint,          //残高の操作、ポジションの修正、引き出し、変動マージン-無視する
   InOut,               //ポジション反転 (DEAL_ENTRY_INOUT)
   OutBy                //反対のオーダーで閉じられたポジション (DEAL_ENTRY_OUT_BY)
  };
5つのうち4つの亜種が必要です。 無視されるすべてのトレードは、OtherPoint に集められます。 各列挙バリアントのパラメータの組み合わせを表に示します。 この関数コードは、以下に添付されているファイルで使用できます。 
Enumeration variant Order ID ENUM_DEAL_ENTRY ENUM_DEAL_TYPE ENUM_DEAL_REASON
UsualInput  >0 DEAL_ENTRY_IN DEAL_TYPE_BUY DEAL_REASON_CLIENT
DEAL_REASON_EXPERT



DEAL_TYPE_SELL DEAL_REASON_WEB


DEAL_REASON_MOBILE



UsualOut >=0(=0 if closed by expiration) DEAL_ENTRY_OUT DEAL_TYPE_BUY DEAL_REASON_CLIENT
DEAL_REASON_EXPERT



DEAL_REASON_WEB



DEAL_TYPE_SELL DEAL_REASON_MOBILE


DEAL_REASON_SL



DEAL_REASON_TP



DEAL_REASON_SO



OtherPoint  0 DEAL_ENTRY_IN DEAL_TYPE_BUY DEAL_REASON_ROLLOVER
DEAL_TYPE_SELL



DEAL_TYPE_BALANCE



DEAL_TYPE_CREDIT



DEAL_TYPE_CHARGE



DEAL_TYPE_CORRECTION



DEAL_TYPE_BONUS DEAL_REASON_VMARGIN


DEAL_TYPE_COMMISSION



DEAL_TYPE_COMMISSION_DAILY



DEAL_ENTRY_OUT DEAL_TYPE_COMMISSION_MONTHLY


DEAL_TYPE_COMMISSION_AGENT_DAILY



DEAL_TYPE_COMMISSION_AGENT_MONTHLY



DEAL_TYPE_INTEREST DEAL_REASON_SPLIT


DEAL_TYPE_BUY_CANCELED



DEAL_TYPE_SELL_CANCELED



DEAL_DIVIDEND



DEAL_DIVIDEND_FRANKED



DEAL_TAX



InOut  >0 DEAL_ENTRY_INOUT  DEAL_TYPE_BUY DEAL_REASON_CLIENT
DEAL_REASON_EXPERT



DEAL_TYPE_SELL DEAL_REASON_WEB


DEAL_REASON_MOBILE



OutBy  >0 DEAL_ENTRY_OUT_BY  DEAL_TYPE_BUY DEAL_REASON_CLIENT
DEAL_REASON_EXPERT



DEAL_TYPE_SELL DEAL_REASON_WEB


DEAL_REASON_MOBILE



getDeals_forSelectedKeeperメソッドを使用して必要な履歴を形成します。 一般的なロジックを表示してから、上記の列挙バリアント (行303から始まる) のそれぞれについて、詳細を分析してみましょう。

//+------------------------------------------------------------------+
//| One record for each selected position is formed in в inputParam  |
//+------------------------------------------------------------------+

void CDealHistoryGetter::getDeals_forSelectedKeeper(DealKeeper &inputParam,DealDetales &ans[])
  {
   ArrayFree(ans);
   int total=ArraySize(inputParam.deals);
   DealDetales detales;                                          //次のループの結果が追加される変数
   detales.symbol=inputParam.symbol;
   detales.volume= 0;
   detales.pl_forDeal=0;
   detales.pl_oneLot=0;
   detales.close_comment= "";
   detales.open_comment = "";
   detales.DT_open=0;

//ポジションをセットに追加するかどうかを示すフラグ
   bool isAdd=false;
   bool firstPL_setted=false;
//エントリの価格、決済の価格、エントリロット、決済ロット、取引の配列
   double price_In[],price_Out[],lot_In[],lot_Out[],contracts[]; //ライン404

   for(int i=0;i<total;i++)                                      //トレードをループする (すべてのトレードに同じ ID がありますが、トレードタイプがエントリーされている場合は複数のポジションを持つことができます)
     {
      BorderPointType type;                                      //取引タイプ、ライン408
      double pl_total=0;

      if(isBorderPoint(inputParam.deals[i],type))                //ボーダー取引および取引のタイプであるかどうか、ライン301
        {
          //ライン413 
        } //ライン414
      else
        {
/*
         ボーダー取引でなければ、結果を記録
         バリエーションマージンと各種補正操作しかありません。
         初期データの取得時に、入金および出金操作が除外されます。 
*/
         detales.pl_forDeal+=(inputParam.deals[i].profit+inputParam.deals[i].comission);
         detales.pl_oneLot+=inputParam.deals[i].profit/calcContracts(contracts,GET_LAST_CONTRACT);
        }
     }

//アクティブなポジションをフィルタリングして保存
   if(isAdd && PositionSelect(inputParam.symbol))                 // line 541
     {
      if(PositionGetInteger(POSITION_IDENTIFIER)==inputParam.ID)
         isAdd=false; 
     }                                                            // line 546

//固定済みおよび非アクティブなポジションの保存
   if(isAdd)
     {
      detales.price_in=MA_price(price_In,lot_In);
      detales.price_out=MA_price(price_Out,lot_Out);

      detales.volume=calcContracts(contracts,GET_REAL_CONTRACT);
      addArr(ans,detales);
     }
  }

配列は、関数の404行で宣言されます。 さらに411-414 行で指定された条件の下で使用します。唯一の境界点は、この条件の中で考えられています。 すなわち、オープン/クローズまたは増加/部分的に価格レートのポジションを閉じるトレードです。

トレードが最初の条件に該当しない場合、唯一必要なアクションは、その利益/損失を計算することです。 ヒストリーは、実際にトレードに分割されている損益を取得しています。 各取引は分析された取引の実行に先行する取引から始まって PL の変更を反映します。 総ポジションの利益は、すべてのトレードの PLの合計に等しくなります。 開始価格と終値の差額として損益を計算した場合、ポジション、コミッション、手数料におけるスリップ、ボリュームの変更など、要因の数は無視されます。

コードライン541-546では、開始価格レートのポジションがフィルタ処理され、結果として保存されます。 次の関数の最後に計算されます: オープンクローズの価格だけでなく、相場にあった最大のポジションのボリュームが計算されます。

type 変数は、ボーダーポイントのフィルター処理に使用します。 オープンまたは取引の増加が現時点で行われている場合、413行から始まる次の条件に切り替える (添付ファイル内のメソッドのフルコードを参照してください)。

if(type==UsualInput)                                                   //最初のエントリまたはポジションの増加である場合
  {
   if(detales.DT_open==0)                                              //ポジションの開始日の割り当て
     {
      detales.DT_open=inputParam.deals[i].DT;
      detales.day_open=getDay(inputParam.deals[i].DT);
     }
   detales.isLong=inputParam.deals[i].type==DEAL_TYPE_BUY;             //ポジション方向の決定
   addArr(price_In,inputParam.deals[i].price);                         //エントリ価格の保存
   addArr(lot_In,inputParam.deals[i].volume);                          //ロット数の保存

   pl_total=(inputParam.deals[i].profit+inputParam.deals[i].comission);
   detales.pl_forDeal+=pl_total;                                       //手数料を考慮したトレードの損益
   if(!firstPL_setted)
     {
      detales.pl_oneLot=pl_total/inputParam.deals[i].volume;           //トレードの利益/損失は、1つのロットを交換する場合は、手数料を考慮
      firstPL_setted=true;
     }
   else
      detales.pl_oneLot=inputParam.deals[i].profit/calcContracts(contracts,GET_LAST_CONTRACT);                 

   if(StringCompare(inputParam.deals[i].comment,"")!=0)                //取引へのコメント
      detales.open_comment+=(StringCompare(detales.open_comment,"")==0 ?
                             inputParam.deals[i].comment :
                             (" | "+inputParam.deals[i].comment));
   addArr(contracts,inputParam.deals[i].volume);                       // "+ " シンボルを使用してトレードのボリュームを追加する
  }

また、ポジション開始価格レート日付を割り当て、利益 (合計と1ロットあたり) を計算します。 ポジションの決済は別の条件の下で実行されます:

if(type==UsualOut || type==OutBy)                         //ポジションの決済
  {
/*
           いくつかの決済があるので、すぐには結果を保存しません
           したがって、データの損失を避けるために、フラグを残す 
*/
   if(!isAdd)isAdd=true;                                  //ポジションを保存するフラグ

   detales.DT_close=inputParam.deals[i].DT;               //決算日時
   detales.day_close=getDay(inputParam.deals[i].DT);      //決算日
   addArr(price_Out,inputParam.deals[i].price);           //決済価格を保存
   addArr(lot_Out,inputParam.deals[i].volume);            //決済ボリュームを保存する

   pl_total=(inputParam.deals[i].profit+inputParam.deals[i].comission);          //手数料を考慮したトレードの損益
   detales.pl_forDeal+=pl_total;

   if(i==total-1)
      detales.pl_oneLot+=pl_total/calcContracts(contracts,GET_LAST_CONTRACT);    //トレードの利益/損失は、1つのロットを交換する場合は、手数料を考慮
   else
      detales.pl_oneLot+=inputParam.deals[i].profit/calcContracts(contracts,GET_LAST_CONTRACT); //トレードの利益/損失は、1つのロットを交換する場合は、手数料を考慮

   if(StringCompare(inputParam.deals[i].comment,"")!=0)                          //取引コメント
      detales.close_comment+=(StringCompare(detales.close_comment,"")==0 ?
                              inputParam.deals[i].comment :
                              (" | "+inputParam.deals[i].comment));
   addArr(contracts,-inputParam.deals[i].volume);                                //"-" シンボルでトレードのボリュームを追加する
  }

この条件により、ポジションの決済日が割り当てられ、トレードの利益が計算されます。 複数のエントリ/決済があり、条件が数回発生することができます。

入出力条件は、2番目と最初の条件の組み合わせです。 ポジションの反転の結果が一度だけ発生しました。

if(type==InOut)                                                                 //ポジションの反転
  {
/*
           第1部:
           前のポジションを保存する
*/
   firstPL_setted=true;
   double closingContract=calcContracts(contracts,GET_LAST_CONTRACT);           //クローズド取引
   double myLot=inputParam.deals[i].volume-closingContract;                     //オープン取引

   addArr(contracts,-closingContract);                                          //取引ボリュームを  "-" シンボルで追加します。
   detales.volume=calcContracts(contracts,GET_REAL_CONTRACT);                   //実際に相場に存在していた最大の実質トレード量を得る

   detales.DT_close=inputParam.deals[i].DT;                                     //決算日
   detales.day_close=getDay(inputParam.deals[i].DT);                            //決算日
   addArr(price_Out,inputParam.deals[i].price);                                 //決済価格
   addArr(lot_Out,closingContract);                                             //決済ボリューム

   pl_total=(inputParam.deals[i].profit*closingContract)/inputParam.deals[i].volume;        //決算トレードの PL の計算
   double commission_total=(inputParam.deals[i].comission*closingContract)/inputParam.deals[i].volume;
   detales.pl_forDeal+=(pl_total+commission_total);
   detales.pl_oneLot+=pl_total/closingContract;                                 //トレードの利益/損失は、1つのロットを交換する場合は、手数料を考慮
   if(StringCompare(inputParam.deals[i].comment,"")!=0)                         //決済コメントを保存する
      detales.open_comment+=(StringCompare(detales.open_comment,"")==0 ?
                             inputParam.deals[i].comment :
                             (" | "+inputParam.deals[i].comment));

   detales.price_in=MA_price(price_In,lot_In);                                  //ポジションのエントリの価格を取得します (平均)
   detales.price_out=MA_price(price_Out,lot_Out);                               //ポジションを取得する決済価格 (平均)
   addArr(ans,detales);                                                         //形成されたポジションを追加
   if(isAdd)isAdd=false;                                                        //フラグが有効になっている場合はリセットする

                                                                                //データの一部を消去する
   ArrayFree(price_In);
   ArrayFree(price_Out);
   ArrayFree(lot_In);
   ArrayFree(lot_Out);
   ArrayFree(contracts);
   detales.close_comment="";
   detales.open_comment="";
   detales.volume=0;

/*
           第2部:
           詳細配列からデータの一部を削除した後、新しいポジションを保存します。
*/

   addArr(contracts,myLot);                                                     //ポジションオープンロットの追加

   pl_total=((inputParam.deals[i].profit+inputParam.deals[i].comission)*myLot)/inputParam.deals[i].volume; //手数料を考慮したトレードの損益
   detales.pl_forDeal=pl_total;
   detales.pl_oneLot=pl_total/myLot;                                            //手数料を考慮した場合のトレードの利益/損失
   addArr(lot_In,myLot);                                                        //エントリロットの追加

   detales.open_comment=inputParam.deals[i].comment;                            //コメントを保存する

   detales.DT_open=inputParam.deals[i].DT;                                      //開始日を保存する
   detales.day_open=getDay(inputParam.deals[i].DT);                             //オープン日時を保存する
   detales.isLong=inputParam.deals[i].type==DEAL_TYPE_BUY;                      //トレードの方向を決定する
   addArr(price_In,inputParam.deals[i].price);                                  //エントリ価格の保存
  }

上記の計算の結果はテーブルであり、各行はポジションの主要なパラメータを反映しています。 これで、ポジションに基づいて、すべての必要な計算を生成することができます。

Instrument Open DT Open day Close DT Close day Contracts Direction Price open Price close PL for 1 lot PL for position Open comment Close comment
RTS-12.17 17.11.2017 19:53 FRIDAY 17.11.2017 19:54 FRIDAY 2.00000000 Long 113200.00000000 113180.00000000 -25.78000000 -55.56000000
RTS-12.17 17.11.2017 19:54 FRIDAY 17.11.2017 19:54 FRIDAY 2.00000000 Short 113175.00000000 113205.00000000 -58.47000000 -79.33000000
RTS-12.17 17.11.2017 19:58 FRIDAY 17.11.2017 19:58 FRIDAY 1.00000000 Short 113240.00000000 113290.00000000 -63.44000000 -63.44000000
RTS-12.17 17.11.2017 19:58 FRIDAY 17.11.2017 19:58 FRIDAY 1.00000000 Long 113290.00000000 113250.00000000 -51.56000000 -51.56000000
Si-12.17 17.11.2017 20:00 FRIDAY 17.11.2017 20:00 FRIDAY 10.00000000 Long 59464.40000000 59452.80000000 -23.86000000 -126.00000000
Si-12.17 17.11.2017 20:00 FRIDAY 17.11.2017 20:00 FRIDAY 5.00000000 Short 59453.20000000 59454.80000000 -5.08666667 -13.00000000
Si-12.17 17.11.2017 20:02 FRIDAY 17.11.2017 20:02 FRIDAY 1.00000000 Short 59460.00000000 59468.00000000 -9.00000000 -9.00000000
Si-12.17 17.11.2017 20:02 FRIDAY 17.11.2017 20:03 FRIDAY 2.00000000 Long 59469.00000000 59460.00000000 -14.50000000 -20.00000000
Si-12.17 21.11.2017 20:50 TUESDAY 21.11.2017 21:06 TUESDAY 2.00000000 Long 59467.00000000 59455.00000000 -13.00000000 -26.00000000
Si-12.17 23.11.2017 17:41 THURSDAY 21.12.2017 15:45 THURSDAY 2.00000000 Long 58736.50000000 58610.50000000 -183.00000000 -253.50000000 Open test position | Open test position PartialClose position_2 | [instrument expiration]
RTS-12.17 23.11.2017 18:07 THURSDAY 14.12.2017 14:45 THURSDAY 1.00000000 Short 115680.00000000 114110.00000000 1822.39000000 1822.39000000 Open test position_2
RTS-3.18 30.01.2018 20:22 TUESDAY 30.01.2018 20:22 TUESDAY 2.00000000 Short 127675.00000000 127710.00000000 -61.01000000 -86.68000000
RTS-3.18 30.01.2018 20:24 TUESDAY 30.01.2018 20:24 TUESDAY 1.00000000 Long 127730.00000000 127710.00000000 -26.49000000 -26.49000000
RTS-3.18 30.01.2018 20:24 TUESDAY 30.01.2018 20:25 TUESDAY 1.00000000 Long 127730.00000000 127680.00000000 -60.21000000 -60.21000000
RTS-3.18 30.01.2018 20:25 TUESDAY 30.01.2018 20:25 TUESDAY 1.00000000 Long 127690.00000000 127660.00000000 -37.72000000 -37.72000000
RTS-3.18 30.01.2018 20:25 TUESDAY 30.01.2018 20:26 TUESDAY 1.00000000 Long 127670.00000000 127640.00000000 -37.73000000 -37.73000000
RTS-3.18 30.01.2018 20:29 TUESDAY 30.01.2018 20:30 TUESDAY 1.00000000 Long 127600.00000000 127540.00000000 -71.45000000 -71.45000000

第2章. カスタムトレーディングレポートの作成

次に、トレーディングレポートを生成するクラスを作成しましょう。 まず、レポートの要件を定義します。

  1. このレポートは、パフォーマンスのより効率的な評価の標準の PL チャートと拡張されたものが含まれます。 図表の構造体はゼロから始まり、 (最初の資産に関係なく)-評価の客観性を高めます。
  2. PL チャートに似ている戦略の "買いとホールド " チャートを生成します (両方が同じ関数によって計算されます)。 図はいずれも、レポートに表示されるすべてのアセットに基づいて作成されます。
  3. 主な係数とトレード結果を表に表示します。
  4. 追加のチャートは、日毎に PLのように構築されます。

最後に、変数のチャートの形で分析されたパラメータを提示し、csv ファイルにすべての計算結果をダウンロードします。 ここで指定した例は、一定期間の実際の履歴に基づいています。 この履歴は以下に添付されます。 可視化とデータのダウンロードのスクリプトは、次の関数が含まれます: 最初の1つは、接続されたトレードの履歴に例を示し、2番目はターミナルで利用可能な独自の履歴に基づいて行われます。

この記事では、最小限のコードを提供します。 その代わりに、得られたデータを調べ、その意味を説明することに焦点を当てましょう。 レポートを作成するクラスのすべての部分は、詳細にコメントされているので、理解できるでしょう。 記述された関数のより良い理解のために、ここにクラスの構造体を提供します。

class CReportGetter
  {
public:
                     CReportGetter(DealDetales &history[]);                      //準備されたフォーマットのヒストリーだけ与えられることができる
                     CReportGetter(DealDetales &history[],double balance);       //ここでは、計算を実行するときの相対的な履歴とバランスの両方を設定できます。
                    ~CReportGetter();

   bool              get_PLChart(PL_chartData &pl[],
                                 PL_chartData &pl_forOneLot[],
                                 PL_chartData &Indicative_pl[],
                                 string &Symb[]);                                //PL チャート

   bool              get_BuyAndHold(PL_chartData &pl[],
                                    PL_chartData &pl_forOneLot[],
                                    PL_chartData &Indicative_pl[],
                                    string &Symb[]);                             // Buy and hold charts

   bool              get_PLHistogram(PL_chartData &pl[],
                                     PL_chartData &pl_forOneLot[],
                                     string &Symb[]);                            //損益積算ヒストグラム

   bool              get_PL_forDays(PLForDaysData &ans,
                                    DailyPL_calcBy calcBy,
                                    DailyPL_calcType type,
                                    string &Symb[]);                             //PL の曜日別

   bool              get_extremePoints(PL_And_Lose &total,
                                       PL_And_Lose &forDeal,
                                       string &Symb[]);                          //極度なポイント (取引内の最高および最低値)

   bool              get_AbsolutePL(PL_And_Lose &total,
                                    PL_And_Lose &average,
                                    string &Symb[]);                             //絶対値 (累積および平均 PL)

   bool              get_PL_And_Lose_percents(PL_And_Lose &ans,string &Symb[]);  //勝利と負け取引の分配の図式

   bool              get_totalResults(TotalResult_struct &res,string &Symb[]);   //主変数の表

   bool              get_PLDetales(PL_detales &ans,string &Symb[]);              //PL チャートの概要

   void              get_Symbols(string &SymbArr[]);                             //履歴で使用可能なシンボルのリストを取得する

private:
   DealDetales       history[];                                                  //トレードのヒストリーを保存します。
   double            balance;                                                    //残高の値を格納します。

   void              addArray(DealDetales &Arr[],DealDetales &value);            //動的配列へのデータの追加
   void              addArray(PL_chartData &Arr[],PL_chartData &value);          //動的配列へのデータの追加
   void              addArray(string &Arr[],string value);                       //動的配列へのデータの追加
   void              addArray(datetime &Arr[],datetime value);                   //動的配列へのデータの追加

   void              sortHistory(DealDetales &arr[],bool byClose);               //始値レートまたは終値による履歴のソート

   void              cmpDay(int i,ENUM_DAY_OF_WEEK day,ENUM_DAY_OF_WEEK etaloneDay,PLDrowDown &ans);      //PLDrowDown 構造体

   bool              isSymb(string &Symb[],int i);                               //履歴からの i 番目のシンボルが Symb 配列にあるかどうかを確認します。

   bool              get_PLChart_byHistory(PL_chartData &pl[],
                                           PL_chartData &pl_forOneLot[],
                                           PL_chartData &Indicative_pl[],
                                           DealDetales &historyData[]);          //渡されたヒストリーに基づく PL チャート

   ENUM_DAY_OF_WEEK  getDay(datetime DT);                                        //日付からトレード日を取得する

  }

3種類の PL 図

損益図を作成するには、初期データをポジションの決済日で並べ替えます。 標準のチャートであるため、ここでは説明は必要ありません。 X 軸に沿ってポジションを閉じる日付を持つ2つのチャートで構成されます。 最初の1つは実際の pl チャートで、2つ目は最大 pl 値に対する累積ドローダウンをパーセントで示しています。 3種類の図を考えてみましょう。

  1. 標準累積利益チャート。
  2. 全体のヒストリーを通して、すべてのシンボル上で一ロットトレードしたかのように、トレードボリュームが考慮されていない累積利益チャート
  3. 正規化された負けた最大ロットの利益と損失のチャート PL チャートは、レッドゾーンにある場合、その後、最大収益性の高いロットで i-th の損失を分割します。 チャートが緑のゾーンにある場合は、最大損失ロットによって i 番目の利益を分割します。

最初の2つの図では、トレードされたボリュームの変化が損益にどのように影響するかを理解できます。 3つ目は極端な状況を想像することができます: 損失の一連の突然始まった場合、何が起こるか、損失は、ロットあたりの最大可能なヒストリー的損失 (実質的に不可能です) に等しくなりました。 0に達する前に、PLが連続して起こり得る最大の損失を示しています。(つまりすべての利益がロスト)逆を言えば、すべて負けた場合に何が起こるかを表しています。 図の種類を次に示します。

リアル PL チャート

1ロット PL チャート

インジケータの PL

1ロットトレーディングの PL チャートは、実際のチャートよりも魅力的です。 実質のトレードの間の利益はわずか 30% によって仮説 「1ロット 」のトレードを超過しました。 ロットサイズは1から10まで及びました。 % のドローダウンは 30,000% に達した。 状況はそれほど酷くはありません。 前述のように、pl チャートの構築はゼロから始まり、ドローダウンは pl 曲線の最大値を基準に計算されます。 同時に、損失はまだ最大値 (チャート上の赤いゾーン) に達していなかったとき、利益は-18000 ルーブルに下落した。 よって、このドローダウンはとても巨大です。 実際のドローダウンは1ロットあたり 25%、実際の取引の 50% を超過していません。

1ロットトレードのドローダウン


総ドローダウン


正規化された PL チャートは、1つの値でスタックします。 トレードメソッドを変更する (ロット管理メソッドを変更するなど) か、またはトレードアルゴリズムを再最適化する必要があることを示しています。 可変ロットを持つ PL チャートは、同じ期間の1ロットチャートよりも悪く見えますが、そのようなポジション管理は、まだ正の結果を持っていました。つまり、ドローダウンジャンプが弱くなった。

トレーディングレポートを生成するクラスはCReportGetterと呼ばれ、ダイアグラムはget_PLChart_byHistoryメソッドによって構築されます。 このメソッドは、ソースコードファイル内の詳細なコメントが提供されます。 次のように動作します。

  1. 渡された履歴を繰り返し処理します。
  2. 各ポジションは、PL、最大利益とドローダウンの計算に含まれています。
  3. ドローダウンは、最大利益に対する累積値として計算されます。 PL チャートがすぐに赤のゾーンにドロップを開始する場合は、ドローダウンは、新しい最小値が表示されるたびに再計算されます。 この場合、最大利益はゼロで、i 番目および前のすべての要素のドローダウンは最大損失に対して再計算されます。 ここでドローダウンは 100% に等しくなります。 最大利益がゼロ (PL 曲線がチャートの正の部分に入る) の上に上がると、ドローダウンはさらに最大利益に対してのみ相対的に計算されます。

3つのチャートを比較して分析を行いましょう。 このメソッドは、単一の標準損益図の使用よりもはるかに多くの欠陥を検出することができます。 "買いとホールド " 戦略の PL チャートは、同じアルゴリズムに従って構築されています。 一例として1つのチャートのみを提供します。 他のものは、視覚化スクリプトの起動時に自動的に構築されます。

 PL  "買い、ホールド " 戦略

図は、 "買いホールド " 戦略に応じて同じボリュームと同じ資産を交換した場合、PL チャートはほとんどゼロになり、ドローダウンは約8万ルーブルになることを示しています。

PL 累積チャート

このチャートは、2つのヒストグラムを表します。 その構造体は、標準の PL チャートとは異なります。 利益ヒストグラムは、唯一の収益性の高いトレードの緩やかな累積によって作成されます。 i 番目のポジションが失われている場合は、値を無視し、前の値を i 番目の時間間隔に書き込みます。 負け取引のヒストグラムは鏡のロジックに従って造られます。 下記は、データに基づいた利益と損失のヒストグラムチャートです。

リアル PL ヒストグラム

1ロットトレードの PL ヒストグラム

通常の PL チャートは、損益ヒストグラムのシンプルな差です。 目をひく最初のものは、実際に得られた利益とトレードされたものとの間の大きな差です。 実質得られた利益は約 30% で1ロットトレードを上回り、ヒストグラムチャート分析はほぼ 50% の差を示しました。 利益の欠如の 20% は、利益の成長のダイナミクスの差からの損失は、第1および第2のチャートにあります。 この分析を説明しましょう。 ヒストグラムに基づいて2つの利益と損失のダイナミクスチャートを構築します。 式は非常に簡単です:

利益率式

プロフィットファクターダイナミクス


リアルプロフィット因子ダイナミクス


利益のダイナミクスは、損失に比べて、冒頭に成長していたことがわかります。 これは、理想的な開発です: それぞれの新しい取引では、負けトレードのヒストグラムから利益ヒストグラムの距離が増加します。 全体のトレードを通じて損失以上の利益がポジティブなダイナミクスな場合、最高の結果を得ます。 利益は、より迅速に蓄積され、損失は利益に関連して、同じまたは低いレートで増加しています。

チャートの次のセグメントは、利益と損失のヒストグラムの割合の差の増加がストップし、横方向のトレンドに移動し続けたことを示しています。 損失に対する利益の成長の横のトレンドが1つ上の間隔を有したら、またポジティブとして見られます。 間隔が1に等しい場合、PL 曲線はゼロに近づきます (それぞれの新しい利益は新しい損失に等しくなります)。 横の間隔が1を下回っている場合、資金を失い始めています。 言い換えれば、図は、利益率の緩やかな変化を視覚化しています。 これがその図です:

利益率に応じた PL ヒストグラム


利益率に応じた PL チャート


青色のヒストグラムは、損失の線形累積を示しています (スケール範囲は 0 ~ 100)。

このチャートは、利益率 (損失に対する利益の過剰を示す比率) が常に1より大きい必要があることを示しています。 理想的な開発は、PFが少しずつ成長することです。 この場合、PL チャートは指数関数的に大きくなります。 残念ながら、長期的には非現実的ですが、そのような状況は、各収益性の高いトレード後に多くを増やす場合は、短い幸運な期間で発生することができます。 この例に基づいて、トレードの主なポイントがPL チャートの変更する様子ではなく、収益性と損失の情報のヒストグラムがどのように動作するか、その結果、利益率の変化のダイナミクスがどうなっているかということを100%確認することができます。

さて、20% 失われた利益を考えてみましょう。 1ロットの利益成長ダイナミクスの図を参照してください: 利益の成長は、間隔 [1.4-1.6] でストップしました。 [1.2-1.4] よりも高くなっています。 時間の経過とともに、この差は、潜在的な利益の 20% になっています。 つまり、ポジションのサイズ管理はポジティブな結果を与えました。 マーチンゲールやアンチマーチンゲールなどを使用する場合、チャート、特にその基礎で計算されたメトリックは、分析の有用な情報の多くを提供することができます。 このチャートは、 get_PLHistogram関数によって作成されます。

日別損益

これまでストラテジーテスターでテストしたことがある人は、すでにこの図を知っています。 このヒストグラムの意味と構造体は同じです。 さらに、 (日によって利益と損失の総和によって得られる) 絶対値を使用してを構築する可能性を実装します。 単純平均化メソッドは、添付クラスで使用します。 他の平均法 (モード/中央値、加重平均) は、さらに興味深い結果を生むでしょう。 平均タイプはご自身で実装できます。

また、トレードの合計金額 (正と負) を追加: 日毎のトレードの数を示しています。 日による PL チャートとこのヒストグラムの組み合わせ分析は、1週間のコンテキストでより正確なトレードの画像をもたらします。 例えば、1日に50の小さい損失と3つの大きい利益を有し、大きい利益がすべての損失をカバーするとき状況の検出を可能にします。 絶対データとポジションの終値に基づいて構築された棒チャートの例を次に示します。

日別 PL


1日のトレード数


週のすべての日の図表はポジティブな取引が損失をカバーしたが、損失の取引の数が常に大きかったことを示します。 (一般に、この状態はアルゴリズムトレードに典型的です)。 また、負け取引の数は25%以上勝ち取引数より増加しなかったが、これは一般的です。

極値点と絶対値

極値の図は、2つのグループに分かれた4つ足のヒストグラムです。 極値点は、PL チャートの最大最小偏差 (最大達成利益と最大累積ドローダウン) です。 さらに2つの足は、最大収益性と損失の取引を示しています。 どちらのグループも、1つのトレードごとの損益データではなく、実際のトレードデータに基づいています。 PL 曲線上の最大利益の計算は、チャート上の最高点です。 最大ドローダウン計算メソッドは上で述べています。 ここに関連する式は次のとおりです。

最小最大

エクストリームポイントダイアグラム


この図は、損益の最大スプレッド(開き)を示しています。 最大の利益に比べて最大ドローダウンのシェアは 30% だった。 最も収益性の高いものに比べて最大の損失の取引の値は 60% だった。 このコードでは、指定された条件に従って PL 曲線データを段階的に比較するループとして実装します。

絶対値については、表形式で表すのが最適です。 また、データの2つのグループとして表されます: 最初の1つはすべての利益とすべての損失の合計の合計です。2番目のグループは、分析された履歴内の平均損益値です。

Total Average
Profit 323237 2244.701
Drawdown 261534 1210.806

簡単な PL チャートの要約と主なトレード結果とテーブル

このテーブルには、トレードパフォーマンスの数値特性が反映されます。 テーブル作成コードには、次の構造体が含まれます。

//+------------------------------------------------------------------+
//|トレード結果の構造体                                                 |
//+------------------------------------------------------------------+
struct TotalResult_struct
  {
   double            PL;                                //損益合計
   double            PL_to_Balance;                     //現在のバランスのPL率
   double            averagePL;                         //平均利益または損失
   double            averagePL_to_Balance;              //averagePL の収支比
   double            profitFactor;                      //利益率
   double            reciveryFactor;                    //リカバリーファクター
   double            winCoef                            //ペイオフファクター
   2重dealsInARow_to_reducePLTo_zerro;/* プラス利益なら、トレードの最大損失と行のトレードの数
                                                        現在のアカウトの利益をゼロにします。
                                                        負け取引なら、トレードの最大利益と行のトレードの数は、
                                                        ゼロにします。 */

   double            maxDrowDown_byPL;                  //PL に対する最大ドローダウン
   double            maxDrowDown_forDeal;               //取引ごとの最大ドローダウン
   double            maxDrowDown_inPercents;            //現在の残高のパーセンテージとしてのPL に対する最大ドローダウン
   datetime          maxDrowDown_byPL_DT;               //PL に対する最大ドローダウンの日付
   datetime          maxDrowDown_forDeal_DT             //取引ごとの最大ドローダウンの日付

   double            maxProfit_byPL;                    //PL の最大利益
   double            maxProfit_forDeal;                 //トレードごとの最大利益
   double            maxProfit_inPercents;              //現在の残高の割合としての PL の最大利益
   datetime          maxProfit_byPL_DT;                 //PL の最大利益の日付
   datetime          maxProfit_forDeal_DT;              //トレードごとの最大利益の日付
  };
//+------------------------------------------------------------------+
//| Part of the PL_detales structure (declared below)                |
//+------------------------------------------------------------------+
struct PL_detales_item
  {
   int               orders;                            //トレード件数
   double            orders_in_Percent;                 //オーダーの合計数に対する% としてのオーダー数
   int               dealsInARow;                       //行の情報
   double            totalResult;                       //入金通貨の合計結果
   double            averageResult;                     //資産通貨の平均結果
  };
//+-------------------------------------------------------------------+
//| A brief PL graph summary divided into 2 main blocks               |
//+-------------------------------------------------------------------+
struct PL_detales
  {
   PL_detales_item   profits;                           //有益な取引の情報
   PL_detales_item   loses;                             //負け取引の情報
  };

最初の構造体TotalResult_structは、リクエストされたトレード履歴全体のキー値の概要です。 必要な値 (トレードごとの損益など) と、計算されたトレードパフォーマンス係数が含まれます。

第2および第3構造体は相互に関係があります。 PL_detalesは、利益と損失のヒストグラムの簡単な要約を含む主な構造体です。 次の結果は分析されたヒストリーで得られました:

意味
PL 65039
PLからバランス 21,8986532
平均PL 180,1634349
平均PLからバランス 0,06066109
プロフィットファクター 1,25097242
リカバリーファクター 3,0838154
ペイオフレシオ 1,87645863
PL がゼロにダウンするまでの情報 24,16908213
PL に対するドローダウン -23683
1ロット取引あたりのドローダウン -2691
バランスに対するドローダウン -0,07974074
PL に対するドローダウンの日付 24.07.2017 13:04
1ロット取引あたりのドローダウンの日付 31.01.2017 21:53
PL の利益 73034
1ロットトレード当たり利益 11266
バランスに対する利益 0,24590572
PL の利益の日付 27.06.2017 23:42
1ロット取引あたりの利益の日付 14.12.2016 12:51

2番目の表は次のとおりです。

利益 損失
平均結果 2244.701 -1210,81
ラインの情報 5 10
トレードの総数 144 216
% の取引 0,398892 0,598338
合計結果: 323237 -261534

損失と収益性のポジションの分布は、ドーナツチャートとして表すことができます:

利益とドローダウンの%


この結果からわかるように、トレードの 40% がポジティブでした。

結論

アルゴリズムトレードにおいて、最適化するだけでは十分とは言えません。 ポートフォリオ構造体に合わせて調整することなく、最適化しただけでアルゴリズムを稼働させれば、予期しない結果をもたらす可能性があります。 もちろん、トレーダーらは、しばしばロシアンルーレットをしています。 しかし、未来のことをよく考える合理的なトレーダーも多くいます。 この記事で使用するヒストリー分析の技術はそのようなトレーダーにとって、興味深い内容を提供し、各トレードアルゴリズムに割り当てられる選ばれた加重の最適性をテストすることを可能にします。 

興味深いものの1つとしては、さまざまなポートフォリオの計算メソッドを分析し、利用可能なトレード履歴でテストし、新しいポートフォリオのパフォーマンスを実際の結果と比較することです。 この記事の最初の章で実際のトレード履歴に基づいて計算される1ロットのトレードを介して行うことができます。 ただし、このような計算で得られるデータは、資産の流動性、コミッション、および様々なフォースメジャーを考慮していないため、おおよそのものになることに注意してください。


次のファイルが記事に添付されています。

  1. トレード履歴(フォルダMQL5\Files\article_4803にある) を含むCSVファイル dealHistory.csv-この記事に記載されている例は、この履歴に基づいています。
  2. MQL5\Scripts\Get_TradigHistoryの下にあるMetaTrader5のソースファイル
補助ファイル:
    1. test_1 関数は、アタッチされたテスト履歴ファイルへのパスを1つのパラメータとして受け取り、2番目のパラメータとして [結果] タブへのパスを受け入れます。 この関数は、最初の関数パラメータとして渡されたテストファイルに関するレポートを生成します。
    2. 2番目の test_2 関数は、2番目のフォルダパス (パスは異なる必要があります) をパラメータとして受け取ります。 トレードに関するレポートがそのフォルダに保存されます。

主なファイル: