MQL5 クックブック:Expert Advisorsにトレード条件を設定するためのインディケータ利用
はじめに
本稿では、Expert Advisor は値がポジションオープンの条件を確認するのに使用されるインディケータを使って強化されます。それに一点添えるために、外部パラメータにドロップダウンリストを作成し、3つのトレードインディケータの中から1つを選ぶことができるようにします。
念のために以下を思い出してください。 MQL5 クックブックシリーズの先行記事をとおして作業をおこなってきているExpert Advisorの修正を続行します。Expert Advisor の最終バージョンは記事 "MQL5 Cookbook: The History of Deals And Function Library for Getting Position Properties"からダウンロードすることができます。
また、本稿ではトレード処理を行うことができるか否かを確認するために作成する関数を取り上げます。ポジションをオープンする関数は修正し、Expert Advisor がトレードモード(即時実行 と マーケット実行)を判断できるようにします。
先行記事で行われたすべての強化策や改善に続いて Expert Advisorのコードはすでに 1,500 行を越えているため、新しい機能が追加されるごとにそれは利便性が低下しています。そのため理論的なソリューションは個別のライブラリファイルとして複数のカテゴリーに分けられています。これで目標は設定できました。では始めましょう。
Expert Advisor の作成
Expert Advisor (*.mq5) のソースコードは先行記事から別のフォルダ TestIndicatorConditionsに入れ、そこにサブフォルダ Include を作成する必要があります。これはインクルードファイル (*.mqh)を作成するフォルダです。それらはMQL5 ウィザード (Ctrl+N) を用いて作成するか、標準テキストファイル (*.txt) として必要なディレクトリにマニュアルで作成し、のちに *.mqhと名前を付けなおすことができます。
以下が作成されるインクルードファイルすべての名前とコメントです。
- Enums.mqh はすべての列挙を持ちます。
- InfoPanel.mqh は情報パネルを設定し、グラフィックオブジェクトを作成および削除します。
- Errors.mqh はエラーコードと再初期化理由を返す関数すべてを扱います。
- TradeSignals.mqh は価格とインディケータ値を配列に書き込む関数、およびシグナルブロックを取り上げます。
- TradeFunctions.mqh はトレード関数を持ちます。
- ToString.mqh は数値を文字列値に変換する関数を取り扱います。
- Auxiliary.mqh はその他補助関数用に使用されます。
これらライブラリをメインのファイルにインクルードするには #include 命令を使用します。Expert Advisor のメインファイルとインクルードファイルフォルダ(Include)は同じフォルダにあるため、ファイルをインクルードするコードは以下のようなものとなります。
//--- Include custom libraries #include "Include\Enums.mqh" #include "Include\InfoPanel.mqh" #include "Include\Errors.mqh" #include "Include\TradeSignals.mqh" #include "Include\TradeFunctions.mqh" #include "Include\ToString.mqh" #include "Include\Auxiliary.mqh"
そうするとそれらを開き変更し、Expert Advisorのメインファイルからソースコードの一部を移動することができるようになります。
コードで正確に検索するには、Expert Advisor のメインファイルと同様に隣接したヘッダファイルへの参照が各ヘッダファイルに追加されます。たとえばわれわれのトレード関数のライブラリ TradeFunctions.mqhに対して、これは次のように記載されます。
//--- Connection with the main file of the Expert Advisor #include "..\TestIndicatorConditions.mq5" //--- Include custom libraries #include "Enums.mqh" #include "InfoPanel.mqh" #include "Errors.mqh" #include "TradeSignals.mqh" #include "ToString.mqh" #include "Auxiliary.mqh"
同一ネストレベルのファイルに対しては、ただ名前を指定するだけで十分です。上位レベルに行くにはパスのバックスラッシュの前にドットを2個入れる必要があります。
Enums.mqh ファイルのインディケータに列挙を追加します。説明のためにこの Expert Advisor では標準インディケータを2個(移動平均 および コモディティチャネル指数)とカスタムインディケータを1個(MultiRange_PCH)使用します。以下がその列挙です。
//--- Indicators enum ENUM_INDICATORS { MA = 0, // Moving Average CCI = 1, // CCI PCH = 2 // Price Channel };
外部パラメータは次のように変更されます。
//--- External parameters of the Expert Advisor sinput long MagicNumber=777; // Magic number sinput int Deviation=10; // Slippage input ENUM_INDICATORS Indicator=MA; // Indicator input int IndicatorPeriod=5; // Indicator period input int IndicatorSegments=2; // Number of one direction indicator segments input double Lot=0.1; // Lot input double VolumeIncrease=0.1; // Position volume increase input double VolumeIncreaseStep=10; // Step for volume increase input double StopLoss=50; // Stop Loss input double TakeProfit=100; // Take Profit input double TrailingStop=10; // Trailing Stop input bool Reverse=true; // Position reversal sinput bool ShowInfoPanel=true; // Display of the info panel
前述のようにインディケータパラメータのドロップダウンリスト内で3つのインディケータから1つを選択することが可能となります。
インディケータ期間が設定されているインディケータ-IndicatorPeriodに対してパラメータは1個だけ適用されます。Expert Advisor の前バージョンからのNumberOfBars パラメータは名前を付け替えて IndicatorSegments となり、ここではポジションオープンの条件を満たすように既定のインディケータが上下するバー番号を表記します。
外部パラメータをもう一つ追加します。VolumeIncreaseStepでこれはポイント内にボリュームインディケータに対するステップを設定するのに使用することができます。
AllowedNumberOfBars 変数(ここでは AllowedNumberOfSegments)の値はカスタム関数GetBarsData() 内で調整されていました。それは今は個別の関数に入れられ初期化のときのみ呼ばれます。
ポジションオープンの条件はここではインディケータ値を用いてチェックされるため、割り当てられるこの値は常に3以上となります。すなわち、外部変数 IndicatorSegments が値1に割り当てられると、 AllowedNumberOfSegments 変数が値3に割り当てられるのです。これは条件を満たすため完了バーのインディケータ値が前回バーよりも大きな値である必要があるためです。このため最後のインディケータ値3個を取得する必要があります。
以下はCorrectInputParameters() 関数コードです。
//+------------------------------------------------------------------+ //| Adjusting input parameters | //+------------------------------------------------------------------+ void CorrectInputParameters() { //--- Adjust the number of bars for the position opening condition if(AllowedNumberOfSegments<=0) { if(IndicatorSegments<=1) AllowedNumberOfSegments=3; // At least three bars are required if(IndicatorSegments>=5) AllowedNumberOfSegments=5; // but no more than 7 else AllowedNumberOfSegments=IndicatorSegments+1; // and always greater by two } }
インディケータを処理する前にトレードが許可されるか確認する関数-CheckTradingPermission()を作成します。関数内にリストアップされるあらゆる理由によりトレードが許可されるなら、値ゼロが返されます。これは次の試行が次のバーで行われる必要があることを意味します。
//+------------------------------------------------------------------+ //| Checking if trading is allowed | //+------------------------------------------------------------------+ bool CheckTradingPermission() { //--- For real-time mode if(IsRealtime()) { //--- Checking server connection if(!TerminalInfoInteger(TERMINAL_CONNECTED)) return(1); //--- Permission to trade at the running program level if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED)) return(2); //--- Permission to trade at the terminal level if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return(3); //--- Permission to trade for the current account if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)) return(4); //--- Permission to trade automatically for the current account if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT)) return(5); } //--- return(0); }
それでは本稿の主要ポイントに取り掛かりましょう。インディケータ値にアクセスするにはまずそのハンドルを取得する必要があります。これはインディケータ名の短縮形から取られる名前を持ち、前に記号 'i'がくる特殊関数を用いて行われます。
たとえば移動平均 インディケータには対応する関数 iMA()があります。MetaTrader 5ターミナルのすべての標準インディケータハンドルはこれら関数を用いて取得可能です。リストの完全版は テクニカルインディケータと名前のついた MQL5 参考資料で入手可能です。カスタムインディケータのハンドルを取得する必要がある場合は、iCustom() 関数を使用します。
Indicator パラメータで選択されるインディケータに応じて対応するインディケータのハンドル値がグローバル変数 indicator_handle に割り当てられる GetIndicatorHandle() 関数を実装します。関数コードはトレードシグナル関数のライブラリ(\Include\TradeSignals.mqh ファイル)にあります。またインディケータハンドルを伴う変数は Expert Advisorのメインファイルに入っています。
//+------------------------------------------------------------------+ //| Getting the indicator handle | //+------------------------------------------------------------------+ void GetIndicatorHandle() { //--- If the Moving Average indicator is selected if(Indicator==MA) indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE); //--- If the CCI indicator is selected if(Indicator==CCI) indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE); //--- If the MultiRange_PCH indicator is selected if(Indicator==PCH) indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod); //--- If the indicator handle could not be obtained if(indicator_handle==INVALID_HANDLE) Print("Failed to get the indicator handle!"); }
取得したインディケータハンドルを使用しその値を取得することができる関数GetDataIndicators() を作成します。これは記事"MQL5 Cookbook: Analyzing Position Properties in the MetaTrader 5 Strategy Tester"で考察された関数 CopyTime()、CopyClose()、 CopyOpen()、CopyHigh()、 CopyLow() を用いて値を取得するのと同様の方法で CopyBuffer() 関数をもちることで行います。
インディケータは複数のバッファ(値の行)を持つことができるため、バッファインデックスは2番目のパラメータとして CopyBuffer() 関数に渡されます。標準インディケータ用バッファインデックスは MQL5 参考資料にあります。カスタムインディケータについては、ソースコードが入手可能であれば、バッファインデックスはコードで確認できます。コードがない場合、実験によってストラテジーテスタの可視化モードで条件がどのように満たされているか観察しインデックスを見つける必要がります。
その前に、Expert Advisorのメインファイル内にインディケータバッファへの動的配列を作成する必要があります。
//--- Arrays for indicator values double indicator_buffer1[]; double indicator_buffer2[];
以下が GetIndicatorsData() のコードです。
//+------------------------------------------------------------------+ //| Getting indicator values | //+------------------------------------------------------------------+ bool GetIndicatorsData() { //--- If the indicator handle has been obtained if(indicator_handle!=INVALID_HANDLE) { //--- For the Moving Average or CCI indicator if(Indicator==MA || Indicator==CCI) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer1,true); //--- Get indicator values if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); return(false); } } //--- For the MultiRange_PCH indicator if(Indicator==PCH) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer1,true); ArraySetAsSeries(indicator_buffer2,true); //--- Get indicator values if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); return(false); } } //--- return(true); } //--- If the indicator handle has not been obtained, retry else GetIndicatorHandle(); //--- return(false); }
GetTradingSignal() 関数は実質上変更されています。ポジション不在の場合とポジションが存在する場合では条件は異なります。インディケータMoving Average および CCI に対しては条件は同じです。MultiRange_PCHに対しては、条件は個別のブロックに作成されます。コードを読みやすくし、冗長をなくすため、補助関数 GetSignal()を作成します。そのようなポジションが存在し、がイプパラメータによって適切な処理が許可されているなら、それはポジションオープンまたはクローズに対するシグナルを返します。
以下が GetSignal() 関数のコードです。
//+------------------------------------------------------------------+ //| Checking the condition and returning a signal | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE GetSignal() { //--- Check conditions for the Moving Average and CCI indicators if(Indicator==MA || Indicator==CCI) { //--- A Sell signal if(AllowedNumberOfSegments==3 && indicator_buffer1[1]<indicator_buffer1[2]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==4 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==5 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==6 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4] && indicator_buffer1[4]<indicator_buffer1[5]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments>=7 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4] && indicator_buffer1[4]<indicator_buffer1[5] && indicator_buffer1[5]<indicator_buffer1[6]) return(ORDER_TYPE_SELL); //--- A Buy signal if(AllowedNumberOfSegments==3 && indicator_buffer1[1]>indicator_buffer1[2]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==4 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==5 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==6 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4] && indicator_buffer1[4]>indicator_buffer1[5]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments>=7 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4] && indicator_buffer1[4]>indicator_buffer1[5] && indicator_buffer1[5]>indicator_buffer1[6]) return(ORDER_TYPE_BUY); } //--- Block that checks conditions for the MultiRange_PCH indicator if(Indicator==PCH) { //--- A Sell signal if(close_price[1]<indicator_buffer2[1] && open_price[1]>indicator_buffer2[1]) return(ORDER_TYPE_SELL); //--- A Buy signal if(close_price[1]>indicator_buffer1[1] && open_price[1]<indicator_buffer1[1]) return(ORDER_TYPE_BUY); } //--- No signal return(WRONG_VALUE); }
これで GetTradingSignal() 関数のコードは以下のようになります。
//+------------------------------------------------------------------+ //| Determining trading signals | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE GetTradingSignal() { //--- If there is no position if(!pos.exists) { //--- A Sell signal if(GetSignal()==ORDER_TYPE_SELL) return(ORDER_TYPE_SELL); //--- A Buy signal if(GetSignal()==ORDER_TYPE_BUY) return(ORDER_TYPE_BUY); } //--- If the position exists if(pos.exists) { //--- Get the position type GetPositionProperties(P_TYPE); //--- Get the last deal price GetPositionProperties(P_PRICE_LAST_DEAL); //--- Block that checks conditions for the Moving Average and CCI indicators if(Indicator==MA || Indicator==CCI) { //--- A Sell signal if(pos.type==POSITION_TYPE_BUY && GetSignal()==ORDER_TYPE_SELL) return(ORDER_TYPE_SELL); //--- if(pos.type==POSITION_TYPE_SELL && GetSignal()==ORDER_TYPE_SELL && close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_SELL); //--- A Buy signal if(pos.type==POSITION_TYPE_SELL && GetSignal()==ORDER_TYPE_BUY) return(ORDER_TYPE_BUY); //--- if(pos.type==POSITION_TYPE_BUY && GetSignal()==ORDER_TYPE_BUY && close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_BUY); } //--- Block that checks conditions for the MultiRange_PCH indicator if(Indicator==PCH) { //--- A Sell signal if(pos.type==POSITION_TYPE_BUY && close_price[1]<indicator_buffer2[1] && open_price[1]>indicator_buffer2[1]) return(ORDER_TYPE_SELL); //--- if(pos.type==POSITION_TYPE_SELL && close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_SELL); //--- A Buy signal if(pos.type==POSITION_TYPE_SELL && close_price[1]>indicator_buffer1[1] && open_price[1]<indicator_buffer1[1]) return(ORDER_TYPE_BUY); //--- if(pos.type==POSITION_TYPE_BUY && close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_BUY); } } //--- No signal return(WRONG_VALUE); }
ここではシンボルプロパティの一部であるモードInstant Execution および Market Execution を確認し、ポジションオープン関数OpenPosition() のコードを変更します。名前が自明であるモードもまた MQL5 参考資料で確認できます。
- 即時実行
- マーケット実行
Market Execution モードを処理するとき、レベルセットStop Loss と Take Profit ではポジションをオープンできないことを思い出してください。まずポジションをオープンし、それからレベル設定によってそれを変更する必要があります。
シンボルプロパティのストラクチャに実行モードを追加します。
//--- Symbol properties struct symbol_properties { int digits; // Number of decimal places in the price int spread; // Spread in points int stops_level; // Stops level double point; // Point value double ask; // Ask price double bid; // Bid price double volume_min; // Minimum volume for a deal double volume_max; // Maximum volume for a deal double volume_limit; // Maximum permissible volume for a position and orders in one direction double volume_step; // Minimum volume change step for a deal double offset; // Offset from the maximum possible price for a transaction double up_level; // Upper Stop level price double down_level; // Lower Stop level price ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode };
列挙 ENUM_SYMBOL_PROPERTIES を適切に変更する必要があります。
//--- Enumeration of position properties enum ENUM_SYMBOL_PROPERTIES { S_DIGITS = 0, S_SPREAD = 1, S_STOPSLEVEL = 2, S_POINT = 3, S_ASK = 4, S_BID = 5, S_VOLUME_MIN = 6, S_VOLUME_MAX = 7, S_VOLUME_LIMIT = 8, S_VOLUME_STEP = 9, S_FILTER = 10, S_UP_LEVEL = 11, S_DOWN_LEVEL = 12, S_EXECUTION_MODE = 13, S_ALL = 14 };
また GetSymbolProperties() 関数も変更します。
case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE); break; //--- case S_ALL : symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD); symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL); symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT); symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits); symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits); symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT); symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits); symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits); symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits); symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE); break; //---
結果 OpenPosition() 関数コードは以下のようになります。
//+------------------------------------------------------------------+ //| Opening a position | //+------------------------------------------------------------------+ void OpenPosition(double lot, ENUM_ORDER_TYPE order_type, double price, double sl, double tp, string comment) { //--- Set the magic number in the trading structure trade.SetExpertMagicNumber(MagicNumber); //--- Set the slippage in points trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); //--- The Instant Execution mode // A position can be opened with the Stop Loss and Take Profit levels set if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT) { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } //--- The Market Execution mode // First open a position and only then set the Stop Loss and Take Profit levels // *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening *** if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET) { //--- If there is no position, first open a position and then set Stop Loss and Take Profit if(!pos.exists) { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); //--- Get the flag of presence/absence of the position pos.exists=PositionSelect(_Symbol); //--- If the position exists if(pos.exists) { //--- Set Stop Loss and Take Profit if(!trade.PositionModify(_Symbol,sl,tp)) Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } } //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged else { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } } }
まだイベント処理関数に最後の重要な仕上げをする必要があります。
- OnInit
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Adjust the input parameters CorrectInputParameters(); //--- Get indicator handles GetIndicatorHandle(); //--- Initialize the new bar CheckNewBar(); //--- Get the properties GetPositionProperties(P_ALL); //--- Set the info panel SetInfoPanel(); //--- return(0); }
- OnDeinit
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Print the deinitialization reason to the journal Print(GetDeinitReasonText(reason)); //--- When deleting from the chart if(reason==REASON_REMOVE) { //--- Delete all objects relating to the info panel from the chart DeleteInfoPanel(); //--- Delete the indicator handle IndicatorRelease(indicator_handle); } }
- OnTick
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- If the bar is not new, exit if(!CheckNewBar()) { if(IsVisualMode() || IsRealtime()) { //--- Get the properties and update the values on the panel GetPositionProperties(P_ALL); //--- Set/update the info panel SetInfoPanel(); } return; } //--- If there is a new bar else { //--- If trading is allowed if(CheckTradingPermission()==0) { if(!GetIndicatorsData()) return; GetBarsData(); // Get bar data TradingBlock(); // Check the conditions and trade ModifyTrailingStop(); // Modify the Trailing Stop level } } //--- Get the properties GetPositionProperties(P_ALL); //--- Update the info panel SetInfoPanel(); }
これで関数はすべて準備完了。パラメータの最適化が可能です。メインのプログラムファイルからコードをコンパイルする必要があることを忘れないようにします。
パラメータの最適化と Expert Advisorの検証
「ストラテジーテスタ」は以下のように設定します。
図1 ストラテジーテスタ設定
それから最適化のために Expert Advisor のパラメータ設定を行います(添付にある設定を伴う *.set ファイルを参照ください)。
図2 Expert Advisor の設定
デュアルコアプロセッサでは最適化は約40分かかります。最適化チャートにより部分的に収益ゾーンの結果を基にしたトレーディングシステムのクオリティーを評価することができます。
図3 最適化チャート
以下は最大リカバリーファクタ検証結果です。
図4 最大リカバリーファクタ検証結果
おわりに
ダウンロード可能なExpert Advisorのソースコードを伴うアーカイブを本稿に添付しています。それを抽出したら、 \TestIndicatorConditions ファイルフォルダを <Metatrader 5 terminal>\MQL5\Expertsに入れる必要があります。Expert Advisorの正しい処理を確認するには、インディケータ MultiRange_PCH をだ論ロードし、<Metatrader 5 terminal>\MQL5\Indicatorsに入れる必要があります。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/645
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索