【実践ハウツー】OptiMax VPSで「完全」2年・約4億tickのFXデータ基盤を作り、64コアで戦略を総当たり最適化する

【実践ハウツー】OptiMax VPSで「完全」2年・約4億tickのFXデータ基盤を作り、64コアで戦略を総当たり最適化する

FX専用VPS / OptiMax 活用事例

バックテストの解像度は、データの解像度で決まります。日足・時間足では消えてしまう値動きの構造(スプレッド内の動き、約定の偏り、同時急変)は、tick(約定ごと)データにしか残りません。しかし tick は桁が違います。FX 6通貨ペア・2年分(完全)で4億レコード超。これを「漏れなく集め」「メモリに載せ」「総当たりで最適化する」には、ふつうの小型VPSでは力不足です。本記事では、当社のFX専用VPS OptiMax で、ゼロから完全な2年分tickデータ基盤を構築し、64コアで2,430通りの戦略パラメータを総当たり最適化するまでを、つまずきポイントごと実測値で解説します。

検証環境:OptiMax VPS(64 vCPU / 251GB RAM / Ubuntu 24.04)
計測期間:2023–2024(完全2年)/6通貨ペア。本記事の数値はすべて実測値です。
範囲:データ基盤構築・レート制限回避・並列最適化という汎用エンジニアリング手法のみで、当社の独自シグナル研究の内容は含みません。

OptiMax VPS の詳細・お申し込みはこちら

なぜ「tickデータ × ハイスペックVPS」なのか #

tick は「約定が起きるたび」の最小単位の記録です。スプレッドの内側で何が起きているか、急変時にどちらに約定が偏るか——こうしたマイクロ構造は、足を丸めた瞬間に消えます。だからこそ短期戦略の検証には tick が要る。ところが tick はデータ量が桁違いで、収集・保持・計算のすべてでマシンの地力が問われます。本記事は「取得したつもりで実は8割欠損していた」失敗とその修正まで、tickデータ収集で誰もが踏む落とし穴を正直に共有します。

何を作ったか(成果物) #

指標
期間 × 通貨ペア 完全2年(2023–2024) × 6ペア
総tick数 405,616,079(約4.06億)
被覆率 ≈100%(取引時間の取りこぼしゼロ。各ペア 15,048 時間中 data≈12,473+休場(404)≈2,574、未取得≤6)
1秒バー換算 1.41億本
最適化試行数 2,430通り(信号 × 保有時間 × 閾値 × ペア、各々ブートストラップCI付き)

全工程の所要時間(実測) #

工程 時間 備考
① 完全tick取得(2クリーンIP分割・ギャップ充填) 約3時間 取得役1台あたり3ペアで 10,856 秒、2台並走
② 計算機(OptiMax)への転送(約1GB) 51秒 約13.6 MB/s
③ 解析用フォーマット変換 116秒 npz → parquet
④ 64コアで2,430通り総当たり最適化 581秒 グリッド構築111s+スイープ470s、約60コア占有

ゼロから「分析可能な完全2年tick基盤+最適化結果」まで、実質3時間強です。

STEP 1:データ取得 ― 無料feedと「2つの落とし穴」 #

ヒストリカルtickは Dukascopy の無料データフィードから取得できます(.bi5 = LZMA圧縮 + 20バイト固定長レコード)。1時間=1ファイルで、純Pythonでデコードできます。

# .bi5(LZMA + 20B固定長: ms_offset, ask, bid, ask_vol, bid_vol)を時間単位で並列取得
import lzma, urllib.request, numpy as np, concurrent.futures as cf
REC = np.dtype([("t",">u4"),("ask",">u4"),("bid",">u4"),("av",">f4"),("bv",">f4")])
def fetch_hour(sym, y, m, d, h):
    url = f"https://datafeed.dukascopy.com/datafeed/{sym}/{y:04d}/{m-1:02d}/{d:02d}/{h:02d}h_ticks.bi5"
    raw = urllib.request.urlopen(url, timeout=30).read()
    return np.frombuffer(lzma.decompress(raw), dtype=REC)  # 価格 = points/(JPYは1000, それ以外100000)

落とし穴①:HTTP 503(レート制限)は「総量」ではなく「バースト」で出る #

高速化のため複数台に分散させ、停止→即再起動を何度も繰り返したところ、IPアドレスが Dukascopy 側から一時的に 503 → 応答なし でブロックされました。検証の結論:

  • 503の引き金は「リクエスト総量」ではなく「短時間の接続バースト」(=連続した停止・再起動、過剰な同時接続数)。
  • 一度ブロックされても、リクエストを完全に止めれば 5〜10分で自然回復
  • 鉄則は 「1回だけ・控えめな同時接続で・止めずに流し切る」。今回は 1ペア24スレッド × 2ペア並行(=48接続) が安定帯でした。

落とし穴②(最重要):「サイレント・ドロップ」― 取得したつもりで8割欠損 #

最初の取得は一見「完走」しましたが、後で被覆率を測ると約22%しかありませんでした。原因は、ダウンローダが HTTP 503 を「データ無し(404)」と同じ扱いで黙って捨てていたこと。ブロックされていなくても、混雑時のソフトな503が散発し、その時間足が静かに欠落していたのです。「データが流れている=完全」ではありません。

