前回はブレイクイーブンストップ関数を作り、そのコード記述について解説しました。
ブレイクイーブンストップを簡単に実装するために、OriginalCTrailingクラスのメンバ関数として、BreakEven関数を追加しました。
これでメインプログラムにこのメンバ関数を呼び出せば、簡単にブレイクイーブンストップを実装する事が可能になりました。
具体的な関数の使い方については、この講座の終盤にもう少し応用的なEAを作り、そのコード記述を解説する予定なので、その時に改めて紹介していきたいと思います。
※ブレイクイーブンストップについての詳細は↓の記事をご覧ください。
MQL5 EA講座 第99回「ブレイクイーブンストップについて」
さて、今回からはMQL5を使って、資金管理とその資金に応じてロット調整をする方法について解説していきたいと思います。
資金管理とは?→相場に生き残り続ける為に必須のスキル
- 取れるリスクの度合いを決定する。
- 取れるリスクに応じたトレード計画を立案する。
- 取れるリスクに応じたトレードを実現する為に、損失を限定する適切なストップロスを設定する
などの意味を持ちます。
さらに言えば、我々MQL5を利用して、EA自動売買の開発をしている者にとっては、それをシステムトレード化させる為のコード記述を指します。
FXはハイリスク・ハイリターンな金融商品であり、短期間で大きな利益を見込める半面、相場変動も大きく,資金管理を適切に行わないと大きな損失を被る可能性が高まります。
そして、多くのトレーダーが資金管理を疎かにした結果、相場を退場していきます。
多くの人が資金管理を失敗する理由はいくつか考えられますが、概ね
- 感情的なトレードを行ってしまったから(損失を出した焦りや、利益を出して舞い上がってしまった結果の冷静さを欠いた意思決定)
- レバレッジをかけすぎたり、大きなポジションを取りすぎたり、といった過剰なリスクを許容してしまう。
- そもそも事前に資金管理計画を立てる事を怠り、感覚的なトレードを繰り返す。
- 相場への理解不足から誤ったトレード判断をしてしまう。
↑のどれかに当てはまる事が殆どだと思います。
これら資金管理の失敗は、EA開発時に、資金管理を適切に取り込むような記述を実装する事で、かなりその発生確率を下げることができると考えています。
今回からはそのコード記述について解説していく訳ですが、その前にロット調整についても説明しておきましょう。
ロット調整とは?→損失を限定する為に資金量に応じた適切なロットを設定する事。
説明するロット調整という概念も、先に説明した資金管理を適切に行う、方策の1つになります。
ロット調整には、以下のような方法があります。
トレーダーが取引する通貨ペアに対して、口座残高に応じて、あらかじめ固定されたロットサイズを決めておく方法
例えば口座残高が50万円までなら、0.1ロット、50万-100万円の間なら0.2ロット・・・といった具合に口座残高に応じてエントリー時のロットサイズを漸減漸増させる調整方法です。
口座残高をリスク許容度の第1基準にする方式、と言えるでしょうか。
ポジションサイズを口座残高に対する一定の損失割合に収まるように設定する方法
例えば100万円の口座残高があり、損失を1%まで許容する設定にする場合、1万円までの損失は許容できるようなロットサイズを設定する方法です。
この方法を選択する場合、ロットサイズを算出するのに、損切り価格を決定する必要がありますから、EA開発時に損切り戦略も明確に規定しておく必要があります。
ボラティリティに基づいてロットサイズを設定する方法
ボラティリティとは?
ボラティリティとは、金融市場における価格変動の幅を表す指標のことで、端的に言えば「値動きの大きさ」のことです。
ボラティリティを図る指標としては、ATR(Average True Range)などが有名です。
※ATRについての詳細は↓の記事をご参照ください
このATRなどを利用して、相場のボラティリティが高い相場・通貨ペアではロットサイズを小さくしたり、逆にボラティリティが低い相場・通貨ペアにおいてはロットサイズを大きくしたりすることでリスクコントロールを行おうとする調整方法になります。
その他にも色んな方法があるでしょうが、よく使われるのは上記のような方法になります。
ロット調整に関する記述について
この後、資金管理やロット調整に特化したクラスや関数を作り、そのコード記述を解説していくのですが、今回はまずクラスや関数を使わない状態での、ロット調整に関する基本的な記述を見ていきます。
ロット調整記述1:ロット数をパラメータ化したinput変数を宣言する
//インプット変数の宣言
input double TradeVolume =0.14;//ロット数をパラメータ化
まずはグローバル領域に、input変数を宣言します。
変数名は「TradeVolume」とします。このinput変数の値が、実際にEAを動かす際に注文する基本のロットになります。
※input変数については下記の記事をご覧ください。↓
続いては、イベントハンドラーであるOnTick関数内の記述に移ります。
ロット調整記述2:OnTick関数内に必要な値を記述していく。
OnTick関数内の全体記述は以下のようになります。
void OnTick()
{
double minVolume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);//通貨ペアの取り扱い最小ロットを取得
double maxVolume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);//通貨ペアの取り扱い最大ロットを取得
double stepVolume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);//通貨ペアのロットステップ幅を取得
//発注に渡す、最終的なロット数を格納する変数
double tradeSize;
if(TradeVolume < minVolume) tradeSize = minVolume;//最小ロットよりも小さい値になっていた場合、最小ロットに修正
else if(TradeVolume > maxVolume) tradeSize = maxVolume;//最大ロットよりも大きい値になっていた場合、最大ロットに修正
//ロットのステップ幅を使って、ロット数の最終調整をする。
else tradeSize = MathRound(TradeVolume / stepVolume) * stepVolume;
//ブローカーの規定するステップ幅に応じて正規化を行う
if(stepVolume >= 0.1) tradeSize = NormalizeDouble(tradeSize,1);
else tradeSize = NormalizeDouble(tradeSize,2);
}
一つ一つ順を追って見ていきましょう
double型の変数「minVolume」は、取り扱い最小ロットを格納する
double minVolume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);//通貨ペアの取り扱い最小ロットを取得
FXブローカーが設定している通貨ペアの最小ロットは、そのブローカーが提供する取引プラットフォームや口座種別などによって異なります。
基本的には0.01ロットか0.1ロットが最小ロットと規定している所が殆どでしょう。
double型のローカル変数「minVolume」には、各ブローカーが設定している、対象取引通貨ペアの取り扱い最小ロットを格納します。
取り扱い最小ロットの取得には、SymbolInfoDouble関数の第2引数に定数「SYMBOL_VOLUME_MIN」を記述します。
double型の変数「maxVolume」は、取り扱い最大ロットを格納する
double maxVolume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);//通貨ペアの取り扱い最大ロットを取得
取り扱い最小ロットと同じ理屈で、取り扱い最大ロットについても各ブローカによって異なってきます。同じブローカでも、口座種別等によって変わってくる場合もあります。
あるブローカーでは最大200ロットまでだったものが、別のブローカでは500ロットまで取引可能だったり・・・といった事があり得る訳です。
double型のローカル変数「maxVolume」には、各ブローカーが設定している、対象取引通貨ペアの取り扱い最大ロットを格納します。
取り扱い最大ロットの取得には、SymbolInfoDouble関数の第2引数に定数「SYMBOL_VOLUME_MAX」を記述して取得します。
double型の変数「stepVolume」は、ロットのステップ幅を格納する
double stepVolume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);//通貨ペアのロットステップ幅を取得
double型のローカル変数「stepVolume」には、ロットのステップ幅を格納します。
ロットのステップ幅とは、取引数量を変更する時の最小単位の事を指します。
ロットのステップ幅は通常0.1ロットか、0.01ロットになっています。
例えば1ロットの買いポジションを持っていて、同じ方向に追加でポジションを持ちたい場合があるとしましょう。その時に、ロットのステップ幅を通常0.1ロットとしているブローカでは最低0.1ロットはポジション量を指定しないといけません。
「もう1ロットも持っているから、追加分は細かく刻んで0.01ロットにして、合計1.01ロットにしておこう!」という判断は、ロットのステップ幅を通常0.1ロットにしている業者においては出来ないという事になります。
ロットのステップ幅の取得には、SymbolInfoDouble関数の第2引数に定数「SYMBOL_VOLUME_STEP」を記述して取得します。
発注時に渡す、最終的なロット数を格納する変数「tradeSize」を宣言する
//発注時に渡す、最終的なロット数を格納する変数
double tradeSize;
double型のローカル変数「tradeSize」は、発注の際、
MqlTradeRequest構造体のメンバ変数である .Volumeへの値を代入する為に使います。
ロット調整記述1:ロット数をパラメータ化したinput変数を宣言するセクションで宣言したinput変数を元にして、これから解説いくつかの記述で、ロットを適切な形に整えてから、.Volumeに値を渡します。
変数「tradeSize」に格納されているロット数を適切な形に整える記述を行う
if(TradeVolume < minVolume) tradeSize = minVolume;//最小ロットよりも小さい値になっていた場合、最小ロットに修正
else if(TradeVolume > maxVolume) tradeSize = maxVolume;//最大ロットよりも大きい値になっていた場合、最大ロットに修正
//ロットのステップ幅を使って、ロット数の最終調整をする。
else tradeSize = MathRound(TradeVolume / stepVolume) * stepVolume;
続いて、変数「tradeSize」に格納されているロット数を適切な形に整える記述を行います。
最小ロットよりも小さい値になっていた場合、最小ロットに修正する
最初のif文の()内条件文
(TradeVolume < minVolume)はinput変数「TradeVolume 」で設定したパラメーター値が、ブローカーの規定した取引最小ロットよりも小さい値になっている事を意味します。これではエラーになってしまうので、この場合は、
tradeSize = minVolume;
すなわち、規定されている取引最小ロットの値を変数「tradeSize」に代入します。
最大ロットよりも大きい値になっていた場合、最大ロットに修正する。
(TradeVolume > maxVolume)は、逆にinput変数「TradeVolume 」で設定したパラメーター値が、ブローカーの規定した取引最大ロットよりも大きい値になっている事を意味します。これもエラーになってしまうので、この場合も、
tradeSize = maxVolume;
すなわち、規定されている取引最大ロットの値を変数「tradeSize」に代入します。
最小ロット・最大ロットに違反していない場合の記述を行う。
最後のelse文に、最小ロット・最大ロットに違反していない場合の記述を行います。
else tradeSize = MathRound(TradeVolume / stepVolume) * stepVolume;
まず、MathRound関数の引数に、TradeVolume / stepVolumeという算式が入っているのが、見受けられます。まずはMathRound関数について説明しましょう。
MathRound関数について
MathRound関数は引数に入れた値(double型)を「丸める」処理を行う関数です。戻り値は最も近い整数に丸めた値(double型)を返します。
※「丸める」というのは、数学分野においては、計算結果や数値を一定の規則に従って、整える作業の事を言います。具体的には
「四捨五入」「切り捨て」「切り上げ」などの処理の事を指します。
MathRound関数の性質がわかったところで、改めて
MathRound(TradeVolume / stepVolume) * stepVolumeという計算式がなにをやろうとしているのかを、具体的な数値を当てはめながら見ていきましょう。
まずinput変数「TradeVolume 」ですが、サンプルコードでは0.14としてあるので、ここでも0.14としておきます。変数「stepVolume」にはブローカーが規定したロットのステップ幅、すなわち0.1か0.01が格納されています。
※「double型の変数「stepVolume」は、ロットのステップ幅を格納する」セクションを参照。
ロットのステップ幅が0.1だった場合TradeVolume / stepVolumeは0.14/0.1=1.4となります。
これをMathRound関数の()に入れて処理すると丸められて、1となります。この値にstepVolumeをかけると、1*0.1=0.1となります。
一方、ロットのステップ幅が0.01だった場合はどうなるかというと、TradeVolume / stepVolumeは0.14/0.01=14となります。
これをMathRound関数の()に入れて処理した場合、すでに整数値14となっているので14となります。この値にstepVolumeをかけると、14*0.01=0.14となります。
いかがでしょうか?
ステップ幅が0.1の時は変数「tradeSize」には、0.1が代入され、
ステップ幅が0.01の時は変数「tradeSize」には、0.14が代入される・・・
といった具合に、ブローカーが規定したロットのステップ幅に応じたロット数が変数「tradeSize」に格納できたのが、おわかりいただけるのではないか、と思います。
※基本的な計算に関する記述については、下記の記事もご参照ください。
ブローカーの規定するステップ幅に応じて正規化を行う
最後に念の為、ブローカーの規定するステップ幅に応じて正規化を行います。
※正規化というのは、プログラムが取り扱うルールに則って値を整える作業
のことを言います。
//ブローカーの規定するステップ幅に応じて正規化を行う
if(stepVolume >= 0.1) tradeSize = NormalizeDouble(tradeSize,1);
else tradeSize = NormalizeDouble(tradeSize,2);
正規化にはNormalizeDouble関数を利用します。
変数「stepVolume」の値が0.1以上のときは、小数点第1位で、
そうでない時、すなわち変数「stepVolume」の値が0.1より小さいときは、小数点第2位で、
それぞれ正規化を行います。
以上が、資金管理とロット調整を考慮した、初歩的な記述となります。
まとめ
今回は、資金管理とロット調整に関する基本的な部分を解説し、MQL5で資金管理とロット調整を行うにあたってのたたき台となるような記述についてもあわせて解説を行いました。
次回以降は、資金管理・ロット調整を容易に記述する為の関数を解説していきます。
それらの関数を一つに集約させたインクルードファイルを作っていく予定となっております。
今回は一旦以上とさせていただきます
最後までお読みいただきありがとうございました。
コメント