
トレーリングストップのパターンとマーケットの退出
はじめに
注文修正やクローッジングのアルゴリズムの開発者は、異なるメソッドから取得された結果をどのように比較するかという不滅の悩みに苦しみます。チェックのメカニズムは、よく知られています - それは、ストラテジーテスターです。しかし、注文のオープン/クローズにおいて等しくEAを動作させるにはどうすれば良いでしょうか?この記事は、トレーリングストップやマーケットの退出のための異なるアルゴリズムの結果を比較するためのプラットフォームを数学的に維持できる注文のオープンの繰り返しを提供するツールを紹介します。
もしマーケットへの参入、トレーリングストップ、マーケットの退出などの時間を独立して計算する複雑なEAをデバッギングしているのであれば、その他のものに比較される繰り返しパターンを取得することは不可能です。注文のオープンのためにかなり長いシグナルがある状況を想像してください。理想的には、その注文はオープンされる予定です。もし選択された方向が正しく、その価格が予期された方向に移動するのであれば、トレーリングストップは価格の変動に従って作動し始め、近くに配置されたストップは、利益を増やすことのできるかもしれない注文をかなり早い段階でクローズすることもあります。もしそのオープンのシグナルがその時に有効であれば、EAは新しい注文をクローズします。結果として、早いクローズの後にオープンされたいくつかの注文の結果と、特定の”正しい”注文の結果を比較しなければならなくなります。この状況を避けるため、以下を提示します。
問題の詳細
- 注文オープン・クローズパターンがチャートにマークされています。
- オープン・クローズ時間とトレードの方向(買い/売り)がファイルに保存されています。
- 準備されたファイルを読み込み、コマンドを実行するためのエキスパートアドバイザーが作成されます。
オープンのポイントがマーケット反転にて設定されなければなりません - 履歴ではかなり明確です。しかしながら、そのクロージングポイントは、価格が反対のリバーサルポイントに達した時ではなく、その後に選択される必要があります。ここでのタスクはトレーリングとマーケットの退出の最適化であり、”終わり”に向かうために不適切であってもいかなるアルゴリズムも使用する必要があることを忘れてはいけません。利益を修復できないのであれば、アルゴリズムを再稼動させるシグナルになる損失がみれるようになります。
上の図を見てください。その青色の線が正しい参入と退出を示しています。得たい最大の利益の計算のために用いられます。しかし、トレーリングテストのために青色の線に似たものを使用します。実際のトレーディングの本質を示しています;遅延とともに参入し、損得なしでクロージングします。
青色の線に沿って実行されるトレーディングでは、トレーリング後に三つの潜在的なストップを引き起こすポイントがあります。
- 現在の価格からの最小の距離での攻撃的なトレーリング
- 通常の”忍耐強い”トレーリング
- 最後の一滴まで絞る理想的なトレーリングの利益
加えて、”忍耐のない”トレーリングをあ、ポイント4の周りの区域で発生します。
理想的な区域をマークする方法を知ったので、残っていることはできる限りそれを便利なものにすることのみです。
マーキングツール
理想的な線をマークするチャートを促進するためスクリプトを準備しましょう。二つのスクリプト、TL_Buy、TL_Sellは、マーキング線を買い売りのためにそれぞれ作成しますl。Script TL_Writeは、Expert Advisor TL_Tradeが扱えるように作成された線を見て、それらの特徴をファイルに保存します。 script TL_Readは、作成されたファイルを読み込むことができ、それに基づいてすべての線を再形成します。これは、いくつかの新しい線を追加したり、既存のものを削除したり、いくつかの線を訂正するためには役に立ちます。
読み書きのスクリプトがそれらの線を扱えるように、すべての線を特定のルールに沿って名付けます。
- すべての線を同じプレフィックス(TL_).で名付けます。線を選択し、削除するためにそのプレフィックスを使用できます。
- そのプレフィックスは、オペレーションコードである1文字に続きます: B-buy, S-sell;
- 線の名前のオペレーションコードは、お互いの線を区別するために線の番号に続きます。
結果として、チャートにて以下のような名前の線を得るはずです: TL_B1 TL_B2, TL_S3, etc.
線を構築するスクリプトは、チャートに配置され、一致する線は配置ポイントに表示されます。トレーディングに必要な理想的な”青色の線”をマークするようにその終点を動かすことができます。そのチャートに貼り付けられた際、その読み書きスクリプトはファイル名が保存され読み込まれるようリクエストします。これは、例えば、異なる通貨ペアにおいて異なる線を用いることができるようにします。
そのスクリプトのコードはかなり明確で、必要なコメントが提供されています。そのため、それらのアルゴリズムの詳細はスキップするためにライブラリを用います - それらのコードからご覧になれます。
/**************************************************************** PATTERN TRADING: TL_Buy - creation of a new, pattern buying line Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua *****************************************************************/ #include <WinUser32.mqh> #define _prefix_ "TL_" int start() { int MaxNo=0,i,No; if(WindowOnDropped()!=0) { MessageBox("Script should be dropped in the main window","ERROR", IDOK + MB_ICONERROR); return(1); } // find the maximum suffix number for all lines for(i=0;i<ObjectsTotal();i++) { if(StringFind(ObjectName(i),_prefix_)==0) { No=StrToInteger(StringSubstr(ObjectName(i),StringLen(_prefix_)+1)); // select the line number if(MaxNo<No) MaxNo=No; // store it, if it is larger } } datetime t0=WindowTimeOnDropped(); double p0=WindowPriceOnDropped(); // find the coordinates of the script dropping point int width = 5*Period()*60; // width of the created line in bars converted into time units double height = 20*MarketInfo(Symbol(),MODE_TICKSIZE); // height of the created line in ticks converted into price units string LineName = _prefix_+"B"+(MaxNo+1); // create a name for a new line ObjectCreate(LineName,OBJ_TREND,0,t0-width,p0-height, t0+width,p0+height); // create a line ObjectSet(LineName,OBJPROP_RAY,False); // make it a section, not a ray ObjectSet(LineName,OBJPROP_WIDTH,2); // set its width ObjectSet(LineName,OBJPROP_COLOR,Blue); // set its color }
/**************************************************************** PATTERN TRADING: TL_Sell - creation of a new, pattern selling line Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua *****************************************************************/ #include <WinUser32.mqh> #define _prefix_ "TL_" int start() { int MaxNo=0,i,No; if(WindowOnDropped()!=0) { MessageBox("Script should be dropped in the main window","ERROR", IDOK + MB_ICONERROR); return(1); } // find the maximum suffix number for all lines for(i=0;i<ObjectsTotal();i++) { if(StringFind(ObjectName(i),_prefix_)==0) { No=StrToInteger(StringSubstr(ObjectName(i),StringLen(_prefix_)+1)); // select the line number if(MaxNo<No) MaxNo=No; // store it, if it is larger } } datetime t0=WindowTimeOnDropped(); double p0=WindowPriceOnDropped(); // find the coordinates of the script dropping point int width = 5*Period()*60; // width of the created line in bars converted into time units double height = 20*MarketInfo(Symbol(),MODE_TICKSIZE); // height of the created line in ticks converted into price units string LineName = _prefix_+"S"+(MaxNo+1); // create a name for a new line ObjectCreate(LineName,OBJ_TREND,0,t0-width,p0+height, t0+width,p0-height); // create a line ObjectSet(LineName,OBJPROP_RAY,False); // make it a section, not a ray ObjectSet(LineName,OBJPROP_WIDTH,2); // set its width ObjectSet(LineName,OBJPROP_COLOR,Red); // set its color }
/**************************************************************** PATTERN TRADING: TL_Write - saving the coordinates of pattern lines in a file Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua *****************************************************************/ #include <WinUser32.mqh> #define _prefix_ "TL_" #property show_inputs extern string FileNameForWrite = "TL_DATA.TXT"; int start() { int LinesCNT=0,i; string Operation; double p; datetime t; int fh=FileOpen(FileNameForWrite,FILE_CSV|FILE_WRITE,';'); // look through all lines created and save the opening commands for the EA from them for(i=0;i<ObjectsTotal();i++) { if(StringFind(ObjectName(i),_prefix_)==0) // our line { string LineName = ObjectName(i); datetime t1=ObjectGet(LineName,OBJPROP_TIME1); datetime t2=ObjectGet(LineName,OBJPROP_TIME2); double p1=ObjectGet(LineName,OBJPROP_PRICE1); double p2=ObjectGet(LineName,OBJPROP_PRICE2); LinesCNT++; // increase the counter for producing the final message Operation = StringSubstr(ObjectName(i),StringLen(_prefix_),1); // prices are necessary only for restoring the line in the chart FileWrite(fh,Operation,TimeToStr(t1),DoubleToStr(p1,Digits),TimeToStr(t2),DoubleToStr(p2,Digits)); } } FileClose(fh); MessageBox("Stored sections "+(LinesCNT)+" pcs.","Done", IDOK + MB_ICONINFORMATION); }
/**************************************************************** PATTERN TRADING: TL_Read - drawing pattern lines from the file Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua *****************************************************************/ #include <WinUser32.mqh> #define _prefix_ "TL_" #property show_inputs extern string FileNameForRead = "TL_DATA.TXT"; int start() { int LinesCNT=0,i; int fh=FileOpen(FileNameForRead,FILE_CSV|FILE_READ,';'); if(fh<0) { MessageBox("Error opening file \"" + FileNameForRead + "\"","ERROR", IDOK + MB_ICONERROR); return(1); } // first of all, delete everything for(i=0;i<ObjectsTotal();i++) { if(StringFind(ObjectName(i),_prefix_)==0) { ObjectDelete(ObjectName(i)); i--; } } // look through all lines created and save the opening commands for the EA from them while(true) { string Operation=FileReadString(fh); if(FileIsEnding(fh)) break; // file ended? - exit // read the section's coordinates datetime t1=StrToTime(FileReadString(fh)); double p1=StrToDouble(FileReadString(fh)); datetime t2=StrToTime(FileReadString(fh)); double p2=StrToDouble(FileReadString(fh)); // draw a section LinesCNT++; string LineName = _prefix_+Operation+(LinesCNT); // create a name for a new line ObjectCreate(LineName,OBJ_TREND,0,t1,p1, t2,p2); // create a line ObjectSet(LineName,OBJPROP_RAY,False); // make it a section, not a ray ObjectSet(LineName,OBJPROP_WIDTH,2); // set its width if(Operation=="B") ObjectSet(LineName,OBJPROP_COLOR,Blue); else ObjectSet(LineName,OBJPROP_COLOR,Red);// set its color } FileClose(fh); MessageBox("Read sections "+(LinesCNT)+" pcs.","Done", IDOK + MB_ICONINFORMATION); }
/**************************************************************** PATTERN TRADING: TL_Clear - deletion of all pattern lines Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua *****************************************************************/ #include <WinUser32.mqh> #define _prefix_ "TL_" int start() { int LinesCNT=0,i; for(i=0;i<ObjectsTotal();i++) { if(StringFind(ObjectName(i),_prefix_)==0) { ObjectDelete(ObjectName(i)); i--; LinesCNT++; } } }
ファイルの配置
ファイルの配置はとても重要なポイントです。標準の手段を用いると、そのスクリプトはディレクトリ c:\Program Files\MetaTrader 4\experts\filesにしかファイルを作成できません。しかし、エキスパートアドバイザーをテストする際、テスターはc:\Program Files\MetaTrader 4\tester\files.に1する同じ名前のフォルダへのアクセス権があります。
そのため、ファイルの作成後、EAのテストでそれらを用いる前にc:\Program Files\MetaTrader 4\experts\filesからコピーし、c:\Program Files\MetaTrader 4\tester\filesに保存する必要があります。
コードを変更しファイルを再度作成した後はこの処理を繰り返す必要があります。
EAのテスト
EAのテストは、コードにおいて何も難しい点はありません。以下のブロックはEAのテストにて強調されています。
- パターン選択の終わりに達した際の注文クロージングブロック
- パターン選択の始まりに達した際の注文オープンブロック
- トレーリングストップをテストし、マーケットの退出のためのブロック
それらはソースコードにおいてかなり明確です。いくつかのコメントがこちらに記述されています。
- そのコードはどの特定の注文においても作成されないので、その全ての行はテスターの各ティックごとにオープン/クローズに必要な行を見つけるためにテストされます。
- オープン・クロージング時間は、日付の内部フォーマットにてその注文のコメントに記述されています。これは、もしそのパターンの線の終わり以前に前もってトレーリングによってクローズされた場合に同じ注文を何回もオープンしないために必要です。さらに、オープンの注文をチェックし、コメントからそのクロージング時間を取得する際に、クロージング時刻はそのオープンの注文に記述されているため、その操作の行が終了した時間に注文をクローズします。
- パラメーター ProcedTrailing は、トレーリングの処理を稼動/停止させます。これにより、取得された最適化の結果と比較するための最も悲惨な結果を得れるようトレーリングなしのEAを渡すことができます。
/**************************************************************** PATTERN TRADING: TL_Trader - trading on pattern lines Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua *****************************************************************/ #include <WinUser32.mqh> #define _prefix_ "TL_" extern string FileNameForRead = "TL_DATA.TXT"; extern double Lots = 0.1; extern double StopLoss = 0; extern double TrailingStop = 30; extern bool ProcedTrailing=true; // process the trailing block double SL; // to calculate the SL values for opening an order int start() { int LinesCNT=0,i,ticket,pos; double p; datetime t; string s; int fh=FileOpen(FileNameForRead,FILE_CSV|FILE_READ,';'); // to test the file, it is necessary to pout it into tester\files\TL_DATA.txt if(fh<0) { MessageBox("Error opening file \"" + FileNameForRead + "\"","ERROR", IDOK + MB_ICONERROR); return(1); } // check all entries: if the opening time has already passed and no order with such a comment is found in history or in open orders // then it has not been opened yet - open it as it's said there while(true) { string Operation=FileReadString(fh); if(FileIsEnding(fh)) break; // file ended? - exit // count the section coordinates string st1=FileReadString(fh); string sp1=FileReadString(fh); string st2=FileReadString(fh); string sp2=FileReadString(fh); datetime t1=StrToTime(st1); double p1=StrToDouble(sp1); datetime t2=StrToTime(st2); double p2=StrToDouble(sp2); // what if sections' ends are mixed? if(t1>t2) { p=p1; p1=p2; p2=p; t=t1; t1=t2; t2=t; s=st1; st1=st2; st2=s; s=sp1; sp1=sp2; sp2=s; } string MarkComent = t1+"="+t2; //********************************************************************************** // 1) block closing the orders as soon as the end of the pattern section is reached. //********************************************************************************** for(i=0;i<OrdersTotal();i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) continue; if(OrderComment()==MarkComent && TimeCurrent()>=t2) // order must be closed { if(OrderType()==OP_BUY) OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position else OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position } } //********************************************************************************** // 2) block opening orders as soon as the beginning of the pattern section is passed. //********************************************************************************** bool OrderNotPresent=true; // a sign showing that we haven't opened such an order yet if(t1<=TimeCurrent() && TimeCurrent()<t2) // time to open - make sure that this order is not opened or closed { for(i=0;i<OrdersTotal();i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) continue; if(OrderComment()==MarkComent) { OrderNotPresent=false; break; } // order already exists } for(i=0;i<OrdersHistoryTotal() && OrderNotPresent;i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) continue; // order in history is added to the end, something like "[sl]" - it must be cut off!! pos = StringFind(OrderComment(),"["); string CurOrderComment = StringSubstr(OrderComment(),0,pos); if(CurOrderComment==MarkComent) { OrderNotPresent=false; break; } // order already exists } if(OrderNotPresent) // no such order - open it { // open an order if(Operation=="B") // Buy { if(StopLoss<=0) SL=0; else SL=Ask-StopLoss*Point; ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,SL,0,MarkComent,1235,0,Blue); OrderSelect(ticket,SELECT_BY_TICKET); } else // Sell { if(StopLoss<=0) SL=0; else SL=Bid+StopLoss*Point; ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,SL,0,MarkComent,1235,0,Red); OrderSelect(ticket,SELECT_BY_TICKET); } } } } FileClose(fh); //****************************************************** // 3) block testing trailing stop and exit the market //****************************************************** if(ProcedTrailing) { for(i=0;i<OrdersTotal();i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) continue; if(OrderType()==OP_BUY) { if(Bid-OrderOpenPrice()>Point*TrailingStop) { if(OrderStopLoss()<Bid-Point*TrailingStop) { OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green); return(0); } } } if(OrderType()==OP_SELL) { if((OrderOpenPrice()-Ask)>(Point*TrailingStop)) { if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0)) { OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red); return(0); } } } } } return(0); }
How the System Works When "Fully Integrated"
To test the system, we used a microset of 14 lines. Below is the content of the pattern file named TL_DATA.txt:
B;2007.12.28 05:00;1.4605;2008.01.09 22:00;1.4658 B;2008.01.29 05:00;1.4767;2008.02.05 05:00;1.4811 B;2008.02.15 16:00;1.4687;2008.02.21 09:00;1.4735 B;2008.02.21 14:00;1.4738;2008.02.26 07:00;1.4812 B;2008.02.28 14:00;1.5129;2008.03.05 12:00;1.5186 B;2008.03.05 22:00;1.5261;2008.03.11 20:00;1.5316 B;2008.03.13 01:00;1.5539;2008.03.18 22:00;1.5620 B;2008.03.26 14:00;1.5724;2008.03.28 10:00;1.5758 S;2007.11.30 13:00;1.4761;2007.12.10 22:00;1.4711 S;2007.12.14 04:00;1.4626;2007.12.28 00:00;1.4610 S;2008.01.17 17:00;1.4688;2008.01.24 13:00;1.4671 S;2008.02.07 12:00;1.4633;2008.02.14 11:00;1.4617 S;2008.03.19 23:00;1.5641;2008.03.25 23:00;1.5629 S;2008.03.31 19:00;1.5811;2008.04.08 04:00;1.5796
以下でチャートでどのようになるのか示されています:
最も高価的なトレーディングではなく、トレーリングをテストするための理想的な基礎;)
もしトレーリングストップが停止(ProcedTrailing=false)された状態でテスターを開始すれば、以下のような貧しい結果を取得します:
トレーリングストップのサイズによるシンプルな最適かは95ポイントの最適化の値を提供します。
最大の利益を生む最適化の値は、テスト下でのその期間でのバーサイズの統計と同調しています:95ポイントはこの期間のバーの98%を作成し、ft.BarStat indicatorのチャートにて明らかです。
ご覧の通り、最適化された結果はより魅力的に移ります。
チャートにてよりはっきりとわかります。すべての注文はパターンの行の最初に正確にオープンされます!
そのまさに最初のセクションを見てください(3月, 5)その利益は、ダウンスパイクにより吹き飛びますが、買いトレンドは依然同じです。もし通常のEAでトレーリングをテストすれば、二つ目の線の終わりまで維持する買いポジションをオープンするでしょう。その場合、 比較のできない結果取得しています。2番目のケースで取得された利益は、 トレーリングストップのメカニズムではなく、繰り返される新規注文のオープンに由来します。. しかし、問題は、最大の利益を得ることではなく、できる限り効果的なトレーリングストップメカニズムを得ることです。すべての注文が同時にオープンされ、長い間維持されないことが重要です。しかし、この場合、最適化による利益の増加は、トレーリングアルゴリズムの効果を反映しています。
まとめ
この記事に関する議論はまだ私が扱えていないことの悪口に向かっていないことを願います - また、ここで記されているように読者の皆様が提案されたその調査アルゴリズムの使用方法を便利だと思ってもらえることを願っています。この記事は、私が本格的に取り組んだツールを紹介しています。長い間温めていたアイディアが明確になり、MQL4コードとして実現されました。そのツールが作成された目的である調査を行うことができませんでした。そのため、この記事は様々なトレーリングアルゴリズムの比較分析を提供できませんでした - 近い将来それについて取り組み、またこの記事の第2部を公開したいと思います。ただ、この記事はMQL4 Communityにとっては役に立っているようです。
このツールに関して執筆しようと思ったもう一つの理由は、私がプロのプログラマーであり、未熟なトレーダーであるためです。MQL4コードをできる限りシンプルにすることができますが、私がプログラミングに精通しているのと同じほどに専門的な知識を持つトレーダーのみとでしか、効果的なトレーディング戦略やトレーリングアルゴリズムを開発できません。そのため、Forex "guild fellows"の方々とコミュニケーションをとることに興味があり、そのツールを実際のトレーディングに使用できる状態まで引き上げるよう協力したいと思っています。私に協力していただける方は、my profileから連絡してください。
さらなる開発として、一つのチャートで同時にいくつかのトレーリングアルゴリズムをテストできます。パターン選択の初めに、いくつかの注文をオープンし、それぞれがそのアルゴリズムに従ってトレーリングストップされます。お互いに重なり合った図を得ることができるはずです。量と質によって結果を分析し、どのアルゴリズムがより正確にその機能を満たすかを見ることができます。しかし、トレーリングの代替物によって注文を区別するようEAを訓練する必要はありますが、この問題は解決可能です。
ところで、これらのメソッドは参入と退出の戦術両方を比較するために利用できます。このために、いくつか異なるコードを準備し、メソッドに沿って注文をオープンするポイントができる限りチャートのパターンオープンポイントに近くなるようにしなければなりません。しかし、これはまた個別の研究課題であり、他の記事で執筆する必要がありそうです。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1527



- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索