固定ロット(常に0.1ロットなど)でトレードを続けていると、
口座残高が増えても減っても、1回の負けで受けるダメージの「割合」
が変わり続けます。
残高が減ってきた場面ほど、同じ0.1ロットの損失が相対的に重くのしかかります。
この記事では、口座残高の常に一定%だけをリスクにさらす、「リスク%ベースのロット自動計算」
をMQL4で実装する方法を解説します。
固定ロットの何が問題なのか
固定ロットの最大の問題は、残高とロットサイズが連動しないことです。
残高10万円で0.1ロットも、残高5万円に減った後の0.1ロットも、
証拠金に対する負担も損失額も同じままです。
要点: リスク%ベースのロット計算は、
「残高の2%だけ失う」というリスク量を一定に保つ考え方です。
残高が減れば自動的にロットも減り、
連敗によるダメージの拡大を抑えられます。
複利ロットとの違い
似た発想に複利ロット(残高に比例してロットを増やす)がありますが、
複利は「増えた分を積極的に使う」設計です。
リスク%ベースは「一定のリスク量を守る」ことが目的で、
攻めよりも守りに重心がある点が異なります。
計算に使うMQL4関数: MarketInfo
ロット計算には、通貨ペアごとに異なる「1ポイントあたりの価値」を知る必要があります。
これを取得するのが`MarketInfo()`関数です。
double MarketInfo( string symbol, //対象の通貨ペア int type //取得したい情報の種類 );
1ポイントの価値を返すMODE_TICKVALUEとMODE_TICKSIZE
`MODE_TICKVALUE`は、1ロットにおける最小価格変動(ティック)1回分の、
損益額を預入通貨で返します。
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);//1ティックあたりの価値 double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE); //1ティックの価格幅
注意: 多くの4桁ブローカーでは1ティック=1ポイントですが、
5桁ブローカーではティックサイズがPointと異なる場合があります。
`MODE_TICKVALUE`をそのまま「1ポイントの価値」として使うと、
ずれた計算になることがあります。
正確には、1ポイントあたりの価値は次の式で求めます。
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE); double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE); double pointValue = tickValue * (Point / tickSize);//1ポイントあたりの価値
ロットを丸めるMODE_LOTSTEP・MODE_MINLOT・MODE_MAXLOT
計算したロット数は、そのままでは注文できません。
ブローカーが許可するロット単位(`MODE_LOTSTEP`)に丸め、
最小・最大ロット(`MODE_MINLOT`/`MODE_MAXLOT`)の、
範囲に収める必要があります。
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP); double minLot = MarketInfo(Symbol(), MODE_MINLOT); double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
リスク許容額からロット数を計算する式
計算の流れは、次の3ステップです。
ステップ1: リスク許容額を求める
口座残高に、許容するリスク%を掛けます。
double riskAmount = AccountBalance() * (RiskPercent / 100.0);
ステップ2: 損切り幅(ポイント数)で割る
このリスク許容額を、損切り幅(ポイント数)×1ポイントの価値で割ると、
ロット数が求まります。
double pointValue = tickValue * (Point / tickSize); double rawLot = riskAmount / (StopLossPoints * pointValue);
ステップ3: LOTSTEPで丸め、MIN/MAXの範囲に収める
double lot = MathFloor(rawLot / lotStep) * lotStep; if(lot < minLot) lot = minLot; if(lot > maxLot) lot = maxLot; lot = NormalizeDouble(lot, 2);
補足: `MathFloor`で切り捨てているのは、
計算上のロットを繰り上げると、
想定したリスク%をわずかに超えてしまうためです。
安全側に倒すなら切り捨てが基本です。
実際に動くコード全体(汎用ロット計算関数)
ここまでの内容をまとめた、リスク%と損切り幅を渡すとロット数を返す関数と、
実際に発注する例です。
実際にMetaEditorでコンパイルできます。
//+------------------------------------------------------------------+
//| RiskPercentLotSize.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property strict
input double RiskPercent = 2.0;//口座残高に対するリスク%
input int StopLossPoints = 300;//損切り幅(ポイント)
input int MagicNumber = 20260927;
//+------------------------------------------------------------------+
//| リスク%と損切り幅からロット数を計算する汎用関数 |
//+------------------------------------------------------------------+
double CalcLotByRisk(string symbol, double riskPercent, int slPoints)
{
double tickValue = MarketInfo(symbol, MODE_TICKVALUE);
double tickSize = MarketInfo(symbol, MODE_TICKSIZE);
double point = MarketInfo(symbol, MODE_POINT);
double lotStep = MarketInfo(symbol, MODE_LOTSTEP);
double minLot = MarketInfo(symbol, MODE_MINLOT);
double maxLot = MarketInfo(symbol, MODE_MAXLOT);
if(tickValue <= 0 || tickSize <= 0 || lotStep <= 0 || slPoints <= 0)
{
Print("MarketInfoの取得に失敗、またはslPointsが不正です。");
return(0);
}
double pointValue = tickValue * (point / tickSize);
double riskAmount = AccountBalance() * (riskPercent / 100.0);
double rawLot = riskAmount / (slPoints * pointValue);
double lot = MathFloor(rawLot / lotStep) * lotStep;
if(lot < minLot) lot = minLot;
if(lot > maxLot) lot = maxLot;
return(NormalizeDouble(lot, 2));
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(OrdersTotal() > 0)
return;//サンプルのため簡略化、実際は条件を追加してください
double lot = CalcLotByRisk(Symbol(), RiskPercent, StopLossPoints);
if(lot <= 0)
{
Print("ロット計算に失敗したため発注を見送りました。");
return;
}
double ask = MarketInfo(Symbol(), MODE_ASK);
double sl = ask - StopLossPoints * MarketInfo(Symbol(), MODE_POINT);
int ticket = OrderSend(Symbol(), OP_BUY, lot, ask, 3, sl, 0,
"RiskPercentLot", MagicNumber, 0, clrGreen);
if(ticket < 0)
Print("発注に失敗しました。エラーコード=", GetLastError());
else
Print("発注成功。ロット=", lot);
}
//+------------------------------------------------------------------+
MetaEditorで実際に動かす手順
- MT4のMetaEditorで「ファイル」→「新規作成」→「エキスパートアドバイザー」を選ぶ
- 「RiskPercentLotSize」という名前で作成し、テンプレートの中身をすべて削除して上のコードを貼り付ける
- F7キーでコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- デモ口座でチャートに適用し、Print()のログでロット計算結果を確認する
- `RiskPercent`や`StopLossPoints`を変えて、ロットが意図通りに増減するか確認する
よくあるエラーと対処
- ロットが常に0になる: `MarketInfo`が0を返している可能性があります。通貨ペア名(`Symbol()`)のスペルやブローカーのサフィックスを確認してください
- 発注エラー130(Invalid stops): `StopLossPoints`がブローカーの最小ストップ距離より小さい可能性があります。`MarketInfo(Symbol(), MODE_STOPLEVEL)`で確認してください
- 発注エラー134(証拠金不足): 計算したロットが証拠金に対して大きすぎる可能性があります。`AccountFreeMarginCheck()`で事前チェックする設計に変更してください
- 計算されるロットが毎回同じ: `AccountBalance()`ではなく固定値を参照していないか確認してください。含み損益も考慮したい場合は`AccountEquity()`に変更します
証拠金維持率ベースの計算との違い
ロット自動計算には、この記事の「リスク%ベース」のほかに、「証拠金維持率ベース」
という考え方もあります。
証拠金維持率ベースは、現在の証拠金維持率が一定水準を下回らない範囲で、
ロットを決める設計です。
リスク%ベースが向く場面: 損切り幅を明確に決めてトレードする、
裁量
・EA問わず一般的な手法
証拠金維持率ベースが向く場面: 損切りを置かない、
または長期保有前提のスワップ運用など、
証拠金の余力そのものを管理したい手法
この記事のリスク%ベースは「いくら失うか」を先に決める考え方であり、
証拠金維持率ベースは「どこまで持ちこたえられるか」を先に決める考え方です。
目的が異なるため、どちらが優れているというものではありません。
この関数を使う際の注意点
この関数は損切り幅(`StopLossPoints`)を先に決めることが前提です。
損切り幅そのものが大きすぎる・小さすぎると、
リスク%を正しく守っていても、
手法自体の期待値が悪ければ意味がありません。
注意: スプレッドが広い通貨ペアや、
深夜
・指標発表前後の急な広がりでは、想定した損切り幅より実際の損失が大きくなることがあります。
よくある質問
リスク%ベースのロット計算でよく検索されている疑問を、3つにまとめて回答します。
リスク%は何%に設定すればいいですか?
一般的には1〜2%が目安とされていますが、これは断定できる正解ではありません。
連敗が続く手法ほど低めに、勝率が高く連敗しにくい手法ほどやや高めに、
自分の手法のバックテスト結果を見ながら調整してください。
AccountBalanceとAccountEquityはどちらを使うべきですか?
含み損の影響を受けずに一定のリスクを守りたいなら`AccountBalance()`、
含み損の分だけリスクを保守的に減らしたいなら、
`AccountEquity()`が向いています。
この記事のコードは前者(`AccountBalance()`)を採用しています。
複数ポジションを同時に持つ場合はどうなりますか?
この記事の関数は1回のエントリーごとのリスク%を計算するものです。
複数ポジションを同時に持つ場合、合計のリスク%が意図せず膨らむため、
保有中のポジション数に応じてリスク%を按分する設計に拡張してください。
【MQL4】固定ロットで消耗していませんか?口座残高のリスク%からロット数を自動計算する関数の作り方:まとめ
この記事では、口座残高の一定%だけをリスクにさらす、「リスク%ベースのロット自動計算」
をMQL4で実装する方法を解説しました。
`MarketInfo()`でティック価値・ロットステップ・最小最大ロットを取得し、
リスク許容額を損切り幅で割ってからLOTSTEPで丸める、という流れが基本です。
証拠金維持率ベースの計算とは目的が異なるため、自分の手法が「損切り幅を決める手法」
か「証拠金の余力を管理したい手法」か、見極めたうえで使い分けてください。
コメント