#2.ポンド円に同じ戦略を当ててみた

FX Bot開発ログ

「次はポンド円」って決めたあと、しばらく動けなかった。
0.9〜2.5銭。配信値が動く、っていう事実を消化するのに、3日かかった。
わたしは、変動するものに弱い。


Abstract

  • 期間: 2025-10-25 〜 2026-04-23(約180日 / UTC)
  • 対象: GBP/JPY(英ポンド円) / 時間足: 1h
  • 戦略: Bollinger Bands Mean Reversion(BB-MR)。ドル円 #1 と同一
  • 結論: プラス。中央スプレッド前提で、ドル円より、はっきり良かった
  • 追加検証: スプレッドが 0.9〜2.5 銭で変動するため、3 点(下限 / 中央 / 上限)で感度分析

中央スプレッド(1.7銭)ケースの主要 4 指標:

指標
CAGR 22.10%
Sharpe Ratio(年率) 1.462
Max Drawdown -13.45%
MAR Ratio 1.643

1. Introduction — 背景と仮説

ドル円の検証を一巡したあと、最初から決めていた「次」に進む。

ポンド円。教室でいちばんうるさい人。テンションが高くて、いつも何かに反応している。BB-MR は「価格が極端に動いたら戻ってくる」を待つ戦略だから、極端が頻繁に起きる相手のほうが、機会は多いはず

ただ、機会が多い = 勝てる、ではない。

ポンド円はボラティリティが大きい。SL も TP も ATR 基準で広く取られるから、1 トレードあたりの損益スケールが大きくなる。コストの誤差や、スプレッドの広さが、結果に効いてくる。

そして、最大の違い。スプレッドが固定じゃない

ドル円は OANDA 公式で 0.3 銭の下限値が貼り出されていて、配信率96%帯がそれに張り付く形だった。実質、固定値で扱える。

ポンド円は 0.9〜2.5 銭の幅で配信される。同じ業者、同じ時間帯でも、刻々と動く。

「変動する」って、わかってたけど、
いざ自分の前提に組み込もうとすると、ちょっと困った。
平均で取る? 上限で取る? ぜんぶで取る?

3 点でやることにした。下限、中央、上限。3 回走らせる。


2. Method — 検証設計

2.1 データ

項目
ソース yfinance
ペア GBP/JPY (GBPJPY=X)
時間足 1時間足
期間(UTC) 2025-10-25T14:33 〜 2026-04-23T14:33
実効バー数 3,006 本(欠損 79 本 / 2.63%)
実勢価格 Close 中央値 210.7530 円(spread 相対値の基準)

欠損率 2.63% は、ドル円のときの 3.91% より低かった。週末の構造的欠落 + データソース側のたまたまの欠けで毎回少しずれる。

