本ページはプロモーションが含まれています

ホーム › EAプログラミング

EAプログラミング

MT4開発者必見!リスク1%を守るロット計算コードの完全実装ガイド

↻

トム

トム

現役エンジニア(本業はJavaバックエンド)。以前はMT4のEAを自作してFX自動売買をしていました(現在は引退)。今はポイ活を「時給」で検証・攻略しています。

結論から言うと、MT4でリスク1%を守るロット数は「口座残高×1%÷(損切り幅×1ロットあたりの値幅価値)」で計算します。値幅価値はMarketInfo()のMODE_TICKVALUEで取得し、結果をMODE_LOTSTEPの刻み幅に切り捨て、MODE_MINLOT〜MODE_MAXLOTの範囲に収めれば、業者ごとの仕様差でも注文エラーになりません。

ロット計算(ポジションサイジング)とは、1回の取引で許容する損失額から逆算して、発注する数量(ロット数)を決める資金管理の手法です。本記事では、この計算をMQL4で実装するコードを段階的に紹介します。

FXの自動売買(EA)を作っていて、一番絶望するのはどんな時でしょうか。ロジックが外れた時?それも痛いですが、一番は「たった1回の負けで、積み上げた利益が全部吹き飛んだ時」ですよね。私も初心者の頃、自作EAのテスト中にロット設定を間違えて、数ヶ月分の利益を1晩で溶かした苦い経験があります。あの時の、胃がキュッとなる感覚は二度と味わいたくありません。

この記事を書こうと思ったのは、多くの開発者が「エントリー条件」には血道を上げるのに、「ロット計算」はかなり適当に済ませている現状を目の当たりにしてきたからです。エントリーロジックが同じでも、ロットが大きすぎれば数回の連敗で口座は破綻します。資金管理はロジックと同じくらい重要です。

私が5年以上の開発経験の中で辿り着いた、堅牢で柔軟なロット計算コードを公開します。これを読めば、初心者でも「いくらでエントリーすべきか」という不安から解放され、プロレベルの資金管理機能を自分のEAに実装できるようになります。もう、相場の急変に怯えて夜中にスマホを確認する必要はありません。

MT4のロットとは?1ロットの通貨量と業者差

MT4のロットとは、注文数量を表す単位で、1ロットが何通貨かは業者の仕様で決まります。

おさらいですが、ロットとは、通常、取引される通貨単位のことを指します。業者にもよりますが、FX取引では1ロット=100,000通貨とされています。この「1ロット」の重みが、実は初心者には掴みづらいものです。

MT4でEAを動かす際、ロットは単なる数字以上の意味を持ちます。それはあなたの口座の「寿命」を決定するレバーです。10万円の資金に対して1ロットで入るのと、0.01ロットで入るのでは、1ピップス動いた時の含み損の重みが100倍違います。

根拠なく0.1ロットや1.0ロットを固定で設定するのは、目隠しをして高速道路を走るようなものです。業者の仕様やレバレッジの設定によって、同じ1ロットでも必要な証拠金は変わります。まずは、ロットが自分の資金に対してどれだけの負荷をかけるのかを、数値で正しく把握する習慣をつけましょう。

1ロットの定義と業者の違い

1ロットの単位は世界共通ではありません。国内業者には1ロット=1万通貨とするところもありますが、MT4を採用している海外業者の主流は1ロット=10万通貨です。この違いをコード内で吸収しておかないと、運用を開始した瞬間に意図しない巨大なポジションを持ってしまうリスクがあります。

私は過去に、1万通貨単位のつもりで書いたコードを10万通貨単位の業者で動かしてしまい、開始3分で強制ロスカットを食らったことがあります。笑えません。こうした「業者の癖」をEA側に自動で判断させるロジックを組み込むのが、プロの仕事です。

リスク1%のロット数はどう計算する?「リスク許容度」ベースの計算術

結論から言うと、ロット計算はあなたのリスク許容度を元に行われるべきです。固定ロットで運用するのは、資金が増えてもチャンスを逃し、資金が減ってもリスクを下げられない非効率な手法だからです。

リスク許容度ベースのロット計算の流れ

