トレードシステムの評価 - 参入、退出と取引における一般の有効性
はじめに
トレードシステムの有効性を決定する多数の尺度がある;そして、トレーダーは気に入ったものを選んでいる。この記事は、S.V.Bulashev(ブラシェフ)による著作"Statistika dlya traderov"(トレーダーのための統計) に書かれているアプローチについて教えるものである。残念なことに、この本のコピー版は非常に少なく、そして長い間再版もされなかった;しかし、その電子版が多くのウェブサイトで入手可能である。
まえがき
この本は 2003 年に出版されたことを述べておく。そしてそれは MQL-II プログラム言語つきのMetaTrader 3 の頃であり、その当時進歩の途上にあった。そのため、トレード条件自体も最新のMetaTrader 5 クライアントターミナルと比較してその変化を辿ることができる。この本の著者は何世代にも渡るトレーダーの教祖になったことも知って頂きたい (この領域における世代交代が速いことを考慮すると)。しかし時は止まることが無い;この本に書かれた原理はいまだに適用できるが、そのアプローチは修正されるべきである。
S.V. ブラシェフは彼の本を、まず、当時の現実のトレード状況に基づいて書いた。このことが、この著者による統計の記述を変形なしには使えない理由である。明確にするため、当時のトレーディングを思い出そう:スポット市場でのマージン取引は投機的な利益を得るため、通貨を買うとしばらくしてそれを売ることになることを意味した。
これは基本であり、思い起こす価値があるものである。この解釈は「トレーダーのための統計」の本が書かれたときのものである。1ロットの各取引は同じ量の逆取引で終了(Close)しなければならなかった。しかし、(2005年に) そのような統計の使用は再構成が必要だった。その理由は取引の部分的終了がMetaTrader 4で可能となったからである。そのため、ブラシェフの記述した統計を使うためには、解釈のシステムを強化する必要がある。特に解釈は開始(Open)によってではなく終了の事実でされなければならない。
さらに次の5年間に状況は顕著に変わった。今や使い慣れた用語「オーダー」はどこにあるだろうか?完全に使われなくなってしまったようだ。このフォーラムでの質問の傾向を考慮して、MetaTrader 5での解釈システムをそのまま紹介することが良いだろう。
そのため、今日、古典的な用語「オーダー」はもはや無い。今日のオーダーは、ブローカーのサーバーへの取引要求であり、それはトレーダーあるいはMTS によって行われるトレードポジションの開始あるいは変更である。今ではそれはポジションであり;その意味を理解するためマージン取引を述べた。実際のところ、マージン取引がお金を借りる際実行され、ポジションはそのお金が存在する限り存在する。
借り手のアカウントをポジションを終了して清算し、そして損益を確定した結果後すぐにポジションは消滅する。ちなみに、この事実はなぜポジションの逆転がそれを終了させないのかの理由を説明している。実際、借金は残り、あなたがそれを買うためあるいは売るために借りたとしてもそこに違いは無い。取引は実行したオーダーの歴史である。
ここでトレーディングの機能について話そう。現在のところ、MetaTrader 5には、ポジショントレードを部分的に終了することも既存のものを増加させることもできる。こうして、ある額のポジションを開始すると同額で終了する解釈の古典的システムは、過去のものとなった。しかしMetaTrader 5に保存された情報から回復することは本当に不可能なのか?そこで、まず、解釈を再構成していく。
参入(Entering)の有効性
多くの人々がそのトレーディングを効果的に行いたいと望むのは確実である、しかし、どう(形式化)すればよいのか?取引は価格により成り立つ道だと仮定するなら、その道に2つの極端な点がある:すなわち観察部分での最小と最大価格。(買うときには)誰もができる限り最小値に近い市場に入ろうと殺到する。これはどのトレーディングでも中心的規則と考えてもよい:低い価格で買い、高い価格で売るというものだ。
参入の有効性はどれだけ最小に近く買うかである。言い換えると、参入の有効性は最大と参入の価格との距離の比である。なぜ最小から最大までの距離を測るのか?有効性を最小で参入すると1、最大で参入すると 0に等しくする必要がある。
これが最小と参入自体の間の距離でなく、残りの距離で比を求めるのかの理由である。売りの状況は買いの状況が反映されると指摘しなければならない。
参入ポジションの有効性はあるトレードの間、如何に MTS が参入の価格に相対的に有利な利益を実現したかを示すものである。次の式で計算される。
for long positions enter_efficiency=(max_price_trade-enter_price)/(max_price_trade-min_price_trade); for short positions enter_efficiency=(enter_price-min_price_trade)/(max_price_trade-min_price_trade); 参入の有効性は 0 からの範囲の値を持ち得る。
退出の有効性
退出の状況は同様である。
退出ポジションの有効性はあるトレードの間、如何に MTS が退出の価格に相対的に有利な利益を実現したかを示すものである。次の式で計算される。
for lone positions exit_efficiency=(exit_price - min_price_trade)/(max_price_trade - min_price_trade); for short positions exit_efficiency=(max_price_trade - exit_price)/(max_price_trade - min_price_trade); 退出の有効性は 0 から 1までの範囲内の値を取り得る。
トレードの有効性
全体として、トレードの有効性は参入と退出の両方で決定される。それはトレード中の参入と退出の最大距離(すなわち最小と最大の間の差)に対する比として計算される。 従って、トレードの有効性は2通りに計算される - トレードについての基本情報を直接用いた方法。あるいは前に評価した参入と退出の結果を用いた方法である(区間をずらして)。
トレードの有効性はあるトレードの間に如何によく MTS が全体の利益を実現したかを示すものである。それは次の式で計算される:
for long positions trade_efficiency=(exit_price-enter_price)/(max_price_trade-min_price_trade); for short positions trade_efficiency=(enter_price-exit_price)/(max_price_trade-min_price_trade); general formula trade_efficiency=enter_efficiency+exit_efficiency-1; トレードの有効性は -1 to 1の範囲内の値をとりえる。 トレードの有効性は 0.2 以上でなければならない。 有効性の解析は視覚的にシステムを強化する方向をを示す、なぜならポジションの参入と退出の信号の質を互いから分離して評価することが可能だからである。
解釈の変換
まず最初に、混乱を避けるため、解釈の対象の名前を明確にする必要がある。同じ用語 - オーダー, 取引(deal), ポジション がMetaTrader 5において用いられ、ブラシェフによると、それらを分離する必要がある。私の論説においては、ブラチェフの解釈の対象である「トレード」の名前を用いる、 すなわちトレードは取引である;彼はまた「オーダー」の用語をそれに用い、このような文脈ではこれらの用語は同じものである。ブラチェフは未完の取引をポジションと呼び、我々は未終了のトレードと呼ぶ。
ここでこれら3つの用語は全て簡単に1つの単語「トレード」に合わせられるのが分かる。我々はMetaTrader 5での解釈の名前の付け替えはしない、そしてこれらの3つの用語はクライアントターミナルの開発者によって設計されたのと同様の解釈に留める。結果として我々が使うのは4単語となる - ポジション、取引、オーダー そして トレードの4つである。
オーダーはポジションの開始/変更のサーバーへのコマンドであり、それは統計に直接には関与しない、それは直接には取引とはならないので (理由はオーダーを送ることは必ずしも対応する特定の額と価格の取引に対応する実行とはならないから)、統計をオーダーではなく取引で集めるのは正しい。
同じポジションの解釈の例を考察しよう(上記の説明を明確にするため):
interpretation in МТ-5 deal[ 0 ] in 0.1 sell 1.22218 2010.06.14 13:33 deal[ 1 ] in/out 0.2 buy 1.22261 2010.06.14 13:36 deal[ 2 ] in 0.1 buy 1.22337 2010.06.14 13:39 deal[ 3 ] out 0.2 sell 1.22310 2010.06.14 13:41
ブラチェフによる解釈 trade[ 0 ] in 0.1 sell 1.22218 2010.06.14 13:33 out 1.22261 2010.06.14 13:36 trade[ 1 ] in 0.1 buy 1.22261 2010.06.14 13:36 out 1.22310 2010.06.14 13:41 trade[ 2 ] in 0.1 buy 1.22337 2010.06.14 13:39 out 1.22310 2010.06.14 13:41
ここでこれらの取扱いが行われる方法を説明しよう。Deal[ 0 ] はポジションを開始し、それを新しい取引の始まりとする。
trade[ 0 ] in 0.1 sell 1.22218 2010.06.14 13:33
次にポジションの逆転が来る;これは前のトレードが全て閉じられるべきであることを意味する。従って、逆転に関する情報 deal[ 1 ] は終了と開始の両方でそして新トレードの開始で考慮される。イン/アウト取引の前に全ての閉じられていないトレードが一旦閉じられると、新しいトレードを開始(open)する必要がある。すなわち選択した終了の取引の 価格 と 時刻 の情報のみを使う、これはトレードの開始で タイプ と 額 が追加で使われるのと異なる。ここで新しい解釈で現れるまで使われていなかった用語を明確にしておく必要がある - それは 取引の方向である。前に "方向" と言うことで買いや売りを意味した、「タイプ」と言う用語も同じ意味を持っていた。これ以降 タイプ と方向は異なる用語である。
タイプ は買いあるいは売りであり、それにたいして 方向 はポジションの参入あるいは退出である。これがなぜポジションが常に イン 方向の取引で開始し、 アウト の取引で終了するのかの理由である。しかし方向はポジションの開始と終了のみに限られない。. この用語はまたポジションの額の増加 (もし「イン」取引がリストの最初に無い場合) とポジションの部分的終了 (「アウト」取引がリストの最後でない場合)も含む。部分終了が可能になったので、ポジションの逆転も導入するのは当然であり、現在のポジションより大きな額の反対取引が行われたとき逆転が起こる、これは イン/アウト 取引である。
そこで前に開始したトレードを終了した (ポジションを逆にするため):
trade[ 0 ] in 0.1 sell 1.22218 2010.06.14 13:33 out 1.22261 2010.06.14 13:36
残った額は 0.1 ロットであり、それは新しいトレードを開始するのに使われる。
trade[ 1 ] in 0.1 buy 1.22261 2010.06.14 13:36
そしてイン 方向でdeal[ 2 ] が来てもう一つのトレードを開く:
trade[ 2 ] in 0.1 buy 1.22337 2010.06.14 13:39
最後に、ポジションを終了する取引 - deal[ 3 ] がまだ終了していない全てのポジションのトレードを終了する。
trade[ 1 ] in 0.1 buy 1.22261 2010.06.14 13:36 out 1.22310 2010.06.14 13:41 trade[ 2 ] in 0.1 buy 1.22337 2010.06.14 13:39 out 1.22310 2010.06.14 13:41
上に述べた解釈はブラチェフが用いた解釈の要点を示し - 各開始トレードは一定の 参入(entry) ポイント とある 退出(exit)ポイント を持ち 額 と タイプを持つ。この解釈のシステムはあるニュアンス - 部分終了 - を考慮していない。よく見てみると、トレードの数は イン の取引 (イン/アウトを考慮) の数に等しいのが分かる 。このケースでは、 イン 取引で解釈する価値があるが、部分終了でより多くの アウト の取引がある だろう(インとアウトの取引の数が等しい状況もあるかもしれないが、それらは額においてお互いに対応しない)。
全ての アウト 取引を処理するには、 アウトの取引で解釈しなければならない。そしてこの矛盾は取引を別々に処理するならば(最初に - 全ての イン、そして全ての アウト 取引 ,あるいは逆順に)、解決できるようには見えない。しかし取引を順に処理し、各々に特別な処理を適用するならば、矛盾は無い。
ここに例を示す、ここでは アウト 取引の数が イン 取引の数より多い (説明付き):
МТ-5での解釈 deal[ 0 ] in 0.3 sell 1.22133 2010.06.15 08:00 deal[ 1 ] out 0.2 buy 1.22145 2010.06.15 08:01 deal[ 2 ] in/out 0.4 buy 1.22145 2010.06.15 08:02 deal[ 3 ] in/out 0.4 sell 1.22122 2010.06.15 08:03 deal[ 4 ] out 0.1 buy 1.2206 2010.06.15 08:06
ブラチェフによる解釈 trade[ 0 ] in 0.1 sell 1.22218 2010.06.14 13:33 out 1.22261 2010.06.14 13:36 trade[ 1 ] in 0.1 buy 1.22261 2010.06.14 13:36 out 1.22310 2010.06.14 13:41 trade[ 2 ] in 0.1 buy 1.22337 2010.06.14 13:39 out 1.22310 2010.06.14 13:41
終了取引が開始取引より後に現れ、しかし全数ではなく、その部分のみという状況がある (0.3 ロットが開始され 0.2が終了する)。そのような状況をどう扱うか?もし各取引が同じ額で終了するなら、状況は一つの取引での数トレードの開始と考えられる。そこで、それらは同じポイントの開始と異なったポイントの終了を持つ (各トレードの額は終了額で決定されるのは明らか) 例えば、処理のために deal[ 0 ] を選び、トレードを開始する:
trade[ 0 ] in 0.3 sell 1.22133 2010.06.15 08:00
そして deal[ 1 ] を選び、オープンなトレードを終了し、終了の間に終了額が十分でないことに気が付く。前の開始トレードのコピーを作り、そして「額(Volume)」のパラメーターに額の不足分を指定する。その後で最初のトレード を取引の額で終了する(すなわち最初のトレードの開始で指定した額を終了額に変える):
trade[ 0 ] in 0.2 sell 1.22133 2010.06.15 08:00 out 1.22145 2010.06.15 08:01 trade[ 1 ] in 0.1 sell 1.22133 2010.06.15 08:00
そうした変換は、トレーダーがこのトレードでなく、他のものを終了したいかもしれないので、トレーダーにとって適当でないと見えるかもしれない。とにかく、システムの評価は正しい変換の結果傷つかない。唯一つトレーダーのMetaTrader 4で損失無くトレードするという確信が傷つくかもしれない;再計算をするこのシステムはあらゆる妄想を起すかもしれない。
ブラチェフの本に書かれた統計的解釈のシステムは感情を持たず、参入、退出両方のレートのポジションからの決定を正直に評価することを可能にする。解釈の変換の可能性(あるものから他のものへデータを失うことなく) はMetaTrader 4のために開発されたMTSは MetaTrader 5 の解釈システムのために作り直せないということが間違っていることを証明する。解釈の変換で唯一失うものは別のオーダー (MetaTrader 4) に属する額かもしれない。しかし事実、もはやオーダーが (この用語の古い意味での) 計数されないとすると、それはトレーダーの主観的な見積りに過ぎない。
解釈の変換のためのコード
ここでコードの全ての部分をもっと詳細に見ていこう。変換に備えるのにOOP(オブジェクト指向プログラミング)の インヘリタンス(相続)の機能を必要とする。これが、慣れていない人に MQL5 User Guide を開けて理論を学ぶことを勧める理由である。まず最初に取引の解釈の 構造を説明する( これらの値を直接 MQL5 の標準ファンクションを用いて得るとコードを加速できるかもしれないが、それは読みづらく混乱するかも知れない)。
//+------------------------------------------------------------------+ //| structure of deal | //+------------------------------------------------------------------+ struct S_Stat_Deals { public: ulong DTicket; // ticket of deal ENUM_DEAL_TYPE deals_type; // type of deal ENUM_DEAL_ENTRY deals_entry; // direction of deal double deals_volume; // volume of deal double deals_price; // price of opening of deal datetime deals_date; // time of opening of deal S_Stat_Deals(){}; ~S_Stat_Deals(){}; };
この構造は取引の全ての核の部分の詳細を含んでいるが、派生された詳細は必要なら計算できるため含んでいない。開発者は既にブラチェフの多くのメソッドを戦略の試験に使っているため、カスタムなメソッドを補足するだけである。そのようなメソッドを全体的なトレードの有効性と開始と終了の有効性のために組み込むことにしよう。
これらの値を得るため、開始と終了の時刻、トレード期間中の最小と最大価格等の主要情報の解釈の組み込みを必要とする。そのような主要情報を持っていれば、多くの派生的情報も得ることができる。以下に説明するトレードの構造に注目いただきたい、これは核となる構造であり、全ての解釈の変換はこれに基づいている。
//+------------------------------------------------------------------+ //| structure of trade | //+------------------------------------------------------------------+ struct S_Stat_Trades { public: ulong OTicket; // ticket of opening deal ulong CTicket; // ticket of closing deal ENUM_DEAL_TYPE trade_type; // type of trade double trade_volume; // volume of trade double max_price_trade; // maximum price of trade double min_price_trade; // minimum price of trade double enter_price; // price of opening of trade datetime enter_date; // time of opening of trade double exit_price; // price of closing of trade/s22> datetime exit_date; // time of closing of trade double enter_efficiency;// effectiveness of entering double exit_efficiency; // effectiveness of exiting double trade_efficiency;// effectiveness of trade S_Stat_Trades(){}; ~S_Stat_Trades(){}; };
ここで2つの核となる構造を作成したので、新しいクラス C_Pos を定義することができ、それが解釈の変換をする。最初に、取引とトレードの解釈の構造へのポインターを定義しよう。相続されたファンクションでその情報が必要なので、それを publicと宣言し; 多くの取引とトレードがあるため、配列を構造へのポインターとして用いる。そのため、情報は構造化され、どの場所からでも使うことができる。
さて来歴を分離したポジションに分割しそしてポジション内の全ての変換を完全なトレードのサイクルとして実行する。これを行うため、 ポジションの属性 の解釈のための変数を宣言する(ポジションのid、ポジションのシンボル、取引の数、 トレードの数)。
//+------------------------------------------------------------------+ //| class for transforming deals into trades | //+------------------------------------------------------------------+ class C_Pos { public: S_Stat_Deals m_deals_stats[]; // structure of deals S_Stat_Trades m_trades_stats[]; // structure of trades long pos_id; // id of position string symbol; // symbol of position int count_deals; // number of deals int count_trades; // number of trades int trades_ends; // number of closed trades int DIGITS; // accuracy of minimum volume by the symbols of position C_Pos() { count_deals=0; count_trades=0; trades_ends=0; }; ~C_Pos(){}; void OnHistory(); // creation of history of position void OnHistoryTransform();// transformation of position history into the new system of interpretation void efficiency(); // calculation of effectiveness by Bulachev's method private: void open_pos(int c); void copy_pos(int x); void close_pos(int i,int c); double nd(double v){return(NormalizeDouble(v,DIGITS));};// normalization to minimum volume void DigitMinLots(); // accuracy of minimum volume double iHighest(string symbol_name,// symbol name ENUM_TIMEFRAMES timeframe, // period datetime start_time, // start date datetime stop_time // end date ); double iLowest(string symbol_name,// symbol name ENUM_TIMEFRAMES timeframe, // period datetime start_time, // start date datetime stop_time // end date ); };
このクラスはポジションを処理する3つのパブリックなメソッドを持っている。
OnHistory() はポジションの来歴を作成する://+------------------------------------------------------------------+ //| filling the structures of history deals | //+------------------------------------------------------------------+ void C_Pos::OnHistory() { ArrayResize(m_deals_stats,count_deals); for(int i=0;i<count_deals;i++) { m_deals_stats[i].DTicket=HistoryDealGetTicket(i); m_deals_stats[i].deals_type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(m_deals_stats[i].DTicket,DEAL_TYPE); // type of deal m_deals_stats[i].deals_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(m_deals_stats[i].DTicket,DEAL_ENTRY);// direction of deal m_deals_stats[i].deals_volume=HistoryDealGetDouble(m_deals_stats[i].DTicket,DEAL_VOLUME); // volume of deal m_deals_stats[i].deals_price=HistoryDealGetDouble(m_deals_stats[i].DTicket,DEAL_PRICE); // price of opening m_deals_stats[i].deals_date=(datetime)HistoryDealGetInteger(m_deals_stats[i].DTicket,DEAL_TIME); // time of opening } };
各取引に対してこのメソッドは構造のコピーを作成し、それを取引についての情報で埋める。これがまさに以前にそれなしでできると言ったときに意味したものであるが、これでより便利になるのだ (時間をマイクロ秒の単位で短縮したいならこれらの構造を等号のサインの右に置く行で置き換えることができる)。
OnHistoryTransform() はポジションの履歴を新しい解釈のシステムに変換する:
- 以前に如何にこの情報が変換されるかを説明したが、その例を考察しよう。変換のために取引の額の計算の精度の値を必要とし、 (min.volume);DigitMinLots() がこれを扱う;もしプログラマーがこのコードが他の条件下で実行されることがないと確信するなら、このパラメータはコンストラクターで指定することができ、このファンクションは飛ばしてもよい。
- 次に count_trades と trades_ends カウンターをゼロにする。その後、取引の解釈の構造のためにメモリーの再割り当てを行う。トレードの正確な数を知らないので、そのポジションの取引の数に従ってメモリーの再割り当てを行う。さらにそれ以上の取引がありそうであれば、再度数回にわたってメモリーの再割り当てを行う;しかし同時に多くの取引は十分なメモリーを持つだろうし、配列全部に対するメモリーの割り当ては計算時間を相当節約する。
必要なときこのメソッドを至るところで使うとよい;新しいオブジェクトの解釈が現れるたびに、メモリーの割り当てをする。必要なメモリーの量の正確な情報がないときには、概略値で割り当てを行う必要がある。いずれにしても、各ステップで全配列を再割り当てするより経済的である。
次に、取引が イン、 イン/アウト, アウト.であれば、3つのフィルターを用いてポジションの全ての取引をフィルターするループが来る: 特定の行動が各変形に対して組まれる。フィルターはシーケンシャルで、入れ子になっている。あるフィルターがfalseを戻すと、この場合にのみ次のフィルターをチェックする。このような構成は、必要のない行動がカットされるためリソースの面で経済的である。コードを読みやすくするため、クラスで private と宣言されているファンクションに多くの行動が取られる。とにかく、これらのファンクションは開発の間 public であるが、コードの他の部分で必要がないことが分かっている、そのためそれらは再度 private と宣言されている。これがOOPにおいて如何に簡単にデータ scope を扱えるかである。
そこで イン のフィルターで新しい取引が実行され (the open_pos() ファンクション)、 これがポインターの配列の大きさを1増やし取引の構造を対応するトレードの構造のフィールドにコピーする理由である。さらに、取引の構造は価格と時間にに2倍のフィールドを持つため、取引が始められたとき開始のフィールドだけが埋められ、未完成とカウントされる;これを count_trades と trades_endsの差で理解できる。これは最初カウンターにゼロの値を持つということである。取引が現れるとすぐに count_trades カウンターが1加えられ、取引が終了すると trades_ends counter is increasカウンターが1加えられる。こうして count_trades と trades_ends は任意の時にいくつのトレードが終了していないのかを教えることができる。
open_pos() ファンクションは簡単で、取引を開始し対応するカウンターを進めるだけであるが、他のファンクションはそう簡単ではない。 取引がイン タイプでないなら、それは イン/アウト あるいは アウトである。2つのケースで、まず、簡単に実行できるものを選ぶ (これは本質的なことではないが、実行の難しさの順でチェックを作成した)。
イン/アウト フィルターを処理するファンクションはオープンポジションを未終了取引で集計する (どの取引が終了していないかを count_trades と trades_endsの間の差を使って、いかにして知るかを既に述べた)。従って、与えられた取引で終了した額の総計を計算する (そして残りの額は現在の取引のタイプで再度開始される)。ここでこの取引は イン/アウト 方向でありその額は前に開始されているポジションの総額を越えないことを意味するので注意する必要がある。それがポジションと イン/アウト の取引の間の差を計算するのに 利にかなっている理由であり、再度開始すべき新トレードの額を知ることができる。
取引が アウト 方向であると、全てはさらに複雑になる。まず、ポジションの最後の取引は常に アウト 方向であり、例外を作らなければならない - もしそれが最後の取引であれば持っている全てを終了しなければならない。そうでないとき (通り引きが最後のものではない)、 2つの変形が可能である。取引が イン/アウトではなく アウト なので、変形は:最初の変形では額が開始時と全く同じであり、開始の取引の額は終了の取引の額と等しい;第2の変形ではそれらの額は同じではない。
最初の変形は終了で処理される。第2の変形は複雑で、さらに2つの変形があり得る:額がより大きい場合と額が開始のものより小さい場合。額がより大きい場合、次の取引を終了の額が開始の額に等しいかより少ないとなるよう終了する。もし額が次の全取引を終了する のに十分でないなら(額が少ない)、 部分的終了を意味する。ここで取引を新しい額 (前の操作の後残ったもの)で終了する必要がある が、 その前に失くした額でトレードのコピーを作る。そしてもちろん、カウンターを忘れてはいけない。
取引では、取引の再開始後、既に後ほどの部分的終了の取引の待ちがあるという状況もありえる。混乱を避けるため、終了の時系列を保つためこれらの全てを1つずらすべきである。
//+------------------------------------------------------------------+ //| transformation of deals into trades (engine classes) | //+------------------------------------------------------------------+ void C_Pos::OnHistoryTransform() { DigitMinLots();// fill the DIGITS value count_trades=0;trades_ends=0; ArrayResize(m_trades_stats,count_trades,count_deals); for(int c=0;c<count_deals;c++) { if(m_deals_stats[c].deals_entry==DEAL_ENTRY_IN) { open_pos(c); } else// else in { double POS=0; for(int i=trades_ends;i<count_trades;i++)POS+=m_trades_stats[i].trade_volume; if(m_deals_stats[c].deals_entry==DEAL_ENTRY_INOUT) { for(int i=trades_ends;i<count_trades;i++)close_pos(i,c); trades_ends=count_trades; open_pos(c); m_trades_stats[count_trades-1].trade_volume=m_deals_stats[c].deals_volume-POS; } else// else in/out { if(m_deals_stats[c].deals_entry==DEAL_ENTRY_OUT) { if(c==count_deals-1)// if it's the last deal { for(int i=trades_ends;i<count_trades;i++)close_pos(i,c); trades_ends=count_trades-1; } else// if it's not the last deal { double out_vol=nd(m_deals_stats[c].deals_volume); while(nd(out_vol)>0) { if(nd(out_vol)>=nd(m_trades_stats[trades_ends].trade_volume)) { close_pos(trades_ends,c); out_vol-=nd(m_trades_stats[trades_ends].trade_volume); trades_ends++; } else// if the remainder of closed position is less than the next trade { // move all trades forward by one count_trades++; ArrayResize(m_trades_stats,count_trades); for(int x=count_trades-1;x>trades_ends;x--)copy_pos(x); // open a copy with the volume equal to difference of the current position and the remainder m_trades_stats[trades_ends+1].trade_volume=nd(m_trades_stats[trades_ends].trade_volume-out_vol); // close the current trade with new volume, which is equal to remainder close_pos(trades_ends,c); m_trades_stats[trades_ends].trade_volume=nd(out_vol); out_vol=0; trades_ends++; } }// while(out_vol>0) }// if it's not the last deal }// if out }// else in/out }// else in } };
有効性の計算
解釈のシステムが変換されると、ブラチェフの方法論による取引の有効性を評価することができる。そのような評価に必要なファンクション は efficiency() メソッドにあり、 取引のストラクチャーを計算されたデータで埋めるのもそこで行われる。参入(Entering)と退出(Exit) の有効性は 0 から 1までで測られ、取引全体に対しては -1 から 1 までで測られる。
//+------------------------------------------------------------------+ //| calculation of effectiveness | //+------------------------------------------------------------------+ void C_Pos::efficiency() { for(int i=0;i<count_trades;i++) { m_trades_stats[i].max_price_trade=iHighest(symbol,PERIOD_M1,m_trades_stats[i].enter_date,m_trades_stats[i].exit_date); // maximal price of trade m_trades_stats[i].min_price_trade=iLowest(symbol,PERIOD_M1,m_trades_stats[i].enter_date,m_trades_stats[i].exit_date); // minimal price of trade double minimax=0; minimax=m_trades_stats[i].max_price_trade-m_trades_stats[i].min_price_trade;// difference between maximum and minimum if(minimax!=0)minimax=1.0/minimax; if(m_trades_stats[i].trade_type==DEAL_TYPE_BUY) { //Effectiveness of entering a position m_trades_stats[i].enter_efficiency=(m_trades_stats[i].max_price_trade-m_trades_stats[i].enter_price)*minimax; //Effectiveness of exiting from a position m_trades_stats[i].exit_efficiency=(m_trades_stats[i].exit_price-m_trades_stats[i].min_price_trade)*minimax; //Effectiveness of trade m_trades_stats[i].trade_efficiency=(m_trades_stats[i].exit_price-m_trades_stats[i].enter_price)*minimax; } else { if(m_trades_stats[i].trade_type==DEAL_TYPE_SELL) { //Effectiveness of entering a position m_trades_stats[i].enter_efficiency=(m_trades_stats[i].enter_price-m_trades_stats[i].min_price_trade)*minimax; //Effectiveness of exiting from a position m_trades_stats[i].exit_efficiency=(m_trades_stats[i].max_price_trade-m_trades_stats[i].exit_price)*minimax; //Effectiveness of trade m_trades_stats[i].trade_efficiency=(m_trades_stats[i].enter_price-m_trades_stats[i].exit_price)*minimax; } } } }
このメソッドは2つのプライベートメソッド iHighest() と iLowest() を用いる - それらは似ているが唯一の違いは要求されたデータとサーチファンクションが fmin あるいは fmaxである点である。
//+------------------------------------------------------------------+ //| searching maximum within the period start_time --> stop_time | //+------------------------------------------------------------------+ double C_Pos::iHighest(string symbol_name,// symbols name ENUM_TIMEFRAMES timeframe, // period datetime start_time, // start date datetime stop_time // end date ) { double buf[]; datetime start_t=(start_time/60)*60;// normalization of time of opening datetime stop_t=(stop_time/60+1)*60;// normaliztion of time of closing int period=CopyHigh(symbol_name,timeframe,start_t,stop_t,buf); double res=buf[0]; for(int i=1;i<period;i++) res=fmax(res,buf[i]); return(res); }
そのメソッドは2つの指定された日付の間の期間の最大値をサーチする。日付はファンクションに start_time と stop_time パラメーターとしてファンクションに渡される。取引の日付はファンクションに渡され、そしてトレードの要求は1分のバーの中間でも来るかもしれないので、デートを最近接バーの値に正規化するのはそのファンクションの中で行われる。同じことが iLowest()ファンクションでも行われる。開発したメソッド efficiency() で、ポジションについての全機能を持つが、ポジションそのものの取り扱いはない。これを全ての前のメソッドが使える新しいクラスを決めて扱うことにしよう; 言い換えれば、それをC_Posのデリバティブとして宣言する。
デリバティブ・クラス (エンジンクラス)
class C_PosStat:public C_Pos
統計情報を考慮するために、その新しいクラスに与えられる構造を作成する。
//+------------------------------------------------------------------+ //| structure of effectiveness | //+------------------------------------------------------------------+ struct S_efficiency { double enter_efficiency; // effectiveness of entering double exit_efficiency; // effectiveness of exiting double trade_efficiency; // effectiveness of trade S_efficiency() { enter_efficiency=0; exit_efficiency=0; trade_efficiency=0; }; ~S_efficiency(){}; };
そしてクラスそのものの本体:
//+------------------------------------------------------------------+ //| class of statistics of trade in whole | //+------------------------------------------------------------------+ class C_PosStat:public C_Pos { public: int PosTotal; // number of positions in history C_Pos pos[]; // array of pointers to positions int All_count_trades; // total number of trades in history S_efficiency trade[]; // array of pointers to the structure of effectiveness of entering, exiting and trades S_efficiency avg; // pointer to the structure of average value of effectiveness of entering, exiting and trades S_efficiency stdev; // pointer to the structure of standard deviation from // average value of effectiveness of entering, exiting and trades C_PosStat(){PosTotal=0;}; ~C_PosStat(){}; void OnPosStat(); // engine classes void OnTradesStat(); // gathering information about trades into the common array // functions of writing information to a file void WriteFileDeals(string folder="deals"); void WriteFileTrades(string folder="trades"); void WriteFileTrades_all(string folder="trades_all"); void WriteFileDealsHTML(string folder="deals"); void WriteFileDealsHTML2(string folder="deals"); void WriteFileTradesHTML(string folder="trades"); void WriteFileTradesHTML2(string folder="trades"); string enum_translit(ENUM_DEAL_ENTRY x,bool latin=true);// transformation of enumeration into string string enum_translit(ENUM_DEAL_TYPE x,bool latin=true); // transformation of enumeration into string (overloaded) private: S_efficiency AVG(int count); // arithmetical mean S_efficiency STDEV(const S_efficiency &mo,int count); // standard deviation S_efficiency add(const S_efficiency &a,const S_efficiency &b); //add S_efficiency take(const S_efficiency &a,const S_efficiency &b); //subtract S_efficiency multiply(const S_efficiency &a,const S_efficiency &b); //multiply S_efficiency divided(const S_efficiency &a,double b); //divide S_efficiency square_root(const S_efficiency &a); //square root string Head_style(string title); };
このクラスを終わりから始めに逆の方向で解析することを勧める。全ては取引とトレードの表をファイルに書くことで終わる。ファンクションのある行がこの目的のために書かれる (名前からお互いの目的を理解できる)。 ファンクションは取引とトレードについてのcvs レポート、また2つのタイプの html レポートを作成する (それらは見た目が異なるだけで、同じ内容を持っている)。
void WriteFileDeals(); // writing csv report on deals void WriteFileTrades(); // writing csv report on trade void WriteFileTrades_all(); // writing summary csv report of fitness functions void WriteFileDealsHTML2(); // writing html report on deals, 1 variant void WriteFileTradesHTML2();// writing html report on trades, 2 variant
enum_translit() ファンクションは enumerations の値を string タイプにしてログファイルに書き込む。private セクションは S_efficiency 構造の数個のファンクションを含んでいる。全てのファンクションは言語の不利な点を補い、構造にまさに算術操作を行う。これらのメソッドの組み込みに対する見解は多様なので、異なった方法でも実現できる。私は構造のフィールドに対する算術操作のメソッドとしてそれらを実現した。構造の各フィールドを個別のメソッドを使って処理する方がよいと言う人もいるかもしれない。総括すると、プログラマーの数だけの見解があるといえるだろう。将来このような操作を組み込みのメソッドを使って行う可能性がある。
AVG() メソッド は渡された配列の算術平均値を計算するものであるが、分布の全体像を示していない、これがもう一つの標準偏差を計算するメソッド STDEV() とともに提供されている理由である。OnTradesStat() ファンクションは有効性 (前に OnPosStat() で計算された)の値を得、それらを統計的メソッドで処理する。最後に、 クラスの主ファンクション OnPosStat().である。
このファンクションは詳細に検討されなければならない。それは2つの部分で構成されていて、簡単に分割できる。第1の部分は全てのポジションとその id の所有をサーチし、一時的な配列 id_pos に保存する。ステップごと: 利用できる来歴の全体を選択し、取引の数を計算し、取引処理のサイクルを走らせる。サイクル: 取引のタイプがバランスすれば、それを飛ばす (始めの取引を解釈する必要はない)、そうでなければポジションの id を変数に保存しサーチを実行する。もし同じ id が既にベースに存在すれば ( id_po 配列)、 次の取引に行き、そうでなければ id をベースに書く。このような方法で、全ての取引を処理すると配列が既存のポジションの id とポジションの数で埋められる。
long id_pos[];// auxiliary array for creating the history of positions if(HistorySelect(0,TimeCurrent())) { int HTD=HistoryDealsTotal(); ArrayResize(id_pos,PosTotal,HTD); for(int i=0;i<HTD;i++) { ulong DTicket=(ulong)HistoryDealGetTicket(i); if((ENUM_DEAL_TYPE)HistoryDealGetInteger(DTicket,DEAL_TYPE)==DEAL_TYPE_BALANCE) continue;// if it's a balance deal, skip it long id=HistoryDealGetInteger(DTicket,DEAL_POSITION_ID); bool present=false; // initial state, there's no such position for(int j=0;j<PosTotal;j++) { if(id==id_pos[j]){ present=true; break; } }// if such position already exists break if(!present)// write id as a new position appears { PosTotal++; ArrayResize(id_pos,PosTotal); id_pos[PosTotal-1]=id; } } } ArrayResize(pos,PosTotal);
第2の部分で、前に基本クラス C_Pos で説明した全てのメソッドを実現する。それはポジションを総なめにして対応するポジションを処理するメソッドを走らせる。そのメソッドの説明は以下のコード中に与えられる。
for(int p=0;p<PosTotal;p++) { if(HistorySelectByPosition(id_pos[p]))// select position { pos[p].pos_id=id_pos[p]; // assigned id of position to the corresponding field of the class C_Pos pos[p].count_deals=HistoryDealsTotal();// assign the number of deal in position to the field of the class C_Pos pos[p].symbol=HistoryDealGetString(HistoryDealGetTicket(0),DEAL_SYMBOL);// the same actions with symbol pos[p].OnHistory(); // start filling the structure sd with the history of position pos[p].OnHistoryTransform(); // transformation of interpretation, filling the structure st. pos[p].efficiency(); // calculation of the effectiveness of obtained data All_count_trades+=pos[p].count_trades;// save the number of trades for displaying the total number } }
クラスの呼び出し方法
これで、クラス全体を検討した。呼び出しの例を与えることが残されている。構成の可能性を保つため、1つのファンクションにこの呼び出しを明示的に宣言しなかった。さらに、必要に応じてクラスを強化することができ、新しいデータの統計処理のメソッドを組み込むことができる。ここにスクリプトからクラスのメソッドを呼び出す例がある:
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ #include <Bulaschev_Statistic.mqh> void OnStart() { C_PosStat start; start.OnPosStat(); start.OnTradesStat(); start.WriteFileDeals(); start.WriteFileTrades(); start.WriteFileTrades_all(); start.WriteFileDealsHTML2(); start.WriteFileTradesHTML2(); Print("cko tr ef=" ,start.stdev.trade_efficiency); Print("mo tr ef=" ,start.avg.trade_efficiency); Print("cko out ef=",start.stdev.exit_efficiency); Print("mo out ef=",start.avg.exit_efficiency); Print("cko in ef=" ,start.stdev.enter_efficiency); Print("mo in ef=" ,start.avg.enter_efficiency); }
このスクリプトは、データを Files\OnHistory ディレクトリーにあるファイルに書き込むファンクションの量に応じて、5つのレポートファイルを作成する。次の主ファンクションがここに示される - OnPosStat() と OnTradesStat()、それらは必要な全てのメソッドを呼び出すのに使われる。 スクリプトは全体のトレードの有効性として得られた値を印刷して終わる。それらの値は遺伝的最適化のために使われる。
最適化の間各々のレポートを書く必要はないので、エキスパートアドバイザーのクラスの呼び出しは少し異なって見える。まず、スクリプトとは違って、エキスパートアドバイザーはテスターで稼働させることができる。戦略テスターで稼働させるにはその特殊性を持たなくてはならない。最適化されたとき、OnTester() ファンクションにアクセスをし、 OnDeinit() ファンクションの実行の前にそれを実行する。こうして、変換の主メソッドの呼び出しは分離される。エキスパートアドバイザーのパラメーターの合わせのファンクションの改変の便宜のため、一覧表をクラスの一部としてでなくグローバルに宣言した。この一覧表はクラス C_PosStat のメソッドと同じシートにある。
//+------------------------------------------------------------------+ //| enumeration of fitness functions | //+------------------------------------------------------------------+ enum Enum_Efficiency { avg_enter_eff, stdev_enter_eff, avg_exit_eff, stdev_exit_eff, avg_trade_eff, stdev_trade_eff };
これはエキスパートアドバイザーのヘディングに追加されるべきものである。
#include <Bulaschev_Statistic.mqh> input Enum_Efficiency result=0;// Fitness function
ここで switch オペレーターを使って必要なパラメーターの受け渡しを記述するだけである。
//+------------------------------------------------------------------+ //| Expert optimization function | //+------------------------------------------------------------------+ double OnTester() { start.OnPosStat(); start.OnTradesStat(); double res; switch(result) { case 0: res=start.avg.enter_efficiency; break; case 1: res=-start.stdev.enter_efficiency; break; case 2: res=start.avg.exit_efficiency; break; case 3: res=-start.stdev.exit_efficiency; break; case 4: res=start.avg.trade_efficiency; break; case 5: res=-start.stdev.trade_efficiency; break; default : res=0; break; } return(res); }
OnTester() ファンクションがカスタムファンクションの最大化に使われている事実に注目していただきたい。 カスタムファンクションの最小値を見つける必要があれば、ファンクション自体に-1 を掛けて逆転させるのがよい。標準偏差の付いたこの例のように、偏差が小さいほどトレードの有効性の間の差は小さくなり、トレードの安定性は高くなる。これが標準偏差が最小であるべき理由である。これで、クラスメソッドの呼び出しを扱ったので、レポートをファイルに書くことを検討しよう。
前に、レポートを作成するクラスメソッドを説明した。ここで、どこでいつそれらを呼ぶべきかを見よう。レポートはエキスパートアドバイザーが単一の実行を立ち上げたときにのみ作成されるべきである。そうでないと、エキスパートアドバイザーは最適化モードでファイルを作成し;すなわち1つのファイルでなく、たくさんのファイルを作成することになる (もし異なる名前が毎回渡されると) あるいは1つ、ただし全てのランに同じ名前としその最後のもの、これは消される情報にリソースを無駄使いするので全く意味がない。
とにかく、最適化中はレポートを作成するべきではない。もし、多数の異なった名前を持ったファイルを得たなら、多分その大半を開けることもないだろう。第2の変形は直ちに消去される情報を得るためにリソースを無駄使いする。
これが最高の変形はフィルターを作ることである (Optimization[disabled] モードでレポートを始める)。こうして、HDD は見ることのないレポートで書き散らされることはない。さらに、最適化のスピードは増加する (ファイル操作が最も遅い操作であることは明確である); さらに、素早く必要なパラメーターを保ってそのレポートを得ることが可能である。実際、OnTester あるいは OnDeinit ファンクションの中でどこにフィルターを置いても問題はない。重要なのは、これがレポートを作成するクラスメソッドであり、変換を実行する主メソッドの後で呼び出されるべきである。私はフィルターコードを一杯にしないためにフィルターを OnDeinit() に置いた。
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(!(bool)MQL5InfoInteger(MQL5_OPTIMIZATION)) { start.WriteFileDeals(); // writing csv report on deals start.WriteFileTrades(); // writing csv report on trades start.WriteFileTrades_all(); // writing summary csv report on fitness functions start.WriteFileDealsHTML2(); // writing html report on deals start.WriteFileTradesHTML2();// writing html report on trades } } //+------------------------------------------------------------------+
メソッドを呼び出す順序は重要ではない。レポート作るために必要な全ては、OnPosStat と OnTradesStat メソッドの中に準備されている。また、レポートを書くために全てのメソッドを呼び出すか、そのいくつかだけかは問題とならず、それらの操作は個別であり;既にクラスに保存された情報の解釈である。
戦略テスターのチェック
戦略テスターの一回の稼働による結果は以下である。
移動平均統計のトレードレポート |
|||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
# | Ticket | type | volume | Open | Close | Price | Efficiency | ||||||
open | close | price | time | price | time | max | min | enter | exit | trade | |||
pos[0] | id 2 | EURUSD | |||||||||||
0 | 2 | 3 | buy | 0.1 | 1.37203 | 2010.03.15 13:00:00 | 1.37169 | 2010.03.15 14:00:00 | 1.37236 | 1.37063 | 0.19075 | 0.61272 | -0.19653 |
pos[1] | id 4 | EURUSD | |||||||||||
1 | 4 | 5 | sell | 0.1 | 1.35188 | 2010.03.23 08:00:00 | 1.35243 | 2010.03.23 10:00:00 | 1.35292 | 1.35025 | 0.61049 | 0.18352 | -0.20599 |
pos[2] | id 6 | EURUSD | |||||||||||
2 | 6 | 7 | sell | 0.1 | 1.35050 | 2010.03.23 12:00:00 | 1.35343 | 2010.03.23 16:00:00 | 1.35600 | 1.34755 | 0.34911 | 0.30414 | -0.34675 |
pos[3] | id 8 | EURUSD | |||||||||||
3 | 8 | 9 | sell | 0.1 | 1.35167 | 2010.03.23 18:00:00 | 1.33343 | 2010.03.26 05:00:00 | 1.35240 | 1.32671 | 0.97158 | 0.73842 | 0.71000 |
pos[4] | id 10 | EURUSD | |||||||||||
4 | 10 | 11 | sell | 0.1 | 1.34436 | 2010.03.30 16:00:00 | 1.33616 | 2010.04.08 23:00:00 | 1.35904 | 1.32821 | 0.52384 | 0.74213 | 0.26597 |
pos[5] | id 12 | EURUSD | |||||||||||
5 | 12 | 13 | buy | 0.1 | 1.35881 | 2010.04.13 08:00:00 | 1.35936 | 2010.04.15 10:00:00 | 1.36780 | 1.35463 | 0.68261 | 0.35915 | 0.04176 |
pos[6] | id 14 | EURUSD | |||||||||||
6 | 14 | 15 | sell | 0.1 | 1.34735 | 2010.04.20 04:00:00 | 1.34807 | 2010.04.20 10:00:00 | 1.34890 | 1.34492 | 0.61055 | 0.20854 | -0.18090 |
pos[7] | id 16 | EURUSD | |||||||||||
7 | 16 | 17 | sell | 0.1 | 1.34432 | 2010.04.20 18:00:00 | 1.33619 | 2010.04.23 17:00:00 | 1.34491 | 1.32016 | 0.97616 | 0.35232 | 0.32848 |
pos[8] | id 18 | EURUSD | |||||||||||
8 | 18 | 19 | sell | 0.1 | 1.33472 | 2010.04.27 10:00:00 | 1.32174 | 2010.04.29 05:00:00 | 1.33677 | 1.31141 | 0.91916 | 0.59267 | 0.51183 |
pos[9] | id 20 | EURUSD | |||||||||||
9 | 20 | 21 | sell | 0.1 | 1.32237 | 2010.05.03 04:00:00 | 1.27336 | 2010.05.07 20:00:00 | 1.32525 | 1.25270 | 0.96030 | 0.71523 | 0.67553 |
Effectiveness Report |
|||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Fitness Func | Average Value | Standard Deviation | |||||||||||
Enter | 0.68 | 0.26 | |||||||||||
Exit | 0.48 | 0.21 | |||||||||||
Trades | 0.16 | 0.37 |
そしてバランスのグラフは:
チャート上でカスタムファンクションの最適化は、取引額がより大きなパラメーターを選ぼうとしているわけでなく、長期間の取引でほぼ同じ利益を持つもの、すなわち分散の大きくないもの、を選んでいるのが明確に見てとれる。
Moving Averagesのコードはポジションの増額の機能あるいはその部分終了を含んでいないので、変換の結果は上記に述べたものに近いとは見えない。下に、特にテストコードのために開始したアカウントでスクリプトを立ち上げたもう一つの結果が見られる。
pos[286] | id 1019514 | EURUSD | |||||||||||
944 | 1092288 | 1092289 | buy | 0.1 | 1.26733 | 2010.07.08 21:14:49 | 1.26719 | 2010.07.08 21:14:57 | 1.26752 | 1.26703 | 0.38776 | 0.32653 | -0.28571 |
pos[287] | id 1019544 | EURUSD | |||||||||||
945 | 1092317 | 1092322 | sell | 0.2 | 1.26761 | 2010.07.08 21:21:14 | 1.26767 | 2010.07.08 21:22:29 | 1.26781 | 1.26749 | 0.37500 | 0.43750 | -0.18750 |
946 | 1092317 | 1092330 | sell | 0.2 | 1.26761 | 2010.07.08 21:21:14 | 1.26792 | 2010.07.08 21:24:05 | 1.26782 | 1.26749 | 0.36364 | -0.30303 | -0.93939 |
947 | 1092319 | 1092330 | sell | 0.3 | 1.26761 | 2010.07.08 21:21:37 | 1.26792 | 2010.07.08 21:24:05 | 1.26782 | 1.26749 | 0.36364 | -0.30303 | -0.93939 |
pos[288] | id 1019623 | EURUSD | |||||||||||
948 | 1092394 | 1092406 | buy | 0.1 | 1.26832 | 2010.07.08 21:36:43 | 1.26843 | 2010.07.08 21:37:38 | 1.26882 | 1.26813 | 0.72464 | 0.43478 | 0.15942 |
pos[289] | id 1019641 | EURUSD | |||||||||||
949 | 1092413 | 1092417 | buy | 0.1 | 1.26847 | 2010.07.08 21:38:19 | 1.26852 | 2010.07.08 21:38:51 | 1.26910 | 1.26829 | 0.77778 | 0.28395 | 0.06173 |
950 | 1092417 | 1092433 | sell | 0.1 | 1.26852 | 2010.07.08 21:38:51 | 1.26922 | 2010.07.08 21:39:58 | 1.26916 | 1.26829 | 0.26437 | -0.06897 | -0.80460 |
pos[290] | id 1150923 | EURUSD | |||||||||||
951 | 1226007 | 1226046 | buy | 0.2 | 1.31653 | 2010.08.05 16:06:20 | 1.31682 | 2010.08.05 16:10:53 | 1.31706 | 1.31611 | 0.55789 | 0.74737 | 0.30526 |
952 | 1226024 | 1226046 | buy | 0.3 | 1.31632 | 2010.08.05 16:08:31 | 1.31682 | 2010.08.05 16:10:53 | 1.31706 | 1.31611 | 0.77895 | 0.74737 | 0.52632 |
953 | 1226046 | 1226066 | sell | 0.1 | 1.31682 | 2010.08.05 16:10:53 | 1.31756 | 2010.08.05 16:12:49 | 1.31750 | 1.31647 | 0.33981 | -0.05825 | -0.71845 |
954 | 1226046 | 1226078 | sell | 0.2 | 1.31682 | 2010.08.05 16:10:53 | 1.31744 | 2010.08.05 16:15:16 | 1.31750 | 1.31647 | 0.33981 | 0.05825 | -0.60194 |
pos[291] | id 1155527 | EURUSD | |||||||||||
955 | 1230640 | 1232744 | sell | 0.1 | 1.31671 | 2010.08.06 13:52:11 | 1.32923 | 2010.08.06 17:39:50 | 1.33327 | 1.31648 | 0.01370 | 0.24062 | -0.74568 |
956 | 1231369 | 1232744 | sell | 0.1 | 1.32584 | 2010.08.06 14:54:53 | 1.32923 | 2010.08.06 17:39:50 | 1.33327 | 1.32518 | 0.08158 | 0.49938 | -0.41904 |
957 | 1231455 | 1232744 | sell | 0.1 | 1.32732 | 2010.08.06 14:58:13 | 1.32923 | 2010.08.06 17:39:50 | 1.33327 | 1.32539 | 0.24492 | 0.51269 | -0.24239 |
958 | 1231476 | 1232744 | sell | 0.1 | 1.32685 | 2010.08.06 14:59:47 | 1.32923 | 2010.08.06 17:39:50 | 1.33327 | 1.32539 | 0.18528 | 0.51269 | -0.30203 |
959 | 1231484 | 1232744 | sell | 0.2 | 1.32686 | 2010.08.06 15:00:20 | 1.32923 | 2010.08.06 17:39:50 | 1.33327 | 1.32539 | 0.18655 | 0.51269 | -0.30076 |
960 | 1231926 | 1232744 | sell | 0.4 | 1.33009 | 2010.08.06 15:57:32 | 1.32923 | 2010.08.06 17:39:50 | 1.33327 | 1.32806 | 0.38964 | 0.77543 | 0.16507 |
961 | 1232591 | 1232748 | sell | 0.4 | 1.33123 | 2010.08.06 17:11:29 | 1.32850 | 2010.08.06 17:40:40 | 1.33129 | 1.32806 | 0.98142 | 0.86378 | 0.84520 |
962 | 1232591 | 1232754 | sell | 0.4 | 1.33123 | 2010.08.06 17:11:29 | 1.32829 | 2010.08.06 17:42:14 | 1.33129 | 1.32796 | 0.98198 | 0.90090 | 0.88288 |
963 | 1232591 | 1232757 | sell | 0.2 | 1.33123 | 2010.08.06 17:11:29 | 1.32839 | 2010.08.06 17:43:15 | 1.33129 | 1.32796 | 0.98198 | 0.87087 | 0.85285 |
pos[292] | id 1167490 | EURUSD | |||||||||||
964 | 1242941 | 1243332 | sell | 0.1 | 1.31001 | 2010.08.10 15:54:51 | 1.30867 | 2010.08.10 17:17:51 | 1.31037 | 1.30742 | 0.87797 | 0.57627 | 0.45424 |
965 | 1242944 | 1243333 | sell | 0.1 | 1.30988 | 2010.08.10 15:55:03 | 1.30867 | 2010.08.10 17:17:55 | 1.31037 | 1.30742 | 0.83390 | 0.57627 | 0.41017 |
pos[293] | id 1291817 | EURUSD | |||||||||||
966 | 1367532 | 1367788 | sell | 0.4 | 1.28904 | 2010.09.06 00:24:01 | 1.28768 | 2010.09.06 02:53:21 | 1.28965 | 1.28710 | 0.76078 | 0.77255 | 0.53333 |
これが変換された情報がどのように見えるか示したものであり;読者に全てを 丹念に検討できるように(そして比較して理解できるように)した 、元の取引の履歴を別のファイルに保存した;これは多くのトレーダーが今はなくした履歴であり、彼らはそれをMetaTrader 4の [Results] セクションで見たものだった。
結論
結論として、私は開発者にエキスパートアドバイザーを最適化する可能性を加えることを勧めたい、それはカスタム可能なパラメーターに依るだけでなく、それを標準のものと組合せて作る可能性であり、それは他の最適化ファンクションで行ったものである。この論説を要約すると、基本のみを含んでいると言え、初期機能の可能性である;そして読者は自身のニーズに従ってクラスを強化できると期待する。成功を祈る!
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/137
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索