MQL5でEA開発 67 ロット数の上限の設定
ロット数の上限の設定
ロット数の上限の設定をします。
ロット数はユニットで管理するつもりでいます。
しかし、データに異常があって、過大なロット数になる可能性がないわけではありません。
そこでロット数の上限を設定して、ロット数がそれより大きくならないようにすると安心です。
ここではMathMin関数を使用しました。
サンプルコード
double ATR(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift)
{
/*
symbol:銘柄
timeframe:足の種類
period:計算期間
shift:シフト
*/
int handle=iATR(symbol,timeframe,period); // ハンドル
double res[1]; // 戻り値
CopyBuffer(handle,0,shift,1,res);
return(res[0]);
}
double N(string symbol)
{
/*
symbol:銘柄
*/
double atr2=ATR(symbol,PERIOD_D1,20,2); // 2日前の足のATR
double tr1=ATR(symbol,PERIOD_D1,1,1); // 前日の足のTR
double res=(atr2*19.0+tr1*2.0)/21.0; // 戻り値
return(res);
}
double Unit(string symbol, double equity)
{
/*
symbol:銘柄
equity:有効証拠金
*/
//--- 1ロットに必要な証拠金を計算する
double price=SymbolInfoDouble(symbol,SYMBOL_ASK); // 基準とする価格(リスクを少しでも小さくするため、より大きなASKを価格とする)
double margin=0; // 1ロットに必要な証拠金(レバレッジで割った分だけ小さく、初期証拠金率を掛けた分だけ大きくなっている)
if(!OrderCalcMargin(ORDER_TYPE_BUY,symbol,1.0,price,margin)) // 成行買い、成行売りの初期証拠金率は同値が普通なので、とりあえずタイプは成行買いにしておく
{
Print("1ロットに必要な証拠金の計算に失敗しました");
}
//--- 調整証拠金を計算する
long leverage=AccountInfoInteger(ACCOUNT_LEVERAGE); // レバレッジ(国内業者であれば25倍が普通)
double initial_margin_rate=0.0; // 初期証拠金率
double maintenance_margin_rate=0.0; // 維持証拠金率。引数の数合わせに使うだけで、実際には使わない
SymbolInfoMarginRate(symbol,ORDER_TYPE_BUY,initial_margin_rate,maintenance_margin_rate); // 上記の理由でタイプは成行買いにしておく
double adj_margin=0.0; // 調整証拠金(レバレッジ1倍、初期証拠金率1の1ロットに必要な証拠金)
if(initial_margin_rate!=0.0)
adj_margin=margin*leverage/initial_margin_rate; // レバレッジを掛け、初期証拠金率で割ってレバレッジ1倍、初期証拠金率1に調整する
else
return(0.0);
//--- 調整証拠金に基づいたロット数を計算する
double lot_by_adj_margin=equity/adj_margin; // 調整証拠金に基づいたロット数(レバレッジ1倍、初期証拠金率1でのロット数)
//--- Nの価格比を計算する
double n=N(symbol); // N
double n_ratio=0.0; // Nの価格比
if(price!=0.0)
n_ratio=n/price;
else
return(0.0);
//--- 戻り値を計算する
/*
戻り値はタートルのユニットである。
計算について説明すると、
ユニットは価格がNの価格比だけ変動したときに資金が1%変動するようなロット数である。
ここでは有効証拠金を資金とする。
調整証拠金に基づいたロット数は価格が1%変動したときに有効証拠金が1%変動するようなロット数である。
したがって、Nの価格比が1%であれば、ユニットは調整証拠金に基づいたロット数と等しい。
また、Nの価格比が1%より大きければ ユニットは調整証拠金に基づいたロット数より小さくなる。
逆に、Nの価格比が1%より小さければ ユニットは調整証拠金に基づいたロット数より大きくなる。
つまり、ユニットは0.01/Nの価格比に比例する。
そこで、ユニットは調整証拠金に基づいたロット数に0.01/Nの価格比を掛けて求める。
*/
double res=lot_by_adj_margin*0.01/n_ratio; // 戻り値
//--- 戻り値を最大ボリューム以下、最小ボリューム以上に調整する
double volume_step=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP); // ボリュームステップ(ここのボリュームはロット数のこと。以下同じ)
res=MathFloor(res/volume_step)*volume_step; // 戻り値をボリュームステップ刻みにして、余りは切り捨てる
double volume_max=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX); // 最大ボリューム
if(res>volume_max)
res=volume_max;
double volume_min=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN); // 最小ボリューム
if(res<volume_min)
res=volume_min;
return(res);
}
void OnTick()
{
double equity=30000000.0; // 有効証拠金
double unit=Unit(_Symbol,equity); // ユニット
double max_lot=0.3; // ロット数の上限
double lot=MathMin(unit,max_lot); // ロット数
Print("unit=",unit);
Print("max_lot=",max_lot);
Print("lot=",lot);
}
有効証拠金は300万円のつもりが3000万円でユニットを計算してしまったとします。
すると、リスクはいきなり10倍になってしまいます。
一方、300万円の有効証拠金なら直近で1ユニットは多くても0.2ロット程度だったので、ロット数の上限を0.3ロットにしておきました。
メッセージ
2023.12.29 00:00:00 unit=1.76
2023.12.29 00:00:00 max_lot=0.3
2023.12.29 00:00:00 lot=0.3
ユニットは誤って1.76ロットになってしまいました。
本来なら0.17ロットのはずです。
リスクは10倍となりました。
しかし、ロット数の上限を0.3ロットに設定しています。
このため、実際のロット数は0.3ロットとなりました。
リスクを2倍以内に抑えることができたわけです。
バックテストの設定であれば、バックテストに影響しないように十分な大きさで設定しておきます。
具体的にはバックテスト期間における最大ユニットを上回る大きさにしておきます。
実際のトレードであれば、直近のユニットの2倍以内にしておけば安心でしょう。