1
リスク金額を出す
口座残高 × リスク許容度(%)
2
1ロットあたりの損失を出す
ストップロス(pips)× pips単価
3
ロットを求める
リスク金額 ÷ 1ロットあたりの損失
4
端数を切り捨てる
0.01ロット単位で切り捨て(四捨五入するとリスクが1%を超えることがある)

以下に、口座残高とリスク許容度(パーセンテージ)を元にしたロット計算の一例を示します。

double calculateLot(double accountBalance, double riskPercent, double stopLossPips) {
    double riskAmount = accountBalance * riskPercent;  // riskPercentは1%なら0.01を渡す
    double pipValue = 1000;  // 円建て口座でドル円1ロット(10万通貨)の1pipsの価値(円)
    double lot = riskAmount / (stopLossPips * pipValue);
    return MathFloor(lot * 100 + 0.0000001) / 100;  // 0.01ロット単位で切り捨て(四捨五入だとリスクが指定を超えることがある)
}

この関数では、まず口座残高とリスク許容度(パーセント)を掛けて1回のトレードで許容する損失金額を計算します。次に、その金額をストップロスのピップ数とピップ値で割ります。これにより、あなたが許容できるリスクでロット数が計算されます。

例えば、残高1,000,000円でリスクを1%にするなら、1回の負けを10,000円に抑える計算です。ストップロスが20ピップスなら、1ピップスあたり500円の価値を持つロット数を算出します。こうすることで、連敗しても資金が急激に減るのを防ぎ、心理的な安定も得られます。

あわせて読むEAのロット数の決め方|リスク1%・最大DD・複利を計算例で解説EAのロット数は「口座残高×リスク%÷(損切り幅×1pipsの価値)」で決めます。リスク1%と最大DDからの計算例に加え、MT4でEAのロットを変更する手順、固定ロットと複利の切替、変更が反映されないときの確認点も解説します。

リスク許容度を固定しない柔軟性

リスク1%というのは一つの目安ですが、相場のボラティリティが高い時には0.5%に落とし、勝率が高い局面では2%に上げるといった戦略も有効です。私は常に、外部パラメーターからこのリスク比率を変更できるように設計しています。

計算式の中にある pipValue = 1000 という部分は、円建て口座でドル円を1ロット(10万通貨)取引したときの1pipsの価値(1,000円)を固定で入れた簡易的なものです。しかし、実際には通貨ペアごとにこの値は変動します。次のセクションでは、この「ピップ値の罠」を回避する方法を説明します。

【実践】MarketInfoを活用した万能ロット計算コード

このセクションの要点は、値幅価値とロット制限をMarketInfo()で業者から取得すれば、通貨ペアや業者が変わっても同じコードで正しいロットを出せることです。

先ほどの簡易コードには弱点があります。それは、pips値の変動や業者の制限を考慮していない点です。口座通貨と決済通貨が異なる通貨ペアでは、1pipsの価値は為替レートに応じて変わります。また、業者によっては最小ロットが0.01だったり0.1だったりしますし、最大ロットの制限も存在します。

これらを解決した、より実践的なソースコードがこちらです。

// riskPercentは1%なら0.01、stopLossPipsはpips単位で渡す
double calculateLot(double accountBalance, double riskPercent, double stopLossPips, double minLot, double maxLot) {
    if (stopLossPips <= 0) return 0;  // 0除算を防ぐ
    double riskAmount = accountBalance * riskPercent;         // 1回の許容損失額(口座通貨)
    double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);  // 1ロットが1ティック動いたときの損益(口座通貨)
    double tickSize  = MarketInfo(Symbol(), MODE_TICKSIZE);   // 1ティックの値幅
    double step      = MarketInfo(Symbol(), MODE_LOTSTEP);    // ロットの刻み幅
    if (tickValue <= 0 || tickSize <= 0 || step <= 0) return 0;
    double pipSize  = (Digits == 3 || Digits == 5) ? Point * 10 : Point;  // 1pipsの値幅(5桁・3桁業者はPointの10倍)
    double pipValue = tickValue * pipSize / tickSize;        // 1ロットが1pips動いたときの損益(口座通貨)
    double lot = riskAmount / (stopLossPips * pipValue);
    lot = MathFloor(lot / step + 0.0000001) * step;  // 刻み幅に切り捨て(微小値は浮動小数点の誤差対策)
    if (lot < minLot) lot = minLot;  // 最小ロットに引き上げた場合、実際のリスクは指定より大きくなる
    if (lot > maxLot) lot = maxLot;
    return NormalizeDouble(lot, 2);
}

