すべてをまとめる P259
この本の大部分を、注文の発注、クローズ、変更、および管理を行う関数とクラスの作成に費やしました。トレーリングストップ、資金管理、トレードタイマーなどの便利な機能を追加しました。また、インジケータを追加し、価格データを簡単に操作できるようにするクラスも作成しました。ここでは、これらすべてを組み合わせて、完全な機能を備えた堅牢なEAを作成する方法を紹介します。
テンプレートの作成 P259
MetaEditor5はMetaEditor4のようなカスタムテンプレートの使用を許可しません。したがって、時間を制約するために、EAを作成するときに使用するときに独自のテンプレートを作成する必要があります。新しいEAを作成するときは、このファイルを開いて新しい名前で保存するだけです。
使用するテンプレートは、MQLBookTemplate.mq5という名前です。このファイルが上書きされないようにするには、Windowsエクスプローラで\MQL5\Experts\Mq15Bookフォルダーに移動し、MQLBookTemplate.mq5ファイルを見つけます。ファイルを右クリックし、【プロパティ】を選択します。読み取り専属性にチェックマークを付けます。読み取り専用ファイルを保存しようとすると、MetaEditorは警告を発し、新しいファイルで保存するように促します。
以下がテンプレートファイルのセクションごとに分けた部分です。最初に#includeディレクティブとオブジェクト宣言があります。。
//トレード
#include <Mql5Book\Trade.mqh>
CTrade Trade;
//価格
#include <Mql5Book\Price.mqh>
CBars Price;
//資金管理
#include <Mql5Book\MoneyManagement.mqh>
//トレーディングストップ
#include <Mql5Book\TrailingStops.mqh>
CTrailing Trail;
//タイマー
#include <Mql5Book\Timer.mqh>
CTimer Timer;
CNewBar NewBar;
//インジケータ
#include <Mql5Book\Indicators.mqh>
\MQL5\Include\Mql5Bookディレクトリから6つのファイルを含めます。また、これらのファイルのクラスのためにいくつかのオブジェクトを宣言しています。Tradeオブジェクトには、注文の発注関数が含まれています。Priceオブジェクトは、価格データ関数用です。Trailにはトレーリングストップ機能が含まれており、TimerとNewBarにはトレードタイマーと新しいバーの関数が含まれています。EAに指標を追加する必要がある場合は、Indicators.mqhファイルの#includeディレクティブの下で指標オブジェクトを作成します。
次に、いくつかの説明的なプロパティと入力変数があります。
//---------------------
// エキスパート情報 |
//---------------------
#property copyright “Andrew Young”
#property version “1.00”
#property description “”
#property link http://www.expertadvisor.com
//---------------------
// 入力変数 |
//---------------------
input ulong Slippage = 3
input bool TradeOnNewBar = true;
sinput string MM; // 資金管理
input bool UseMoneyManagement = true;
input double RiskPercent = 2;
input double FixedVolume = 0.1;
sinput string SL; // Stop Loss & Take Profit
input StopLoss = 20; ストップロス:損失を制限するために指定された価格で売る。
input int TakeProfit = 0; テイクプロフィット:利益を固定するために指定された価格で売る。
sinput string TS; //トレーリングストップ:価格がトレーダーに有利な方向に移動するにつれて
input bool UseTrailingStop = false; 利益を確保する価格レベルを自動的に更新する注文
input int TrailingStop = 0;
input int MinimumProfit = 0;
input int Stop = 0;
sinput string BE; //ブレークイーブン:ポジションに設定された特定の価格レベルに達した時にポジションを
input bool UseBreakEven = false; クローズするための注文を設定するリスクマネジメント手法。
input int BreakEvenProfit = 0;
input int LockProfit = 0;
sinput string TI; //
input bool UseTimer = false;
input int StartHour = 0;
input int StartMinut = 0;
input int EndHour = 0;
input int EndMinute = 0;
input bool UseLocalTime = false;
#property directivesはプログラムを説明するためのディレクティブであり、EAの【プロパティダイアログ】の【共通Common】タブに表示されます。入力セクションには、資金管理、トレーリングストップとブレイクイーブンストップ(損益分岐停止)、取引タイマーなど、よく使用される機能の入力設定があります。オプション機能にはすべて、機能のオンとオフを切り替えるためのブール入力変数があります。「sinput variable」というのは入力変数を入力ウィンドウで明確に定義されたセクションに分割するための変数のことです。
次に、グローバル変数とOnInit()イベントハンドラーが続きます。
//---------------------
//グローバル変数 |
//---------------------
bool glBuyPlaced, glSellPlaced;
//------------------------
// エキスパート初期化関数 |
//------------------------
int OnInit()
{
Trade.Deviation(Slippage);
return(0);
}
glBuyPlacedおよびglSellPlaced変数は、指定された方向でポジションが以前に開かれたかどうかを追跡します。大部分のトレーディングシステムでは、新しいトレードシグナルが書かれた場合には1つのポジションしか開かず、トレードシグナルが反対方向に現れるか、これらの変数のいずれかをfalseに設定する条件が発生するまで、新しいポジションをオープンすることはありません。OnInit()イベントハンドラには、プログラムが最初に起動時した時に実行されるコードが含まれています。上記では、トレードスリッページを設定しました。
次に、OnTick()イベントハンドラを調べてみましょう。
//------------------------+
//エキスパートティック関数 |
//------------------------+
void OnTicke()
{
//新しいバーをチェック
bool newBar = true;
int barShift = 0;
if(TradeOnNewBar == true)
{
newBar = NewBar.CheckNewBar(_Symbol,_Period);
barShift = 1;
}
//タイマー
bool timerOn = true;
if(UseTimer == true)
{
timeOn = Timer.DailyTimer(StartHour, StartMinute, EndHour, EndMinute, UseLocalTime);
}
//価格を更新
Price.Update(_Symbol, _Period);
コードの最初のセクションは、新しいバーの開始をチェックします。newBarという名前のブール変数を宣言し、trueに初期化します。barShift変数はゼロに初期化されます。TradeOnNewBar入力変数がtrueに設定されている場合、CheckNewBar()関数を呼び出して結果をnewBarに保存し、barShift変数を1に設定します。それ以外の場合、newBarはtrueのままになり、イントラバートレーディングが有効になります。
その後はタイマーコードです。timerOnという名前のブール変数を定義し、trueに初期化します。UseTimer入力変数がtrueに設定されている場合、DailyTimer()関数をチェックし、戻り値をtimerOnに割り当てます。それ以外の場合、timerOnの値はtrueのままです。EAでバーデータを使用している場合、Price.Update()関数はBarオブジェクトを価格と時間データで更新します。
次は、資金管理機能を備えた注文配置コードです。
//発注
if(newBar == true && timerOn == true)
{
//資金管理
double tradeSize;
if(UseMoneyManagement == true)
tradeSize = MoneyManagement(_Symbol, FixedVolume, RiskPercent,StopLoss);
else tradeSize = VerifyVolume(_Symbol, FixedVolume);
//買い注文を開く
if(PositionType() != POSITON_TYPE_BUY && glBuyPlaced == false)
{
glBuyPlaced = Trade.Buy(_Symbol, tradeSize);
if(glBuyPlaced == true)
{
double openPrice = PositionOpenPrice(_Symbol);
double buyStop = BuyStopLoss(_Symbol, StopLoss, openPrice);
if(buyStop > 0) AdjustBelowStopLevel(_Symbol, buyStop);
double buyProfit = BuyTakeProfit(_Symbol, TakeProfit, openPrice);
if(buyProfit > 0) AdjustBelowStopLevel(_Symbol, buyProfit);
if(buyStop > 0 || buyProfit > 0)
Trade.ModifyPosition(_Symbol, buyStop, buyProfit);
glSellPlaced = false;
}
}
newBar変数とtimerOn変数の値をチェックして、取引をチェックするかどうかを決定します。両方ともtrueの場合、先に進みます。次に資金管理コードです。UseMoneyManagement入力変数がtrueの場合、取引量を計算し、それをtradeSize変数に保存します。それ以外の場合は、VerifyVolume()関数を使用してFixedVolume設定を検証し、結果をtradeSize変数に保存します。
次に買い注文の条件です。ポジションタイプとglBuyPlacedの値という2つの取引条件を挿入しました。PositionType()関数は現在のポジションタイプを返すか、開いているポジションが無い場合は-1を返します。ポジションが既に開いている場合は注文を開きたくないので、開いている買いポジションが無い場合にのみ注文を開きます。glBuyPlaced変数は、このトレードシグナルに対して買いポジションがあったかどうかを決定します。このif演算子にさらに条件を追加する必要がありますが、現時点ではこれが最小限です。
取引条件がtrueの場合、TradeオブジェクトのBuy()関数が注文を出し、注文が正常に行われた場合はglBuyPlaced変数をtrueに設定します。glBuyPlacedがtrueの場合、ポジションの変更に進みます。
ポジションの開始価格を取得し、その値をopenPrice変数に格納します。次に、BuyStopLoss()関数を呼び出して、値をbuyStop変数に保存します。AdjustBelowStopLevel()関数は、buyStop価格を検証し、必要に応じて調整します。buyProfit変数についても同じことが行われます。buyStopまたはbuyProfitがゼロより大きい場合、ストップロスとテイクプロフィットを買いポジションに追加するためにModifyPosition()関数を呼び出します。最後に、glSellPlaced変数をfalseに設定します。
売り注文の配置コードは非常に似ています。完全な形で以下に示します。
//売り注文を開く
if(PositionType() != POSITION_TYPE_SELL && glSellPlaced == false)
{
glSellPlaced = Trade.Sell(_Symbol, tradeSize);
if(glSellPlaced == true)
{
do Sleep(100); while(PositionSelect(_Symbol) == false);
double openPrice = PositionOpenPrice(_Symbol);
double sellStop = SellStopLoss(_Symbol, StopLoss, openPrice);
if(sellStop > 0) sellStop = AdjustAboveStopLevel(_Symbol,sellStop);
double sellProfit = SellTakeProfit(_Symbol, TakeProfit, openPrice);
if(sellProfit > 0) sellProfit = AdjustAboveStopLevel(_Symbol,sellProfit);
if(sellStop > 0 || sellProfit > 0)
Trade.ModifyPosition(_Symbol, sellStop, sellProfit);
glBuyPlaced = false
}
}
} //発注終了
売り注文配置コードの後、最後の締め括弧が注文配置ブロックを終了します。これらの括弧内のすべては、新しいバーが開いたばかりの場合、タイマーがアクティブであるか、または両方の機能が無効になっている場合にのみ実行されることに注意してください。
最後に、ブレイクイーブン(損益分岐点)とトレーリングストップのコードがあります。そしてOnTicke()イベントハンドラの最後になります。
//ブレイクイーブン(損益なし)
if(UseBreakEven == true && PositionType(_Symbol) != -1)
{
Trail.BreakEven(_Symbol, BreakEvenProfit, LockProfit);
}
//トレーリングストップ
if(UseTrailingStop == true && PositionType(_Symbol) != -1)7
{
Trail.TrailingStop(_Symbol, TrailingStop, MinimumProfit, Stop);
}
} // OnTick()の終了
資金管理、トレードタイマー、新しいバーチェック、トレーリングストップ、ブレーク イーブン ストップ、エラー処理、価格検証などを含むEAテンプレートを作成しました。後は、インジケータと注文の開始条件と終了条件を追加するだけです。
このテンプレートを使用して2つのEAを作成します。1つ目は移動平均クロスで、トレーディングシステムです。もう1つは、ボリンジャーバンドとRSIを使用して、カウンタートレンドの取引システムを作成します。
ヘッジ口座のテンプレート P265
また、ヘッジアカウント用のテンプレートも作成しますが、いくつかの小さな違いがあります。Trade.mqhインクルードファイルを使用する代わりに、TradeHedge.mqhファイルを使用し、CTradeHedgeCPositionsクラスのオブジェクトを作成します。
#include <Mql5Book\TradeHedge.mqh>
CTradeHedge Trade;
CPositions Positions;
取引を区別するためにMagicNumber入力変数を使用するので、それを入力変数の先頭に追加しましょう。
input ulong Slippage = 3
input ulong MagicNumber = 123;
input bool TradeOnNewBar = true;
売買条件が若干異なります。CPositions注文カウント関数を使用してオープン注文を確認し、注文チケットをglBuyTicket変数に割り当てます。そのチケット番号を使用して、注文の開始価格を取得し、注文を変更します。
if(Positions.Buy(MagicNumber) == 0)
{
glBuyTicket = Trade.Buy(_Symbol, tradeSize);
if(glBuyTicket > 0)
{
double openPrice =PositionOpenPrice(glBuyTicket);
double buyStop = BuyStopLoss(_Symbol, StopLoss, openPrice);
if(buyStop > 0) AdjustBelowStopLevel(_Symbol, buyStop);
double buyProfit = BuyTakeProfit(_Symbol, TakeProfit, openPrice);
if(buyProfit > 0) AdjustAboveStopLevel(_Symbol, buyProfit);
if(buyStop > 0 || buyProfit > 0) Trade.ModifyPosition(glBuyTicket, buyStop, buyProfit);
glsellTicket = 0;
}
}
トレーリングストップとブレークイーブンストップの場合は、チケット番号の配列を取得し、開いている注文ごとにトレーリングストップまたはブレークイーブンストップを処理します。
//ポジションチケットを取得
ulong tickets[];
Positions.getTickets(MagicNumber, tickets);
int numTickets = ArraySize(tickets);
//ブレイクイーブン(損益なし)
if(UseBreakEven == true && numTickes > 0)
{
for(int i = 0; < numTickets; i++ )
{
Trail.BreakEven(tickets[i], BreakEvenProfit, LockProfit);
}
}
//トレーリングストップ
if(UseTrailingStop == true && numTickes > 0)
{
for(int i = 0; < numTickets; i++ )
{
Trail.TrailingStop(tickets[i], TrailingStop, MinimumProfit, Step);
}
}
注文の開始条件と終了条件を変更したいことは明らかであり、一度に複数の注文を開始できるようにすることもできます。CPositionsクラス関数を使用して、オープン注文を追跡および管理します。
移動平均線のクロス P266
図19.1-移動平均クロスシステム
移動平均線クロスでは、早い移動平均線と遅い移動平均線の2つの移動平均線を使用します。高速MAが低速MAよりも大きい場合、買いポジションを開きます。高速移動平均線が低速移動平均線よりも小さい場合、売りポジションを開きます。各方向に1つのポジションのみが開かれます。移動平均線が反対方向にクロスすると、現在開いているポジションをクローズし、glBuyPlaced変数とglSellPlaced変数をリセットします。
最初に、CiMAクラスに基づいて2つのオブジェクトを宣言する必要があります。1つは高速MA用で、もう1つは低速MA用です。
#include <MqlBook\Indicators.mqh>
CiMA FastMA;
CiMA slowMA;
「FastMA」というオブジェクトを使用して高速移動平均線を計算し、「SlowMA」というオブジェクトを使用して低速移動平均線を計算します。次に、移動平均線の設定を追加する必要があります。「Fast」接頭辞が付いた変数名は高速移動平均線の設定であり、「Slow」接頭辞が付いた変数名は低速移動平均線の設定です。
sinput string FaMA; // 高速MA
input int FastMAPeriod = 10;
input ENUM_MA_METHOD FastMAMethod = 0;
input int FastMAShift = 0;
input ENUM_APPLIED_PRICE FastMAPrice = PRICE_CLOSE;
sinput string SlMA; //低速MA
input int SlowMAPeriod = 10;
input ENUM_MA_METHOD SlowMAMethod = 0;
input int SlowMAShift = 0;
input ENUM_APPLIED_PRICE SlowMAPrice = PRICE_CLOSE;
ディフォルトでは、10期間のSMAと20時間のSMAが設定されています。次に、インジケータを初期化する必要があります。これは、OnInit()イベントハンドラで行います。
int OnInit()
{
FastMA.Init(_Symbol, _Period, FastMAPeriod, FastMAShift, FastMAMethod, FastMAPrice);
SlowMA.Init(_Symbol, _Period, SlowMAPeriod, SlowMAShift, SlowMAMethod, SlowMAPrice);
Trade.Deviation(Slippage);
return(0);
}
あとは、FastMAおよびSlowMAオブジェクトのMain()関数を使用して、移動平均値を取得するだけです。これは、買い注文と売り注文の条件を保持するif演算子で行います。
//買い注文を開く
if(FastMA.Main(barShift) > SlowMA.Main(barShift) && PositionType() != POSITION_TYPE_BUY
&& glBuyPlaced == false)
{
glBuyPlaced = Trade.Buy(_Symbol, tradeSize);
if(glBuyPlaced == true)
{
double openPrice = PositionOpenPrice(_Symbol);
double buyStop = BuyStopLoss(_Symbol, StopLoss, openPrice);
if(buyStop > 0) AdjustBelowStopLevel(_Symbol, buyStop);
double buyProfit = BuyTakeProfit(_Symbol, TakeProfit, openPrice);
if(buyProfit > 0) AdjustBelowStopLevel(_Symbol, buyProfit);
if(buyStop > 0 || buyProfit > 0) Trade.ModifyPosition(_Symbol, buyStop, buyProfit);
glSellPlaced = false;
}
}
高速MAが低速MAより大きく、現在開いている買いポジションが無く、glBuyPlacedがfalseの場合、買い注文を開きます。Main()関数パラメータにbarShift変数を使用していることに注意してください。TradeOnNewBarがtrueに設定されている場合、barShiftは常に1になります。したがって、現在のバーではなく、最後のバーの値を確認します。TradeOnNewBarがfalseに設定されている場合、barShiftはゼロになり、現在の足の値を確認します。
そして、売り注文の条件です。
//売り注文を開く
if(FastMA.Main(barShift) < SlowMA.Main(barShift) && PositionType() != POSITION_TYPE_SELL
&& glSellPlaced == false)
{
// …
}
それでおしまい!これで、資金管理、トレーディングストップ、ブレークイーブンストップ、トレードタイマーを備えた機能する移動平均クロスができました。コードは、\MQL5\Experts\Mql5Bookフォルダの移動平均Cross.mq5ファイルで表示できます。
ヘッジ口座の移動平均線クロス P268
ヘッジアカウントの移動平均クロスEA\MQL5\Experts\Mql5Bookフォルダに含まれています。変更は、上記のヘッジアカウントテンプレートのトピックで説明されているものと同様です。
Bands/RSIカウンタートレードシステム P268
2番目の例では、RSIとボリンジャーバンドの2つのインジケータを使用します。これは逆トレンドシステムになります。つまり、極端な価格を探して反対方向への取引を試みることを意味します。まず、外側のボリンジャーバンドの外に移動する価格を探します。次に、RSIで買われすぎ、または売られすぎの状態を探します。たとえば、価格が下のボリンジャーバンドを下回り、RSIが30を下回った場合、買い注文を出します。
図19.2-ボリンジャーバンドとRSIを使用したカウンタートレンドシステム
インジケータオブジェクトを宣言することから始めましょう。
#include <Mql5Book\Indicators.mqh>
CiBollinger Bands;
CiRSI RSI;
次に、入力パラメータを追加します。
sinput string BB; //ボリンジャーバンド
input int BandsPeriod = 20;
input int BandsShift = 0;
input double BandsDeviation = 2;
input ENUM_APPLIED_PRICE BandsPrice = PRICE_CLOSE;
sinput string RS; //RSI
input int RSIPeriod = 8;
input ENUM_APPLIED_PRICE RSIPrice = PRICE_CLOSE;
インジケータのInit()関数をOnInit()イベントハンドラに追加します。
int OnInit()
{
Bands.Init(_Symbol, _Period, BandsPeriod, BandsShift, BandsDeviation, BandsPrice);
RSI.Init(_Symbol, _Period, RSIPeriod, RSIPrice);
Trade.Deviation(Slippage);
return(0);
}
最後に、買い注文と売り注文の条件を追加します。
//買い注文を開く
if(Bar.Close(barShift) < Bands.Lower(barShift) && RSI.Main(barShift) < 30
&& PositionType() != POSITION_TYPE_BUY && glBuyPlaced == false)
{
// …
}
//売り注文を開く
if(Bar.Close(barShift) > Bands.Upper(barShift) && RSI.Main(barShift) > 70
&& PositionType() != POSITION_TYPE_SELL && glSellPlaced == false)
{
// …
}
現在のバーの終値がボリンジャーバンドの下限価格よりも低く、RSIの読み取り値が30を下回っている場合、買い注文を開きます。終値がボリンジャーバンドの上限より大きく、RSIが70を超える場合、売り注文を出します。
これをStrategy Testerでテストすると、改善の余地があることがわかります。1つには、通常、注文が入るのが早すぎます。価格がバンド内に戻るのを待つ代わりに、注文はすぐに開始されます。第2にこの戦略は、新しいトレードシグナルが同じ方向に現れるので、オープンポジションに追加することで利益を得ることができます。
取引条件を再定義しましょう。まず、RISの買われすぎまたは売られすぎの状態を伴って、価格がバンドの外に移動するのを探します。次に、価格がバンド内に戻るのを待ち、その時点で注文をオープンします。
2つのステップで取引条件を確認する必要があります。まず、終値がバンドの外にあり、買われすぎまたは売られすぎのRSI状態が存在するかどうかを確認します。次に、価格がバンド内で移動したかどうかを確認します。条件の最初のセットは、通常の買い/売り注文の外でチェックする必要があります。シグナル値を保持するグローバル変数を作成しましょう。
enum Signal
{
SIGNAL_BUY,
SIGNAL_SELL,
SIGNAL_NONE,
};
Signal glSignal;
これは、プログラムのグローバルスコープで宣言されます。SINGL_BUY、SIGNAL_SELL、SIGNAL_NONEの3つの値を持つSignalという名前の列挙を作成しました。glSignalグローバル変数は、これらの値のいずれかを常に保持します。
OnTick()イベントハンドラでは、発注コードの前に、最初の条件セットをチェックします。これらは、以前に定義したのと同じ条件です。
if(Bar.Close(barShift) < Bands.Lower(barShift) && RSI.Main(barShift) < 30)
glSignal = SIGNAL_BUY;
else if(Bar.Close(barShift) > Bands.Upper(barShift) && RSI.Main(barShift) > 70)
glSignal = SIGNAL_SELL;
終値が下のボリンジャーバンドよりも低く、RSIが30未満の場合、glSignalの値をSIGNAL_BUYに設定します。この値は、条件が真でなくなった場合でも保持されます。売り条件についても同じことが言えます。この場合、glSignalの値をSIGNAL_SELLに設定します。
次に、注文の開始条件を確認します。glSignalの値を確認し、終値が最近上限または下限を超えたかどうかを判断します。
if(glSignal == SIGNAL_BUY && Bar.Close(barShift) > Band.Lower(barShift)
&& Bar.Close(barShift+1) <= Bands.Lower(barShift+1))
{
//買いポジションを開く
}
まず、glSignalにSIGNAL_BUYの値が含まれているかどうかを確認します。次に、現在の足の終値が下のバンドを上回っているかどうかを確認します。最後に、前の足の終値が下のバンドを下回っていたかどうかを確認します。前のバーを参照するために、バーのShift値に1を追加することに注意してください。
注文開始条件を非常に具体的にして、価格がバンド内で移動すると、EAが注文を開始し続けないようにします。PositionType()およびglBuyPlaced条件がなくなっていることに注意してください。特定の注文条件が満たされている限り、EAは現在のポジションと同じ方向に別の注文を出すことができます。
完全な形の販売条件は次の通りです。
if(glSignal == SIGNAL_SELL && Bar.Close(barShift) < Bands.Upper(barShift)
&& Bar.Close(barShift+1) >= Bands.Upper(barShift+1))
{
//売りポジションを開く
}
もう一つ、注文を開き、発注されたことを確認したら、誤った注文を避けるために、glSignalの値をSIGNAL_NONEにリセットします。
glSignal = SIGNAL_NONE;
これで、希望通りに取引するカウンタートレンド取引システムができました。この例は、EAをプログラミングする際に、取引条件について非常に具体的にする必要があることを示しています。あなたの取引方法は一見明白に見えるかもしれませんが、EAがそれを正しく取引するには、もう少し手間がかかるかもしれません。この取引システムのコードは、\MQL5\Experts\Mql5Book\にあるファイルBandsRSICounterTrend.mq5ファイルで確認できます。
ヘッジ口座のカウンタートレードシステム P272
ヘッジ口座のBands/RSI Counter-trend EAでは、CPositionsクラス関数を使用して現在の注文チケット番号を取得する方法を示します。これは、取引が開かれている間にEAの実行が中断された場合に役立ちます。
//ポジションを開く
ulong buyTickets[], sellTickets[];
Position.GetTickets(MagicNumber, buyTickets);
glBuyTicket = buyTickets[0];
Position.GetSellTickets(MagicNumber, sellTickets);
glSellTicket = sellTickets[0];
Positions.BuyTickets()およびPositions.SellTickets()関数は、ユーザーが設定したMagicNumber値と一致する配列を取得します。最初のチケット番号は、glBuyTicketまたはglSellTicket変数に割り当てられます。EAアドバイザの残りの部分は、この章で説明するヘッジアカウントのEA機能と同様に機能します。
\MQL5\Experts\Mql5Book\にあるファイルBands RSI Countertrend(Hedging.mq5)で、このトレーディングシステムのヘッジアカウントバージョンのコードを表示できます。
指値注文のテンプレート P272
この章の前半で作成したテンプレートは成行注文用です。未決注文を出すEAをプログラムしたい場合があります。成行注文の代わりに指値注文を出すテンプレートを作成します。
このファイルはMQL5BookPendingTemplate.mq5という名前で、\MQL5\Experts\Mql5Bookフォルダにあります。この章の前半で詳しく説明したテンプレートファイルの変更点に注意してください。
//保留中
#include <MqlBook\Pending.mqh>
CPending Pending;
未決注文管理機能を含むPending.mqhインクルードファイルをインクルードし、CPendingクラスに基づいてPendingオブジェクトを作成します。
//保留中の買いストップ注文を開く
if(PositionType() != POSITION_TYPE_BUY && glBuyPlaced == false)
{
double orderPrice = 0;
orderPrice = AdjustAboveStopLevel(_Symbol, orderPrice);
double buyStop = BuyStopLoss(_Symbol, StopLoss, orderPrice);
double buyProfit = BuyTakeProfit(_Symbol, TakeProfit, orderPrice);
glBuyPlaced = Trade.BuyStop(_Symbol, tradeSize, orderPrice, buyStop, buyProfit);
if(glBuyPlaced == true)
{
glSellPlaced = false;
}
}
//保留中の売りストップ注文を開く
if(PositionType() != POSITION_TYPE_SELL && glSellPlaced == false)
{
double orderPrice = 0;
orderPrice = AdjustBelowStopLevel(_Symbol, orderPrice);
double sellStop = SellStopLoss(_Symbol, StopLoss, orderPrice);
double sellProfit = SellTakeProfit(_Symbol, TakeProfit, orderPrice);
glSellPlaced = Trade.SellStop(_Symbol, tradeSize, orderPrice, sellStop, sellProfit);
if(glSellPlaced == true)
{
glBuyPlaced = false;
}
}
上記は保留中の売買注文配置コードです。OrderPrice変数には、プログラマーが未決注文の始値を入力する必要があります。注文価格が正しいかどうかがチェックされ、それに対してストップロスとテイクプロフィットが計算され、保留中のストップ注文が出されます。最後に、glBuyPlacedまたはglSellPlaced変数がfalseに設定されます。
ブレイクアウト取引システム P274
このテンプレートを使用して未決注文取引システムを作成してみましょう。最後のXバーの最高値と最低値を見つける取引システムを作成します。取引タイマーが開始すると、保留中の買いストップ注文が最高値で配置され、保留中の売りストップ注文が最低値で配置されます。両方の注文のストップロスは反対の価格で設定されます。各方向に1つの取引のみが行われ、すべての取引タイマーの終了時間にクローズされます。
この戦略では、新しいバーチェック、トレーリングストップ、ブレークイーブン機能を削除します。また、StopLoss、Slippage、UseTimer、の設定も削除します。#includeディレクティブから始めましょう。
//トレード
#include <MqlBook\Trade.mqh>
CTrade Trade;
//価格
#include <MqlBook\Price.mqh>
//資金管理
#include <MqlBook\MoneyManagement.mqh>
//タイマー
#include <MqlBook\Timer.mqh>
CTimer Timer;
//保留中
#include <MqlBook\Pending.mqh>
CPending Pending;
図19.3-保留中のブレイクアウト取引システム
これらは、この戦略に必要なインクルードファイルとオブジェクトです。次に、入力変数を調べてみましょう。
sinput string MM; //資金管理
input bool UseMoneyManagement = true;
input double RiskPercent = 2;
input double FixedVolum = 0.1;
sinput string TS; //取引設定
input int HighLowBars = 8;
input int TakeProfit = 0;
sinput string TI; //タイマー
input int StartHour = 8;
input int StartMinute = 0;
input int EndHour = 20;
input int EndMinute = 0;
input bool UseLocalTime = false;
HighLowBarsという名前の新しい入力変数を追加しました。これは、最高値と最低値を見つけるために(現在のバーから開始して)検索するバーの数です。これをTakeProfit変数でグループ化し、静的入力変数を追加して、グループに「Trade Settings」というラベルを付けました。
発注コードに進みましょう。タイマーコードについては後で説明します。
//発注
if(timerOn == true)
{
//最高値、最低値
double hHigh = HighestHigh(_Symbol, _Period, HighLowBars);
double lLow = LowestLow(_Symbol, _Period, HighLowBars);
double diff = (hHigh - lLow) / _Point;
//資金管理
double tradeSize;
if(UseMoneyManagement == true)
tradeSize = MoneyManagement(_Symbol, FixedVolume, RiskPercent, (int)diff);
else tradeSize = VerifyVolume(_Symbol, FixedVolume);
トレードタイマーがアクティブな場合、最高値と最低値を見つけることから始めます。Price.mqhインクルードファイルで定義したHighestHigh()およびLowestLow()関数を使用します。HighLowBarsパラメータは、検索するバーの数を示します。戻り値は、それぞれhHigh変数とlLow変数に保存されます。
資金管理コードを使用しているため、ロットサイズを計算できるようにポイント単位でストップロスを計算する必要があります。これを行うには、最高値(hHigh)から最低値(lLow)を引き、それを現在のシンボルの_Point値で割ります。結果は変数diffに保存されます。
資金管理コードは、差分変数を最終パラメータとしてMoneyManagement()関数に渡すことを除いて、以前のEAと同じです。diff変数の前にある(int)は、単純にdiffの値を整数に変換し、四捨五入して、データ型を暗黙的に変更したときに発生する「型変換によるデータ損失の可能性」という警告を防ぎます。
保留中の売買ストップ注文コードは次のとおりです。
//保留中の買いストップ注文を開く
if(Pending.BuyStop(_Symbol) == 0 && glBuyPlaced == false)
{
double orderPrice = hHigh;
orderPrice = AdjustAboveStopLevel(_Symbol, orderPrice);
double buyStop = lLow;
double buyProfit = BuyTakeProfit(_Symbol, TakeProfit, orderPrice);
glBuyPlaced = Trade.BuyStop(_Symbol, tradeSize, orderPrice, buyStop, buyProfit);
}
//保留中の売りストップ注文を開く
if(Pending.SellStop(_Symbol) == 0 && glSellPlaced == false)
{
double orderPrice = lLow;
orderPrice = AdjustBelowStopLevel(_Symbol, orderPrice);
double sellStop = hHigh;
double sellProfit = SellTakeProfit(_Symbol, TakeProfit, orderPrice);
glSellPlaced = Trade.SellStop(_Symbol, tradeSize, orderPrice, sellStop, sellProfit);
}
最初に買いストップの注文コードを見てみましょう。pending.BuyStop()関数が未決注文(保留注文)が無いことを示すゼロを返し、そしてglBuyPlaced変数がfalseの場合、注文を出すことができます。orderPrice変数にはhHighの値が割り当てられ、これが注文のオープン価格になります。AdjustAboveStopLevel()関数を使用してチェックし、現在の価格に近すぎないことを確認します。buyStop変数は、ストップロスであるlLowに設定されています。指定されている場合は、テイクプロフィットも計算されます。Trade.BuyStop()関数が未決注文を出し、成功するとglBuyPlaced変数がtrueに設定されます。
その日の取引タイマーが最初にアクティブになると、買いと売りのストップ注文が出されます。その日はそれ以上の注文は行われず、すべての注文はタイマーの終了時間にクローズされます。タイマーコードを見てみましょう。これは、上記の発注コードの前に配置されます。
//タイマー
bool timerOn = Timer.DailyTimer(StartHour, StartMinute, EndHour, EndMinute, UseLocalTime);
if(timerOn == false)
{
if(Positionselect(_Symbol) == true) Trade.Close(_Symbol);
int total = Pending.TotalPending(_Symbol);
if(total > 0)
{
ulong tickets[];
Pending.GetTickets(_Symbol, tickets);
for(int i = 0; i < total; i++)
{
Trade.Delete(tickets[i]);
}
}
glBuyPlaced = false;
glSellPlaced = false;
}
まず、timerOn変数を宣言し、DailyTimer()関数を使用して設定します。timerOnの値がfalseで、タイマーがオフであることを示している場合は、開いている注文をすべて閉じて、glBuyPlaced変数とglSellPlaced変数をリセットする必要があります。まず、PositionSelect()関数の出力を確認します。trueを返す場合、Trade.Close()関数を使用して現在のポジションを決済します。
次に、オープンしている未決注文を確認する必要があります。Pending.TotalPending()関数はオープンしている未決注文の数を返し、total変数に保存します。合計がゼロより大きい場合、未決注文を処理します。
チケット[]という名前のulong配列を宣言して未決注文のチケット番号を保持します。。Pending.GetTickets()関数は、チケット[]配列にチケット番号を入力します。forループを使用してticket[]配列を繰り返し処理し、Trade.Delete()関数を使用して各オープン注文を削除します。最後に、glBuyPlacedとglSellPlacedをtrueに設定します。
\Experts\Mql5Book\Pending Order Breakout.mq5ファイルで、このEAのコードを確認できます。この本で検討した手法を使用して、いくつかの基本的な戦略を作成する方法を示しました。一部の高度な戦略では、テンプレートファイルにもう少し変更を加える必要がありますが、基本はそこにあるため、新しい戦略を最初からコーディングしなくても、戦略を簡単に実装できます。