こんにちは、潤奈です!
通貨の強い・弱いを使って売買する「通貨強弱EA」の開発を進めています。前回は、値動きに応じた決済幅の調整と、通貨ペアごとの設定の見直しに取り組みました。
今回は、その続きとなる2026年10月10日のGBPJPY(ポンド円)の検証です。合計利益だけを見ると見落としてしまう、期間ごとの成績の違いを確認しました。
設定を変えても、狙いどおりに良くなるとは限りません。最後に試したADXフィルターも、下落幅が小さくなった一方で、利益は少し減りました。その結果をどう読むか、実装の一部と合わせてまとめます。
合計がプラスでも、長く増えない期間がある
GBPJPYでは、建値移動やトレイリングストップ、上位足の条件などを段階的に調整していました。建値移動は損切り位置をエントリー価格付近へ動かす処理、トレイリングストップは利益方向の値動きに合わせて損切り位置を追従させる処理です。
ところが、長い期間でバックテストすると、途中から損益の伸びが鈍く見える部分がありました。そこで2010〜2019年の結果を、2010〜2014年と2015〜2019年に分けて確認しました。
知りたいのは「最後にいくら残ったか」だけではありません。どの時期に利益を積み上げ、どの時期に失っているのか。買いと売り、エントリー時の条件に偏りがないか。そこまで分けて、調整の候補を探しました。
利益を早く守る調整でも、結果は悪化した
検証の途中では、建値移動やトレイリングの開始を早め、エントリー条件も絞る案を試しました。しかし、テスト後には「思ったような改善ではなく、むしろ悪くなった」という確認になりました。
利益を早めに守ろうとすると、途中の戻りで決済され、その後の伸びを取れなくなる可能性があります。一方、条件を絞れば、負けだけでなく勝っていた取引も対象から外れます。
ただし、このときは複数の設定を変更しています。「建値移動を早めたことだけが原因」とは断定できません。過去の取引の最大含み益を見ても、決済方法を変えた後の損益がそのまま分かるわけではありません。
ログ分析で仮説を立てたら、EAを実際に動かして確かめる。この往復が必要でした。
ADX=20では、何が変わったのか
その後、設定を見直して再テストし、さらに既存のADXフィルターを有効にして比較しました。ADXはトレンドの強さを見る指標で、値そのものが買い・売りの方向を示すものではありません。今回は「ADXが20未満なら新規エントリーを見送る」という使い方です。
以下は、10月10日のバックテスト後に保存されたCSV集計出力の比較です。対象期間は2010〜2019年です。
| 項目 | ADXフィルターなし | ADXの下限20 |
|---|---|---|
| 取引数 | 392回 | 352回 |
| 合計損益 | +1,313.0 pips | +1,291.3 pips |
| 累積確定pipsの最大下落幅 | 875.7 pips | 785.8 pips |
| 2010〜2014年の合計 | +1,469.4 pips | +1,395.8 pips |
| 2015〜2019年の合計 | −156.4 pips | −104.5 pips |
| 2017〜2018年の合計 | −743.9 pips | −643.9 pips |
年別の区分はエントリー年です。最大下落幅は、当時のスクリプトがCSVの行順で確定pipsを積み上げ、過去の最高値からの下落を計算したものです。含み損を含む口座資産の最大ドローダウンとは異なります。
比較当時のCSVは上書きされているため、今回は保存された集計出力を掲載しています。現在のCSVから同じ取引集合を再集計した結果ではありません。また、両テストの全設定・テスターモデルの一致までは再確認できていません。
この記録で見ると、最大下落幅は89.9 pips小さくなり、合計利益は21.7 pips減りました。2017〜2018年の損失は100.0 pips減っていますが、2015〜2019年全体ではまだ赤字です。
「損失が減ったから成功」と決めるには早い結果です。何を改善したくて、どの利益を手放したのかをセットで見る必要があります。
コードでは、確定した足のADXを確認する
ここからは、ハイブリッド通貨強弱EA v4にある処理の抜粋です。今回ADX機能を新しく作ったのではなく、既存のフィルターを有効にして試しています。初期化部分と判定部分を分けて掲載し、売買処理などは省略しています。
まず、初期化時にADXの計算結果を取得するためのハンドルを作ります。
g_adx_handle = iADX(g_trade_symbol, PERIOD_CURRENT, 14);
iADXはMQL5の標準関数です。戻り値はADXの数値ではなく、指標にアクセスするためのハンドルです。14は計算期間、PERIOD_CURRENTはEAを動かすチャートの時間足を指定します。iADXの公式リファレンス
新規エントリーの前では、次の処理を通ります。読みやすさのために字下げを整えていますが、条件式は保存ソースと同じです。
if(InpUseAdxFilter && InpMinAdx > 0.0)
{
if(g_adx_handle != INVALID_HANDLE)
{
double adx_buf[1];
if(CopyBuffer(g_adx_handle, 0, 1, 1, adx_buf) > 0)
{
if(adx_buf[0] < InpMinAdx) return;
}
}
}
抜粋に登場する独自の名前は、次の用途で使っています。
| 名前 | 種類と用途 |
|---|---|
| InpUseAdxFilter | 真偽値の入力設定。trueでADX判定を使います。保存ソースの初期値はfalseで、今回のテストでは有効にしています。 |
| InpMinAdx | 数値の入力設定。エントリーを許可するADXの下限です。今回試した値は20。価格やpipsではなく、ADXの指標値です。 |
| g_trade_symbol | 取引対象の銘柄名を持つ独自変数。今回の対象はGBPJPYです。 |
| g_adx_handle | iADXで作成した指標ハンドルを保持する整数の独自変数。ADX値そのものではありません。 |
| adx_buf | CopyBufferで取得したADX値を一つ入れる、局所的な配列です。adx_buf[0]が取得値になります。 |
CopyBufferもMQL5の標準関数です。引数の「0, 1, 1」は、順に「ADX本線のバッファ番号0」「現在の足から1本前」「取得する値は1個」を意味します。つまり、形成中の足ではなく、直前の確定足を参照しています。CopyBufferの公式リファレンス
INVALID_HANDLEは無効なハンドルを表す標準定数です。取得できたADXが下限未満ならreturnでその回の処理を抜け、新規エントリーへ進みません。20ちょうどなら、この比較では止まりません。ただし、他の売買条件も満たす必要があります。
なお、保存ソースではハンドルが無効な場合や値の取得に失敗した場合、このADX判定では処理を止めずに先へ進みます。「ADXを取得できなければ必ず取引を見送る」実装ではない点も、抜粋を読む際の確認ポイントです。
ログから取引を除くだけでは、再テストの代わりにならない
ADXの下限を22や24に上げた場合についても、既存ログから条件に合う取引を選び直す分析がありました。ただし、それは閾値を変更してEAを動かし直したバックテストとは別です。
取引を見送ると、その後のポジション保有状態や損切り後の待機時間が変わり、次に入れる取引も変わる可能性があります。残った取引だけの合計を、そのまま変更後の成績とは扱えません。
また、今回見ている2010〜2019年は調整に使った期間です。
今回の学びは、改善を一つの数字で決めないこと
今回のADX比較では、下落幅と一部期間の損失が小さくなった一方、合計利益は少し減り、苦手な期間の赤字も残りました。
合計利益、途中の下落、期間ごとの偏り。この三つを並べると、設定変更で得たものと残った課題が見えてきます。
条件を追加する前に「何を良くしたいのか」を決め、変更後には良くなった点と悪くなった点の両方を確認する。GBPJPYの検証で持ち帰りたいのは、この考え方です。


コメント