この関数では、MarketInfo() 関数を使用して MODE_TICKVALUE(1ロットが1ティック動いたときの口座通貨建ての損益)と MODE_TICKSIZE(1ティックの値幅)を取得し、1pipsあたりの価値に換算しています。

1pipsの値幅は、5桁(円は3桁)表示の業者なら Point の10倍、4桁(円は2桁)表示なら Point そのものです。5桁業者では1ティック=0.1pipsなので、この換算をしないとロットが10倍に膨らみます。換算しておけば、ユーロドルでもポンド円でも、その時のレートを反映した1pipsの価値でロットが計算されます。

さらに重要なのが MODE_LOTSTEP です。ロットは0.01刻みで注文できる業者もあれば、0.1刻みの業者もあります。計算結果が0.055ロットになったとして、0.1刻みの業者に注文を出せばエラーで止まります。このコードは、業者の最小刻み幅に合わせて端数を切り捨てる処理を入れているため、エラー知らずです。

MarketInfoを使ったロット計算の処理順

◆① 損切り幅をチェック
0以下 → 0を返して発注しない(0除算を防ぐ)
▼0より大きい
② 許容損失額を出す
口座残高 × riskPercent(1%なら0.01)
▼
③ 1ロットが1pips動いたときの損益を出す
MODE_TICKVALUE × 1pipsの値幅 ÷ MODE_TICKSIZE
(5桁・3桁業者は1pips=Pointの10倍)
▼
④ ロットを求める
許容損失額 ÷(損切り幅pips × 1pipsの価値)
▼
⑤ 刻み幅に切り捨てる
MathFloor(lot ÷ MODE_LOTSTEP + 微小値) × MODE_LOTSTEP
▼
⑥ 最小・最大ロットの範囲に収める
最小未満なら最小ロットへ引き上げ(実際のリスクは指定より大きくなる)
最大超なら最大ロットへ

MarketInfoで取得したTICKVALUE・TICKSIZE・LOTSTEPのどれかが0以下のときも0を返して発注を見送る。

なぜMODE_TICKVALUEが必要なのか

通貨ペアの右側(決済通貨)が円でない場合、例えばEUR/USDなら、1ピップスの価値はドルの価値に依存します。1ドル150円の時と100円の時では、円建て口座におけるリスク額が1.5倍も変わってしまいます。

これを手動で計算するのは不可能です。MarketInfo() を使えば、MT4がバックグラウンドで現在の為替レートを反映した「1ティックの価値」を自動で計算してくれます(上のコードではこれを1pipsの価値に換算しています)。これを使わない手はありません。私は、この関数を知ってからロット計算のエラーで悩むことが一切なくなりました。

動的ロット調整:調子に合わせてアクセルを踏む

自動取引システムの成功は、その戦略だけでなく、ロットサイズの適切な管理にも依存しています。常に同じリスクを取るのも一つの正解ですが、EAの好不調に合わせてロットを増減させる「動的ロット調整」を取り入れると、相場との相性に応じてリスクの取り方を変えられます。

例えば、EAが市場の動向に対してポジティブなパフォーマンスを示す時期では、ロットサイズを増やすことで利益を最大化することが可能です。逆に、市場が不安定でEAのパフォーマンスが低下している場合には、ロットサイズを小さくすることで潜在的なリスクを減らせます。

以下に、パフォーマンスに基づく動的なロットサイズ調整の一例を示します。

double adjustLotSize(double accountBalance, double riskPercent, double stopLossPips, double performanceIndex, double minLot, double maxLot) {
    double baseLot = calculateLot(accountBalance, riskPercent, stopLossPips, minLot, maxLot);
    if (baseLot <= 0) return 0;
    double step = MarketInfo(Symbol(), MODE_LOTSTEP);
    double adjustedLot = baseLot * performanceIndex;
    adjustedLot = MathFloor(adjustedLot / step + 0.0000001) * step;  // 掛け算後も刻み幅に切り捨てる
    if (adjustedLot < minLot) adjustedLot = minLot;
    if (adjustedLot > maxLot) adjustedLot = maxLot;
    return NormalizeDouble(adjustedLot, 2);
}