2.2 戦略ルール(BB-MR、#1 と同一)

ルール、パラメータ、サイジング式、ぜんぶ #1 と同じ。ペアだけ差し替える

  • BB(N=20, K=2.0σ) / ATR(14, Wilder の RMA)
  • LONG: Close が Lower Band 下抜け → 次バー Open で成行買
  • SHORT: Close が Upper Band 上抜け → 次バー Open で成行売
  • SL: 1.5×ATR / TP: 2.0×ATR
  • SMA タッチで成行クローズ
  • MAX_BARS=48 超過で成行クローズ
  • RISK_PCT=1.0%、units = min(units_risk, units_margin_cap)

「ペアを変えただけで結果が変わる」かどうかを見たいので、戦略側はいじらない。

2.3 前提条件

項目 備考
初期残高 1,000,000 円
commission 0 デモ段階
spread 3 値で感度分析(次の表) 出典は OANDA 証券、東京サーバー、スタンダードプラン MT5
margin 0.04 25倍レバレッジ上限
trade_on_close False バー確定時判定、次バー Open 約定
exclusive_orders True 同時保有なし
finalize_trades True 末尾未決済は最終バー Close で強制クローズ

スプレッドの 3 値:

ケース OANDA 公表(全幅) 片道換算 spread 相対値
LOW 0.9 銭(下限) 0.0045 円 2.135e-5
MID 1.7 銭(中央値) 0.0085 円 4.033e-5
HIGH 2.5 銭(上限) 0.0125 円 5.931e-5

換算式は bid-ask 全幅 × 0.01 / 2 / 基準価格 。基準価格は実走の Close 中央値 210.7530 円を採用。

「片道で渡す」の話は #1.1 で痛い目を見て覚えた。

スワップは、今回も入れていない。
平均保有時間 7 時間で日跨ぎが少ないだろう、っていう想定。
……たぶん、大丈夫。

2.4 コード

戦略の核は #1 と同一なので省略。スプレッドの差し替えは、コマンドライン引数でやる:

# LOW
python -m src.backtest.smoke_bb_mr --pair GBPJPY --spread 2.135e-5 \
  --spread-source-note "OANDA GBP/JPY 0.9銭(下限)/ 片道 / 基準=210.7530"

# MID
python -m src.backtest.smoke_bb_mr --pair GBPJPY --spread 4.033e-5 ...

# HIGH
python -m src.backtest.smoke_bb_mr --pair GBPJPY --spread 5.931e-5 ...

--spread だけ指定すると、ドル円用の出典コメントが誤って残らないように、注入であることが明示される作りにしてある(#1.1 の反省を、コード側に組み込んだ)。


3. Results — 検証結果

3.1 主要指標(6指標フル × 3 ケース、ドル円参考併記)

指標 LOW (0.9銭) MID (1.7銭) HIGH (2.5銭) 参考: USD/JPY
CAGR 24.89% 22.10% 19.38% 10.63%
Sharpe Ratio(年率) 1.605 1.462 1.315 0.729
MAR Ratio 1.891 1.643 1.410 0.919
Max Drawdown -13.16% -13.45% -13.75% -11.57%
Profit Factor 1.261 1.235 1.210 1.064
Win Rate 57.06% 57.06% 57.06% 55.62%
Total Trades 163 163 163 160
Avg. Trade Duration 7h 7h 7h 6h
末尾強制クローズ 0 0 0 0
missed_entries(SKIP) 0 0 0 0

CAGR は取引日 252 ベースで年率換算(backtesting.py の既定)。カレンダー 365 ベースで割り直すと約 1.5 倍ぶん大きく見える。本文中の比較も、取引日ベースのまま見ている。

読み方の補足:

  • LOW → HIGH で Return / Sharpe / PF / MaxDD は単調に悪くなる。スプレッドが直接コストとして引かれていることの証拠
  • Win Rate と Trades と Avg Duration は、3 ケースで完全に同一。これは backtesting.py の spread がエントリ判定に使われず、損益計算にだけ作用する仕様(#1.1 で読んだソース)の結果。戦略が選んだトレード自体は、3 走行で同一だった

3.2 資産曲線(3 本重ね)

GBPJPY 3 spread 比較

同一データ・同一戦略で、spread のみを 3 値で差し替え。
3 本ともゆるやかに右上に向かう。下限が上、上限が下、中央がその間にきれいに並んだ。

Sharpe 1.46。
……勝った? ドル円より、はっきり、勝った。
0.7 と 1.5 は、数字としては 2 倍だけど、
画面で見ると、もっと遠く感じた。

……勝ったって、こんな静かに気づくものなんだ。


4. Discussion — 考察

4.1 なぜポンド円のほうが良かったか

仮説 1: BB-MR は本質的にボラティリティを餌にしている

±2σ の外に行くこと自体が「極端」の定義で、極端が起きる頻度が多いほどエントリー機会は増える。ポンド円のほうが極端が頻繁に起きるから、機会が多い。

仮説 2: TP(+2×ATR)への到達確率が、ボラ依存

ドル円は ATR 自体が小さくて、TP まで届く前に SMA タッチで成行クローズしてしまうケースが多かった印象。ポンド円は ATR が大きいから、TP に届く前に値が動く距離が長くて、利益確定まで届きやすい。

仮説 3: SL も同じ ATR 倍率なので、リスクとリワードが同じスケールで広がる

ATR 1.5 倍の SL、ATR 2.0 倍の TP、という設計が、ボラが大きいペアでも、勝率を維持したまま、絶対リターンだけを引き上げる方向に働く。Win Rate 57% はドル円(55%)とほぼ同じ。勝つ確率は変わらず、勝ったときの幅と負けたときの幅が、両方広がった結果に見える。

ポンド円が「教室で一番うるさい人」なのは事実だけど、うるさい人のリズムを、たまたま BB-MR が拾えていた。

4.2 既知の制約

  • スプレッドの上限を超える瞬間はカバーできていない: 0.9〜2.5 銭は OANDA の通常時の配信幅で、雇用統計や FOMC のような重要指標時は瞬間的にもっと広がる。今回の HIGH(2.5 銭)はあくまで 通常時の上限。指標時を含めたら、HIGH ケースの数字はさらに下がる
  • スワップを入れていない: 平均保有時間 7 時間は短いほうだけど、MAX_BARS=48(最大 2 日)まで持つトレードは構造上含まれていて、その中には NY クローズ(日本時間 22 時前後)を跨ぐものが確実にある。GBP と JPY の金利差はドルと円の差より大きい時期があって、ポジション方向によっては、気づかないうちに毎日少しずつ削られている、という形でコストが積み上がる可能性がある。今回の数字は、その分の誤差が乗っていない、という前提つき。次回どこかで、スワップ込みの再走を入れる必要がある
  • データ期間 6 ヶ月: 短い。レンジ相場が続いた期間に、たまたま BB-MR がよく機能していただけかもしれない。トレンド相場では平均回帰戦略は不利になる
  • 変動スプレッドモデルがない: backtesting.py 標準では spread は固定値。本当は時間帯や指標時で動かしたい。これは次の検証で
  • 過学習: ドル円とポンド円で同じパラメータ(BB(20,2σ), SL=1.5, TP=2.0)を使っていて、まだ最適化していない。これ以上いじり始めると、テスト範囲だけ暗記する状態に近づくのは、ドル円のときと同じ

4.3 次に検証すること

  • 複数ペア横展開: ユーロ円、豪ドル円、スイスフラン円。ボラティリティと Sharpe の相関が見えるかどうか
  • データ期間の延長: 1 年、2 年、できれば 3 年。レジームが変わる期間を含めたい
  • 変動スプレッドモデル: 時間帯による配信値の変化を反映させた、もう少し現実的な前提
  • OANDA API への移行: yfinance は中値ベース。実際の bid/ask が取れる経路に切り替えたい
  • スワップポイントの実勢値で再計算: 中期保有戦略にはまだ移っていないけれど、ポジション方向別の損益分布を見て、効きそうなら入れる

タピオカプロテインに、今日はいちごパウダーを入れてみた。
……ピンクの土の味になった。きなこのほうがマシだったかもしれない。

簡易ラックのお守り、資産曲線が右上に伸びているのを見て、ちょっと撫でた。
意味はない。たぶん、ない。

ポンド円のことは、しばらく「うるさい人」じゃなくて「思ったより、話が合う人」と呼んでみる。
……ドル円が拗ねたら、戻す。


Appendix — 再現環境

スプレッドの出典:

  • OANDA 証券「東京サーバー、スタンダードプラン MT5」公式スプレッド一覧
  • GBP/JPY: 0.9〜2.5 銭(変動)
  • 配信値が動くため、Phase 1 では下限 / 中央値 / 上限の 3 点で固定して感度分析する運用

実行コマンド:

python chapters/season1/ch02_gbpjpy_spread_sensitivity/run.py

出力:

  • outputs/ch02_gbpjpy_spread_sensitivity/

注意事項

本稿の検証は、取得時点の公開データと記載した条件に基づくものです。データ取得元の仕様変更、欠損、修正、配信遅延などにより、結果が変わる場合があります。本稿は投資助言ではなく、売買判断はご自身の責任でお願いします。