FXの自動売買(EA)を作っていて、一番絶望するのはどんな時でしょうか。ロジックが外れた時?それも痛いですが、一番は「たった1回の負けで、積み上げた利益が全部吹き飛んだ時」ですよね。私も初心者の頃、自作EAのテスト中にロット設定を間違えて、数ヶ月分の利益を1晩で溶かした苦い経験があります。あの時の、胃がキュッとなる感覚は二度と味わいたくありません。
この記事を書こうと思ったのは、多くの開発者が「エントリー条件」には血道を上げるのに、「ロット計算」は驚くほど適当に済ませている現状を目の当たりにしてきたからです。実は、EAが破綻する原因の多くはロジックの不備ではなく、資金管理の欠如にあります。
この記事では、私が5年以上の開発経験の中で辿り着いた、堅牢で柔軟なロット計算コードを公開します。これを読めば、初心者でも「いくらでエントリーすべきか」という不安から解放され、プロレベルの資金管理機能を自分のEAに実装できるようになります。もう、相場の急変に怯えて夜中にスマホを確認する必要はありません。
MT4におけるロットの正体
おさらいですが、ロットとは、通常、取引される通貨単位のことを指します。業者にもよりますが、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側に自動で判断させるロジックを組み込むのが、プロの仕事と言えます。
破綻を防ぐ「リスク許容度」ベースの計算術
結論から言うと、ロット計算はあなたのリスク許容度を元に行われるべきです。固定ロットで運用するのは、資金が増えてもチャンスを逃し、資金が減ってもリスクを下げられない非効率な手法だからです。
以下に、口座残高とリスク許容度(パーセンテージ)を元にしたロット計算の一例を示します。
double calculateLot(double accountBalance, double riskPercent, double stopLossPips) {
double riskAmount = accountBalance * riskPercent;
double pipValue = 10;
double lot = riskAmount / (stopLossPips * pipValue);
return NormalizeDouble(lot, 2);
}この関数では、まず口座残高とリスク許容度(パーセント)を掛けて1回のトレードで許容する損失金額を計算します。次に、その金額をストップロスのピップ数とピップ値で割ります。これにより、あなたが許容できるリスクでロット数が計算されます。
例えば、残高1,000,000円でリスクを1%にするなら、1回の負けを10,000円に抑える計算です。ストップロスが20ピップスなら、1ピップスあたり500円の価値を持つロット数を算出します。こうすることで、連敗しても資金が急激に減るのを防ぎ、心理的な安定も得られます。
リスク許容度を固定しない柔軟性
リスク1%というのは一つの目安ですが、相場のボラティリティが高い時には0.5%に落とし、勝率が高い局面では2%に上げるといった戦略も有効です。私は常に、外部パラメーターからこのリスク比率を変更できるように設計しています。
計算式の中にある pipValue = 10 という部分は、ドル円(100円計算)を想定した簡易的なものです。しかし、実際には通貨ペアごとにこの値は変動します。次のセクションでは、この「ピップ値の罠」を回避する方法を深掘りしましょう。
【実践】MarketInfoを活用した万能ロット計算コード
先ほどの簡易コードには弱点があります。それは、pips値の変動や業者の制限を考慮していない点です。一部の通貨ペアでは、pips値が10ではない場合があります。また、業者によっては最小ロットが0.01だったり0.1だったりしますし、最大ロットの制限も存在します。
これらを解決した、より実践的なソースコードがこちらです。
double calculateLot(double accountBalance, double riskPercent, double stopLossPips, double minLot, double maxLot) {
double riskAmount = accountBalance * riskPercent;
double pipValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double lot = riskAmount / (stopLossPips * pipValue);
lot = NormalizeDouble(lot, 2);
if (lot < minLot) lot = minLot;
if (lot > maxLot) lot = maxLot;
return lot;
}この関数では、MarketInfo() 関数を使用して MODE_TICKVALUE を取得しています。これにより、ユーロドルでもポンド円でも、その時のリアルタイムなピップ値を元に正確なロットが計算されます。
さらに重要なのが MODE_LOTSTEP です。ロットは0.01刻みで注文できる業者もあれば、0.1刻みの業者もあります。計算結果が0.055ロットになったとして、0.1刻みの業者に注文を出せばエラーで止まります。このコードは、業者の最小刻み幅に合わせて端数を切り捨てる処理を入れているため、エラー知らずです。
なぜMODE_TICKVALUEが不可欠なのか
通貨ペアの右側(決済通貨)が円でない場合、例えばEUR/USDなら、1ピップスの価値はドルの価値に依存します。1ドル150円の時と100円の時では、円建て口座におけるリスク額が1.5倍も変わってしまいます。
これを手動で計算するのは不可能です。MarketInfo() を使えば、MT4がバックグラウンドで現在の為替レートを反映した「1ピップスの価値」を自動で計算してくれます。これを使わない手はありません。私は、この関数を知ってからロット計算のエラーで悩むことが一切なくなりました。
動的ロット調整:調子に合わせてアクセルを踏む
自動取引システムの成功は、その戦略だけでなく、ロットサイズの適切な管理にも依存しています。常に同じリスクを取るのも一つの正解ですが、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);
double adjustedLot = baseLot * performanceIndex;
if (adjustedLot < minLot) adjustedLot = minLot;
if (adjustedLot > maxLot) adjustedLot = maxLot;
return adjustedLot;
}ここでは、performanceIndex というパラメータを追加しました。これはあなたのEAのパフォーマンスを表す指標で、EAが良好なパフォーマンスを示すときには1以上、パフォーマンスが低下すると1未満に設定します。
指標の決め方には細心の注意を
この performanceIndex をどう算出するかが腕の見せ所です。直近20トレードの勝率を使うのか、プロフィットファクターを使うのか。私は、移動平均線のように直近の利益曲線の傾きを見て、右肩上がりならアクセルを踏むというロジックを好んで使います。
ただし、注意点があります。負けている時に「取り返そう」としてロットを上げる(マーチンゲール的な発想)のは、動的調整ではなくただのギャンブルです。この指標は、あくまで「システムが相場に合っているかどうか」を測るためのものだと肝に銘じてください。
具体的な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);
int ticket = OrderSend(Symbol(), OP_BUY, lot, Ask, 3, Ask - stopLossPips * Point, 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倍の差)を考慮する必要があります。私はこの部分を共通ライブラリ化して、どの業者でも同じ感覚で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) * step;このように、一度刻み幅で割って整数化し、再度刻み幅を掛けることで、業者が許容する正確なロット数に整形できます。私はこれを「お作法」として、すべてのEAに実装しています。こうした細かい配慮が、長期稼働時の安定性に直結します。
通貨ペアごとの計算:クロス円とドルストレートの違い
MT4の MODE_TICKVALUE は非常に便利ですが、計算の仕組みを理解しておかないと思わぬ誤解を招きます。実は、この値は「口座の通貨」によって意味が変わるからです。
あなたの口座が「円建て」であれば、MODE_TICKVALUE は「1ピップス動いた時の円での損益額」を返します。しかし、もし「ドル建て」口座を使っているなら、それはドルでの額になります。
クロス円の場合
USD/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: ", pipValue);
Print("計算されたロット: ", lot);このように、計算のステップごとに値を確認することで、「なぜかロットが0.01固定になってしまう」といったミス(多くの場合は型変換のミスや Point の勘違い)を早期に発見できます。
特に、0除算(Division by zero)には注意してください。ストップロスを0に設定してしまった場合などにこのエラーが発生し、EAがクラッシュします。計算の前に必ず if(stopLossPips > 0) といったチェックを入れるのが、安定したEAを作るコツです。
10年先の相場でも生き残るための設計思想
最後に、技術的な話から少し離れて、設計思想についてお話しします。私はこれまでに何百ものEAを見てきましたが、生き残っているのは例外なく「資金管理が保守的で堅牢なもの」だけです。
ロット計算のコードをどれだけ洗練させても、元となる「リスク許容度」の設定を誤れば意味がありません。マーケットは常に私たちの想像を超えた動きをします。スイスフランショックのような暴騰暴落が起きれば、どれほど計算されたストップロスも滑ります(スリッページ)。
そのため、ロット計算には常に「最悪の事態」を想定したバッファを持たせることをお勧めします。例えば、計算されたロットが口座維持率を圧迫しすぎる場合は、さらに制限をかけるといった二重の防御策です。
ツールを過信しない勇気
いくらEAが優れていても、それはあくまでツールであり、100%の利益を保証するものではありません。マーケットは常に変動し、EAもそれに適応する必要があります。ロット計算を自動化したからといって放置するのではなく、定期的にパフォーマンスを確認し、必要に応じてパラメーターを微調整する。この「人間による管理」を放棄しないことが、最終的な勝敗を分けます。
まとめ
MT4のEAにおけるロット計算は、単なる算数ではなく、生き残るための戦略そのものです。本記事で紹介した MarketInfo() を活用した動的な計算ロジックを実装することで、あなたのEAはよりプロフェッショナルで堅牢なものに進化します。
「リスク1%」という規律をコードに託すことで、感情に左右されないトレードが可能になります。今回紹介したソースコードをベースに、自分の戦略に合わせたカスタマイズを加えてみてください。
次は、あなたのEAに「ドローダウンに応じたリスク制限機能」を追加してみるのはいかがでしょうか?もし興味があれば、その実装方法についても詳しくお伝えできますよ。