ここでは、performanceIndex というパラメータを追加しました。これはあなたのEAのパフォーマンスを表す指標で、EAが良好なパフォーマンスを示すときには1以上、パフォーマンスが低下すると1未満に設定します。

指標の決め方には細心の注意を

この performanceIndex をどう算出するかが腕の見せ所です。直近20トレードの勝率を使うのか、プロフィットファクターを使うのか。私は、移動平均線のように直近の利益曲線の傾きを見て、右肩上がりならアクセルを踏むというロジックを好んで使います。

ただし、注意点があります。負けている時に「取り返そう」としてロットを上げる(マーチンゲール的な発想)のは、動的調整ではなくただのギャンブルです。この指標は、あくまで「システムが相場に合っているかどうか」を測るためのものだと肝に銘じてください。

あわせて読むナンピン・マーチン・両建EAは危険?何段で破綻するか計算で解説ナンピン・マーチン・両建EAの危険性を計算で解説。初期0.01ロット・20pips間隔の倍々ナンピンが何pipsの逆行で破綻するか、両建ての落とし穴、最大ポジション数と証拠金維持率の決め方まで数値でわかります。

具体的なEA設定例:注文処理への組み込み

さて、ここまで解説してきたロットサイズ計算を、実際のEAの注文処理部分にどう組み込むのかを見てみましょう。机上の空論で終わらせないのがプロの流儀です。

以下のコードは、注文を発行する直前に最新の残高とリスク設定を読み込み、ロットを算出してから OrderSend() を呼び出す流れです。

void handleOrder(double accountBalance, double riskPercent, double stopLossPips, double performanceIndex, double minLot, double maxLot) {
    double lot = adjustLotSize(accountBalance, riskPercent, stopLossPips, performanceIndex, minLot, maxLot);
    if (lot <= 0) {
        Print("ロットを計算できないため発注を見送ります");
        return;
    }
    double pipSize = (Digits == 3 || Digits == 5) ? Point * 10 : Point;  // 1pipsの値幅
    double sl = NormalizeDouble(Ask - stopLossPips * pipSize, Digits);   // pipsを価格に換算した損切り価格
    int ticket = OrderSend(Symbol(), OP_BUY, lot, Ask, 3, sl, 0, "My order", 12345, 0, Green);
    if (ticket < 0) {
        Print("OrderSend failed with error #", GetLastError());
    } else {
        Print("OrderSend placed with ticket #", ticket);
    }
}

この関数 handleOrder は、引数としてリスク設定やストップロス幅を受け取ります。内部で adjustLotSize を呼び出し、常に最新の口座状況に基づいたロットを算出します。

実運用での「もしも」に備える

実際の相場では、注文を出した瞬間にサーバーが切断されたり、注文が拒絶されたりすることがあります。このコードでは ticket < 0 の場合にエラーログを出すようにしていますが、より堅牢にするなら、エラーコードに応じて数秒後にリトライする処理を追加するのが望ましいです。

また、Point を使ったストップロスの計算は、3桁・5桁業者の違い(いわゆる10倍の差)を考慮する必要があります。上のコードでは、Digits が3か5なら Point の10倍を1pipsとして損切り価格に換算しています。私はこの部分を共通ライブラリ化して、どの業者でも同じ感覚でpips指定ができるように共通化しています。

業者の「罠」を回避する:MODE_LOTSTEPの重要性

ロット計算で意外と見落としがちなのが、業者が設定している「ロットの刻み幅」です。多くのプログラミング解説では無視されがちですが、実運用ではこれが原因でEAが止まることがよくあります。

例えば、計算結果が「0.1234...ロット」となった場合、多くの人は単純に NormalizeDouble(lot, 2) で0.12に丸めます。しかし、もしその業者の最小刻み(MODE_LOTSTEP)が「0.1」だった場合、0.12という注文は不正なロットとして拒絶されます。

これを防ぐには、以下のような処理が確実です。

