私たちのファンページに参加してください
- ビュー:
- 4109
- 評価:
- パブリッシュ済み:
- 2015.11.26 13:11
- アップデート済み:
- 2018.06.04 17:57
-
このコードに基づいたロボットまたはインジケーターが必要なら、フリーランスでご注文ください フリーランスに移動
移動平均EAは MetaTrader 5 に標準装備されています。また、Moving Averageを使ったEAのサンプルでもあります。
Moving Average.mq5 のEAファイルは "terminal_data_folder\MQL5\Experts\Examples\Moving Average\"にあります。この EA はテクニカルインジケーター、トレード履歴 関数、 標準ライブラリのトレードクラスの使い方のサンプルです。また、このEAはトレード結果に基づいた資金管理システムを内包しています。
EAの構造とどのように機能するかを見てみましょう。
1. EA プロパティ
//+------------------------------------------------------------------+ //| Moving Averages.mq5 | //| Copyright 2009-2013, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2009-2013, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00
初めの5行はコメントです。後ろの3行が MQL5 のプロパティで(copyright, link, version)、プリプロセッサー指示文#propertyを使います。
EAをはしらせるとき、これらは"Common" タブに表示されます:
図1. 移動平均EAの一般パラメータ
1.2. インクルードファイル
次に、#includeでコンパイラーに"Trade.mqh" を含むことを指示します。
このファイルはStandard Libraryの一部で、トレード関数に簡単にアクセスできるCTrade クラスを含みます。
#include <Trade\Trade.mqh>
インクルードさせるファイルの名前は "<>;"で囲います。ディレクトリからの相対パスで表記します: "terminal_data_folder\Include\"。
1.3インプット
続いて、タイプ、名前、デフォルト値、コメントです。ルールは図2の通りです。
input double MaximumRisk = 0.02; // Maximum Risk in percentage input double DecreaseFactor = 3; // Descrease factor input int MovingPeriod = 12; // Moving Average period input int MovingShift = 6; // Moving Average shift
MaximumRisk と DecreaseFactor パラメータは資金管理に使います。MovingPeriod と MovingShift は移動平均の期間とシフト値です。これらはトレード条件の確認に使います。
パラメータラインに書かれたコメントのテキストは(デフォルト値を含む)、パラメータの名前の代わりとして"Options"タブに表示されます:
図2. 移動平均EAのパラメータ
1.4. グローバル変数
グローバル変数 ExtHandle を宣言します。この変数は移動平均インジケーターのハンドルとして使われます。
//--- int ExtHandle=0;
6つの関数で使います。それぞれの関数の意図は、関数の記述の前のコメントに記述されています:
- TradeSizeOptimized() - オプションのロットサイズの計算;
- CheckForOpen() - ポジションの条件の確認;
- CheckForClose() - 決済条件の確認;
- OnInit() - EAの最初の関数;
- OnTick() - EAのティックごとの関数;
- OnDeinit() - EAの終わりの関数;
最後の3つの関数はイベントハンドラ関数です。 この3つの関数はコードの中で使います。
2. イベントハンドラ関数
2.1. OnInit() 初期関数
OnInit() 関数は、EAを稼働させたときの最初に一回だけ起動します。一般的に、OnInit()ではEA実行の準備処理を行います: パラメータをチェックしやインジケーターやパラメータを初期化などクリティカルエラーが発生した場合には、その後の処理は無意味になり、関数は INIT_FAILED を返します。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE); if(ExtHandle==INVALID_HANDLE) { printf("Error creating MA indicator"); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); }
この EA は、iMA()による移動平均インジケーターに基づいているので、移動平均インジケーターが生成され、そのハンドルがグローバル変数ExtHandleに保存されます。
エラーが発生した場合、 OnInit() は INIT_FAILED を返します。- これは、初期化に失敗した場合の、EA/インジケーターの挙動として正常です。
2.2. OnTick() 関数
OnTick() 関数は、EAを稼働させているチャートのシンボルに新しいクオートが来た場合に呼び出されます。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(void) { //--- if(PositionSelect(_Symbol)) CheckForClose(); else CheckForOpen(); //--- }
PositionSelect() 関数は、現在のシンボルにおいてポジションを持っているかどうかを定義します。
もし約定しているポジションがある場合には、CheckForClose() が呼び出されます。この関数は現在の相場の状態を分析し、ポジションを決済します。それ以外の場合は、CheckForOpen() を呼び出し、エントリー状態をチェックし、条件がそろえば新規ポジションを建てます。
2.3. OnDeInit() 関数
OnDeInit()は、EAがチャートから外された際に呼ばれます。グラフィックオブジェクトを稼働中に描写していた場合、それらもチャートから取り外されます。
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+
この場合、EAの終了時には何も実行されません。
3. サービス関数
3.1. TradeSizeOptimized()
この関数は、特定のリスクレベルとトレード結果をもとに、最適な新規ポジションのロットサイズ計算し、返します。
//+------------------------------------------------------------------+ //| Calculate optimal lot size | //+------------------------------------------------------------------+ double TradeSizeOptimized(void) { double price=0.0; double margin=0.0; //--- Calculate the lot size if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price)) return(0.0); if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin)) return(0.0); if(margin<=0.0) return(0.0); double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)*MaximumRisk/margin,2); //--- calculate the length of the series of consecutive losing trades if(DecreaseFactor>0) { //--- request the entire trading history HistorySelect(0,TimeCurrent()); //-- int orders=HistoryDealsTotal(); // the total number of deals int losses=0; // the number of loss deals in the series for(int i=orders-1;i>=0;i--) { ulong ticket=HistoryDealGetTicket(i); if(ticket==0) { Print("HistoryDealGetTicket failed, no trade history"); break; } //--- checking the deal symbol if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol) continue; //--- checking the profit double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT); if(profit>0.0) break; if(profit<0.0) losses++; } //--- if(losses>1) lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1); } //--- normalizing and checking the allowed values of the trade volume double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); lot=stepvol*NormalizeDouble(lot/stepvol,0); double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); if(lot<minvol) lot=minvol; double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); if(lot>maxvol) lot=maxvol; //--- return the value of the trade volume return(lot); }
SymbolInfoDouble() は、現在のシンボルの価格が有効化どうかをチェックします。OrderCalcMargin()は、ポジションを建てるのに必要な余剰証拠金を調べるのに使います。(買いポジションの場合)。 初期ロットサイズは、オーダーを一つとるときに要求される証拠金とアカウントの余剰証拠金(AccountInfoDouble(ACCOUNT_FREEMARGIN)) とMaximumRiskパラメータで入力されたリスクレベルからから計算されます。
DecreaseFactor で入力された値が正の場合、履歴の取引が分析され、口座情報の負けトレードをもとにロットサイズが調整されます: 初期ロットサイズはこのサイズ(1-losses/DecreaseFactor)の倍掛けになります。
そしてトレードロットは、現在のシンボルのトレードが許可されている最小桁単位に"四捨五入"されます。ロットサイズが最小ロット未満、もしくは最大ロット以上の場合、それぞれ適切な値に調整されます。結果として、算出された値をトレードロットとして返します。
3.2. Function CheckForOpen()
CheckForOpen() は、ポジションのエントリー条件をチェックするのに利用し、トレード条件がクリアした場合にはポジションを建てます。(今回の場合、価格と移動平均のクロス)
//+------------------------------------------------------------------+ //| Check for open position conditions | //+------------------------------------------------------------------+ void CheckForOpen(void) { MqlRates rt[2]; //--- copy the price values if(CopyRates(_Symbol,_Period,0,2,rt)!=2) { Print("CopyRates of ",_Symbol," failed, no history"); return; } //--- Trade only on the first tick of the new bar if(rt[1].tick_volume>1) return; //--- Get the current value of the Moving Average indicator double ma[1]; if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) { Print("CopyBuffer from iMA failed, no data"); return; } //--- check the signals ENUM_ORDER_TYPE signal=WRONG_VALUE; if(rt[0].open>ma[0] && rt[0].close<ma[0]) signal=ORDER_TYPE_SELL; // sell condition else { if(rt[0].open<ma[0] && rt[0].close>ma[0]) signal=ORDER_TYPE_BUY; // buy condition } //--- additional checks if(signal!=WRONG_VALUE) if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) if(Bars(_Symbol,_Period)>100) { CTrade trade; trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(), SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK), 0,0); } //--- }
トレードが動いた場合、価格が移動平均をクロスしたかどうか確認する必要があります。CopyRates()関数を使うと、bar, rt[0]に応じて二つの現在価格がrt[], rt[1]配列にコピーされます。
1の場合、新しい足は現在足のティックボリュームで始められ、新しい足が始まる。特定の場合、このメソッドの新しい足の検出が機能しない場合があります。そのため、新しい足が形成した事を保存して、現在のクオートの時間と比較する必要があります。 (IsNewBar参照)。
移動平均の現在値は、 CopyBuffer() を使って要求し、 一意の値を持つma[] 配列に保存されます。その後プログラムが価格が移動平均とクロスしたかどうかをチェックし、追加の確認を行います。 (トレードで、EAの利用とヒストリーでの現在足が可能です。)成功すると、PositionOpen()メソッドのトレードオブジェクト(CTradeのインスタンス)によってそのシンボルの適切なポジションが入ります。
新規ポジションは シグナルの変数によってBidかAskを返すSymbolInfoDouble()関数によってセットされます。ボリュームは上記のTradeSizeOptimized() によって決められます。
3.3. Function CheckForClose()
CheckForClose() は、決済条件をチェックし、条件がそろえば決済します。
//+------------------------------------------------------------------+ //| Check for close position conditions | //+------------------------------------------------------------------+ void CheckForClose(void) { MqlRates rt[2]; //--- Copy price values if(CopyRates(_Symbol,_Period,0,2,rt)!=2) { Print("CopyRates of ",_Symbol," failed, no history"); return; } //--- Trade only on the first tick o the new bar if(rt[1].tick_volume>1) return; //--- get the current value of the Moving Average indicator double ma[1]; if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) { Print("CopyBuffer from iMA failed, no data"); return; } //--- get the type of the position selected earlier using PositionSelect() bool signal=false; long type=PositionGetInteger(POSITION_TYPE); if(type==(long)POSITION_TYPE_BUY && rt[0].open>ma[0] && rt[0].close<ma[0]) signal=true; if(type==(long)POSITION_TYPE_SELL && rt[0].open<ma[0] && rt[0].close>ma[0]) signal=true; //--- additional checks if(signal) if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) if(Bars(_Symbol,_Period)>100) { CTrade trade; trade.PositionClose(_Symbol,3); } //--- }
CheckForClose() のアルゴリズムは、 CheckForOpen()のアルゴリズムと類似しています。現在所持しているポジションの向きに応じて、決済条件がチェックされます。 (買いの場合は価格とMAの下向きのクロス、売りの場合は上向きのクロス)ポジションはPositionClose()によって決済されます。 (CTradeのインスタンス)。
4. バックテスト
パラメータの最適な値は MetaTrader 5 terminal の Strategy Testerを使うことで探索可能です。
例として、 MovingPeriod のパラメータを期間2012.01.01-2013.08.01で最適化すると、最適な結果はMovingPeriod=45 となります:
移動平均EAのバックテスト結果
結果:
MetaTrader 5 に標準装備されている移動平均EAは、インジケーター、 トレードヒストリー関数、トレードクラスの1具体例です。また、このEAはトレード結果に基づいた資金管理システムを内包しています。
MetaQuotes Ltdによってロシア語から翻訳されました。
元のコード: https://www.mql5.com/ru/code/1921

ALGLIB 算術関数ライブラリ (v. 3.19) MQL5に移植

このEAは、パラメーターの情報(タイプ、値)を取得して、IndicatorParameters()の使い方を描写します。

MACD のサンプルEAは、MACDのメインとシグナルのクロスでトレードします。このEAは、EA開発におけるオブジェクト指向の一例です。

リアルタイムでの最適化結果の可視化の実例の紹介(資産曲線とEAの統計的パラメータ)。