🛠 どう捕まえ、どう直したか(再現可能なチェックリスト)

  1. 完全性は『流れているか』でなく『被覆率/欠損率』で検証する。 「nonempty 率」が取引時間の想定(≈80%)を大きく下回ったら欠損を疑う。今回は下流の解析でアラインメントが極端に痩せたこと(5分足パネルが本来15万本のところ200本台)で露呈しました。
  2. 404 と 503 を区別する。 404=正当な休場(再取得しない)、503/タイムアウト=要再取得。両者を同一視した瞬間に欠損は不可視化します。
  3. 多パス・ギャップ充填。 各 (日,時) の取得結果を記録し、失敗した時間だけを指数バックオフで再取得 → 失敗0まで反復。
  4. 被覆レポートで締める。 「total / data / 休場(404) / 未取得」を必ず出力し、未取得≈0 と ticks/年 が想定どおりかを確認してから信頼する。

結果、被覆率は 22% → ≈100%(各ペア未取得 ≤6 時間/15,048)に。完全2年で 4.06億tick を確実に取得できました。

STEP 2:落とし穴③メモリ ― tick処理は「RAMバウンド」 #

tickのデコードは、対象範囲のレコードを一度メモリに展開してから書き出します。つまり必要RAMは期間×ペア数に比例します。

検証では、RAM 1.9GB の小型VPSを補助に使うと、多年×複数ペアで即OOM(メモリ不足で強制終了)。一方 OptiMax(251GB RAM)は完全2年×6ペアを丸ごとメモリに載せても余裕(解析時ピークでも空き多数)。

tickデータ処理は、CPUより先にRAMが壁になります。OptiMaxの大容量メモリは、まさにこの用途のためにあります。

STEP 3:設計の勘所 ―「ダウンロード機」と「計算機」を分ける #

  • ダウンロードは回線品質(Dukascopyへの経路)が支配的。
  • 解析・最適化はRAMとコア数が支配的。

別の機械の得意分野なので、役割を分けます。今回は クリーンIPの取得役2台でデータを集め(IPあたりのレート制限を2倍に回避=分割の本当の効能)、OptiMax を「計算の母艦」として転送・集約・最適化に専念させました。約1GBの転送はわずか 51秒。どちらのボトルネックにも引きずられません。

STEP 4:64コアで「戦略を総当たり最適化」する #

ここが OptiMax の本領です。MT5のストラテジーテスター最適化と同じ発想で、1試行=1コアに割り当て、全コアを使い切ります。

ポイントは並列の単位。「通貨ペア」だけで並列にすると6コアしか回りません。(ペア × 信号 × 保有時間 × エントリー閾値) の全組み合わせを1試行にすると試行数が一気に増え、64コアを張り切れます。重い前処理(1秒グリッド)は一度だけ作って共有します。

# 重い前処理(1秒グリッド)は1回だけ → fork pool で共有(copy-on-write) → 全組み合わせを総当たり
import multiprocessing as mp
GRIDS = {p: build_grid(p) for p in PAIRS}            # 親プロセスで一度だけ構築(COWで子に共有)
tasks = [(p,sig,H,thr) for p in PAIRS for sig in SIGNALS for H in HORIZONS for thr in THRESHOLDS]
with mp.Pool(64) as pool:
    results = pool.map(eval_combo, tasks)            # 各combo = walk-forward + コスト考慮 + ブートストラップCI

実測:1.41億本の1秒バー上で 2,430通り約60コア占有・581秒(グリッド構築111s+スイープ470s)で完走。各試行は walk-forward(時系列の学習→検証分割)+往復スプレッドを引いたコスト考慮PnL+ブロック・ブートストラップ信頼区間まで含む本格検証です。

「バックテストだから全コアを使えない」は誤解です。並列の単位を「パラメータの組み合わせ」に取れば、最適化はコア数ぶん素直に速くなります。OptiMaxの64コアはここで文字どおりフル稼働します。

結果(汎用的な学び) #

完全2年・4.06億tick・2,430最適化試行での定量結果:

  • シグナル自体は「存在」する:コスト無視(GROSS)のシャープレシオは最大 +429。短期の値動きには確かに構造があります。
  • しかしテイカー(成行)では取れない:往復スプレッドを引くと、2,430通りのどれ一つプラスにならない(NET>0 が 0/2,430)。さらに各試行の 95%信頼区間の上限すら 0/2,430 がプラス=統計的にも「プラスになり得る」組み合わせがゼロ(データを完全化したことでノイズ由来の“まぐれ陽性”も消滅しました)。
  • これは市場マイクロ構造の教科書的結果(短期エッジは bid-ask スプレッドの内側に収まり、スプレッドを払う側=テイカーには回収できない)を、大規模・完全データで厳密に再確認したものです。

実務的含意:短期エッジの研究は「コストを引いた後」でしか意味を持たない。そしてその大規模検証を現実的な時間で回すには、完全なデータ・RAM・コア数が要る、ということです。

まとめ #

やったこと 効いた要素
完全2年・4.06億tickの取得 控えめ並列+404/503区別+多パス・ギャップ充填で被覆22%→100%
4億tickをメモリに展開・処理 251GB RAM(小型VPSはOOM)
2,430通りの総当たり最適化 64コア+「組み合わせ単位の並列化」
全工程 実質3時間強

tickレベルの大規模バックテスト・最適化は、もはや特別な計算機の専有を必要としません。OptiMax VPS なら、必要なときに必要なだけのRAMとコアを確保して、この規模の検証を現実的な時間で回せます。データ収集の落とし穴(503バースト・サイレントドロップ・RAM上限)も、本記事のチェックリストで回避できます。

この検証はすべて OptiMax VPS(64 vCPU / 251GB RAM)で実施しました。
大容量メモリ・多コア・低遅延を、必要なときに必要なだけ。FX自動売買からクオンツ研究まで。

OptiMax VPS の詳細・お申し込みはこちら

What are your feelings
Updated on 2026年6月19日

アフィリエイターになって頂けませんか?

弊社のアフィリエイトは簡単に始める事が可能です