double step = MarketInfo(Symbol(), MODE_LOTSTEP);
double finalLot = MathFloor(lot / step + 0.0000001) * step;  // 微小値は浮動小数点の誤差対策(0.7÷0.1が6.999…になる)
finalLot = NormalizeDouble(finalLot, 2);                     // 0.30000000000000004 のような端数を消す

このように、一度刻み幅で割って整数化し、再度刻み幅を掛けることで、業者が許容する正確なロット数に整形できます。私はこれを「お作法」として、すべてのEAに実装しています。こうした細かい配慮が、長期稼働時の安定性に直結します。

通貨ペアごとの計算:クロス円とドルストレートの違い

MT4の MODE_TICKVALUE は便利ですが、計算の仕組みを理解しておかないと思わぬ誤解を招きます。実は、この値は「口座の通貨」によって意味が変わるからです。

あなたの口座が「円建て」であれば、MODE_TICKVALUE は「1ロットが1ティック動いた時の円での損益額」を返します。5桁(円は3桁)表示の業者では1ティック=0.1pipsなので、1pipsの損益はこの値の10倍です。しかし、もし「ドル建て」口座を使っているなら、それはドルでの額になります。

ドル円・クロス円の場合

USD/JPY(ドル円)や、EUR/JPYなどのクロス円のように円が決済通貨の通貨ペアでは、1ピップス(0.01)の価値はロット数に依存します。1ロット(10万通貨)なら、1ピップス動けば1,000円です。

ドルストレートの場合

EUR/USDなどでは、1ピップス(0.0001)の価値は現在のUSD/JPYのレートに左右されます。ドル円が150円なら、1ドル分の動きは150円の価値を持ちます。

これらの複雑な計算をすべて MarketInfo() が引き受けてくれるわけですが、バックテスト時には注意が必要です。バックテストで使用するヒストリカルデータに、その時のクロスレート(ドル円など)が含まれていないと、正確なロット計算ができず、テスト結果が歪むことがあります。私は常に、全通貨ペアのデータを同期させてからテストを行うようにしています。

実装時の落とし穴とデバッグのコツ

コードを書いてコンパイルが通っても、それで安心ではありません。ロット計算は「お金」に直結する部分なので、リリース前に徹底的にデバッグする必要があります。

私がよくやる手法は、Print() 関数を使って、計算の過程をすべてログに出力することです。

Print("--- ロット計算デバッグ ---");
Print("口座残高: ", accountBalance);
Print("リスク額: ", riskAmount);
Print("TICKVALUE: ", tickValue);
Print("1pipsの価値: ", pipValue);
Print("計算されたロット: ", lot);

このように、計算のステップごとに値を確認することで、「なぜかロットが0.01固定になってしまう」といったミス(多くの場合は型変換のミスや Point の勘違い)を早期に発見できます。

特に、0除算(Division by zero)には注意してください。ストップロスを0に設定してしまった場合などにこのエラーが発生し、EAがクラッシュします。計算の前に必ず if(stopLossPips > 0) といったチェックを入れるのが、安定したEAを作るコツです。

10年先の相場でも生き残るための設計思想

最後に、技術的な話から少し離れて、設計思想についてお話しします。私はこれまでに何百ものEAを見てきましたが、生き残っているのは例外なく「資金管理が保守的で堅牢なもの」だけです。

ロット計算のコードをどれだけ洗練させても、元となる「リスク許容度」の設定を誤れば意味がありません。マーケットは常に私たちの想像を超えた動きをします。スイスフランショックのような暴騰暴落が起きれば、どれほど計算されたストップロスも滑ります(スリッページ)。

そのため、ロット計算には常に「最悪の事態」を想定したバッファを持たせることをお勧めします。例えば、計算されたロットが口座維持率を圧迫しすぎる場合は、さらに制限をかけるといった二重の防御策です。

あわせて読むEAの資金管理と破産確率|バルサラ表とロット計算で破産を防ぐEA(MT4自動売買)の資金管理を破産確率から解説。ロット計算式、バルサラの破産確率の計算式と早見表、証拠金維持率・ロスカット水準、複数EAの資金配分まで数値で確認できます。

ツールを過信しない勇気

いくらEAが優れていても、それはあくまでツールであり、100%の利益を保証するものではありません。マーケットは常に変動し、EAもそれに適応する必要があります。ロット計算を自動化したからといって放置するのではなく、定期的にパフォーマンスを確認し、必要に応じてパラメーターを微調整する。この「人間による管理」を放棄しないことが、最終的な勝敗を分けます。

よくある質問

Q1. MT4でリスク1%のロット数はどう計算しますか?

A1. 「口座残高×0.01」で1回の許容損失額を出し、それを「損切り幅×1ロットあたりの値幅価値」で割ります。例えば残高100万円・損切り20pipsのドル円(1ロット=10万通貨で1pips=1,000円)なら、10,000÷(20×1,000)=0.5ロットです。

Q2. MODE_TICKVALUEとは何ですか?

A2. MODE_TICKVALUEとは、MarketInfo()で取得できる「1ティック(価格の最小変動)あたりの損益額を口座通貨で表した値」です。1ティックの大きさはMODE_TICKSIZEで確認できます。5桁(円は3桁)表示の業者では1ティック=0.1pipsなので、pips単位の損切り幅と組み合わせるときは単位をそろえてください。

Q3. 業者ごとの最小ロット・最大ロット・刻み幅はどう取得しますか?

A3. MarketInfo(Symbol(), MODE_MINLOT)で最小ロット、MODE_MAXLOTで最大ロット、MODE_LOTSTEPで刻み幅を取得できます。計算結果はMathFloor(lot / step + 0.0000001) * stepで刻み幅に切り捨て(微小値は浮動小数点の誤差対策)、最小〜最大の範囲に収めてから発注します。

Q4. 本記事のコードのriskPercentには1と0.01のどちらを渡しますか?

A4. 0.01を渡します。本記事のコードはaccountBalance * riskPercentと単純に掛け算しているためです。1を渡すと残高の100%を1回の損失許容額とする計算になるので注意してください。

Q5. ロット計算には口座残高と有効証拠金のどちらを使うべきですか?

A5. より保守的にしたいなら有効証拠金です。口座残高はAccountBalance()、含み損益を反映した有効証拠金はAccountEquity()やAccountInfoDouble(ACCOUNT_EQUITY)で取得できます。含み損を抱えたまま複数ポジションを持つEAでは、有効証拠金ベースのほうがリスクを過小評価しにくくなります。

Q6. 損切り幅が0のままロット計算するとどうなりますか?

A6. 計算式が0除算になり、EAの処理が正常に続行できなくなります。計算の前にif(stopLossPips > 0)のようなチェックを入れ、0以下なら発注しない処理にしておくのが安全です。

Q7. リスクは何%に設定するのが妥当ですか?

A7. 本記事では1%を目安にしていますが、最適値は資金量や戦略の最大連敗数で変わります。例えば1%リスクで10連敗すると、残高は約9.6%減ります(0.99の10乗≒0.904)。バックテストで最大連敗数を確認してから決めてください。

まとめ

MT4のEAにおけるロット計算は、単なる算数ではなく、生き残るための戦略そのものです。本記事で紹介した MarketInfo() を活用した動的な計算ロジックを実装することで、あなたのEAはよりプロフェッショナルで堅牢なものに進化します。

「リスク1%」という規律をコードに託すことで、感情に左右されないトレードが可能になります。今回紹介したソースコードをベースに、自分の戦略に合わせたカスタマイズを加えてみてください。

次は、あなたのEAに「ドローダウンに応じたリスク制限機能」を追加してみるのはいかがでしょうか?もし興味があれば、その実装方法についても詳しくお伝えできますよ。

※本記事は情報提供を目的としたもので、特定のEA・金融商品の売買を推奨するものではありません。FX(外国為替証拠金取引)は元本が保証されておらず、レバレッジにより預けた証拠金を上回る損失が発生する可能性があります。記事内の成績・数値は過去の実績であり、将来の利益を保証するものではありません。投資の最終判断はご自身の責任でお願いします。

QUEST CLEAR!

最後まで読んでくれて、ありがとうございます。
つぎのクエストは、この下から選べます。

トム

この記事を書いた人トム

・現役エンジニア(本業はJavaバックエンド)
・以前はMT4のEAを自作してFX自動売買をしていました(現在は引退)
・今はポイ活を「時給」で検証・攻略しています