目次
2026 年 3 月、FX 開発歴 10 年のフォレックスドッグ氏が X で**「凄い論文を見つけた」**と報告した。
【驚愕】凄い論文見つけた😳 と言うのも、今運用してるドル円 EA のチューニングだけど 実はこの論文とほぼ同じことを「手動」でやってた…
具体的には、 時間帯ごと、売り買いごとにバックテストで最適化してた。 だから1つの通貨ペアを最適化するのに1ヶ月掛かってた
でも、これを人力じゃなく、 論文にある GA(遺伝的アルゴリズム)で自動化すれば、 開発スピードも適応力も次元が変わる可能性が高まる
遺伝的アルゴリズム(GA)を用いて、EA(Expert Advisor)のパラメータ最適化を自動化する。
本稿はこのアプローチの概要、fit3 評価軸、そして実装方法を解説する。
手動最適化の課題
フォレックスドッグ氏が報告する手動最適化の方法は以下の通りだ。
手動最適化のプロセス
- 時間帯ごとに分割 - 東京、ロンドン、ニューヨークなど
- 売り買いごとに分割 - ロング用、ショート用
- バックテストで最適化 - 各セグメントでパラメータを調整
- 1 ヶ月/通貨ペア - 1 つの通貨ペアを最適化するのに 1 ヶ月
手動最適化の問題点
| 問題 | 説明 | 影響 |
|---|---|---|
| 時間コスト | 1 通貨ペアに 1 ヶ月 | 複数通貨への展開が遅い |
| 過剰適合 | 直近データに最適化 | 市場変化で性能劣化 |
| 主观性 | 開発者の判断に依存 | 再現性が低い |
| 静的パラメータ | 最適化後は固定 | 市場変化に適応できない |
これらの課題は、遺伝的アルゴリズムによる自動化で解決できる可能性がある。
遺伝的アルゴリズム(GA)とは
遺伝的アルゴリズムは、生物の進化(自然選択・交叉・突然変異)を模倣した最適化手法だ。
GA の基本プロセス
1. 初期集団の生成
↓
2. 適応度評価(fitness)
↓
3. 選択(selection)
↓
4. 交叉(crossover)
↓
5. 突然変異(mutation)
↓
6. 新規集団の生成
↓
(2-6 を繰り返し)
EA 最適化への適用
| GA 要素 | EA 最適化での意味 |
|---|---|
| 個体 | 1 つのパラメータセット |
| 遺伝子 | 各パラメータ(例:移動平均期間、ストップロス) |
| 適応度 | バックテスト結果(利益率、シャープレシオなど) |
| 選択 | 成績の良い個体を次世代に残す |
| 交叉 | 2 つの個体のパラメータを組み合わせる |
| 突然変異 | ランダムにパラメータを変更 |
fit3 評価軸:堅牢性の定量化
論文の核心は**「fit3」**という評価軸だ。
従来の評価軸の問題
従来の EA 最適化では、以下の指標が一般的だ。
- 総利益 - 単純な利益の合計
- 勝率 - 勝ちトレードの割合
- プロフィットファクター - 総利益÷総損失
しかし、これらは**「直近データへの過剰適合」**のリスクがある。
fit3 の特徴
fit3 は以下の 2 つを評価する。
- 単なる利益追求ではない
- トレンドの変化に耐える「堅牢性」を自動計算
fit3 の計算方法(疑似コード)
def calculate_fit3(equity_curve):
# 1. 複数の期間でバックテスト
periods = split_into_periods(equity_curve, n=5)
# 2. 各期間の性能を評価
scores = []
for period in periods:
# シャープレシオ、ドローダウン、利益率を組み合わせ
score = calculate_robustness_score(period)
scores.append(score)
# 3. 期間間の分散を計算(堅牢性の指標)
variance = np.var(scores)
# 4. 平均性能÷分散(分散が小さいほど高評価)
fit3 = np.mean(scores) / (variance + 1e-6)
return fit3
fit3 のメリット
| メリット | 説明 |
|---|---|
| 過剰適合防止 | 複数の期間で評価するため、特定の期間に最適化されない |
| 堅牢性の定量化 | 期間間の分散で堅牢性を数値化 |
| 客観的評価 | 開発者の主観を排除 |
実装アプローチ
ステップ 1: パラメータの定義
# EA の最適化パラメータ
params = {
'ma_period': {'min': 10, 'max': 100, 'step': 5},
'stop_loss': {'min': 10, 'max': 100, 'step': 5},
'take_profit': {'min': 20, 'max': 200, 'step': 10},
'trailing_stop': {'min': 0, 'max': 50, 'step': 5},
}
ステップ 2: 初期集団の生成
import random
def generate_population(size=100):
population = []
for _ in range(size):
individual = {
key: random.randint(val['min'], val['max'])
for key, val in params.items()
}
population.append(individual)
return population
ステップ 3: 適応度評価(fit3)
def evaluate_fitness(individual, historical_data):
# 1. 複数の期間に分割
periods = split_data(historical_data, n_periods=5)
# 2. 各期間でバックテスト
scores = []
for period in periods:
result = backtest(individual, period)
# シャープレシオ、ドローダウン、利益率を組み合わせ
score = calculate_robustness_score(result)
scores.append(score)
# 3. fit3 を計算
variance = np.var(scores)
fit3 = np.mean(scores) / (variance + 1e-6)
return fit3
ステップ 4: 選択・交叉・突然変異
def select(population, fitness_scores, n_parents=50):
# トーナメント選択
parents = []
for _ in range(n_parents):
idx1, idx2 = random.sample(range(len(population)), 2)
if fitness_scores[idx1] > fitness_scores[idx2]:
parents.append(population[idx1])
else:
parents.append(population[idx2])
return parents
def crossover(parent1, parent2):
# 一点交叉
crossover_point = random.randint(1, len(parent1) - 1)
child = {**parent1}
for key in list(parent2.keys())[crossover_point:]:
child[key] = parent2[key]
return child
def mutate(individual, mutation_rate=0.1):
# 突然変異
for key in individual:
if random.random() < mutation_rate:
individual[key] += random.randint(-5, 5)
return individual
ステップ 5: 進化ループ
def optimize_ea(historical_data, generations=100):
# 1. 初期集団
population = generate_population(size=100)
for generation in range(generations):
# 2. 適応度評価
fitness_scores = [
evaluate_fitness(ind, historical_data)
for ind in population
]
# 3. 選択
parents = select(population, fitness_scores, n_parents=50)
# 4. 交叉・突然変異
children = []
while len(children) < 50:
parent1, parent2 = random.sample(parents, 2)
child = crossover(parent1, parent2)
child = mutate(child)
children.append(child)
# 5. 新規集団
population = parents + children
# 6. 経過報告
best_fitness = max(fitness_scores)
print(f"Generation {generation}: Best fit3 = {best_fitness:.4f}")
# 7. 最適個体を返す
best_idx = np.argmax(fitness_scores)
return population[best_idx], fitness_scores[best_idx]
期待される効果
1. 開発スピードの向上
- 従来: 1 通貨ペアに 1 ヶ月
- GA: 数時間〜数日
2. 過剰適合の防止
- 従来: 直近データに最適化
- GA: fit3 で複数期間を評価
3. 自律進化の実現
- 従来: 最適化後は固定
- GA: 運用中に再最適化可能
4. 他通貨への展開
- 従来: 1 通貨ごとに 1 ヶ月
- GA: 最適化パイプラインを再利用
課題と注意点
1. 計算コスト
GA は多数のバックテストを必要とする。
対策:
- 並列処理(マルチコア、クラウド)
- 軽量バックテストエンジンの使用
2. 過剰適合のリスク
fit3 を使っても、過剰適合のリスクは残る。
対策:
- out-of-sample テスト
- 前方分析(forward testing)
3. 市場環境の変化
GA で最適化したパラメータも、市場環境が変化すれば性能が劣化する。
対策:
- 定期的な再最適化
- パラメータの適応的調整
結論:「手動のチューニング」から「自律進化する EA」へ
フォレックスドッグ氏の報告は、EA 開発の新時代を告げるものだ。
- 遺伝的アルゴリズムで自動最適化
- fit3 評価軸で堅牢性を定量化
- 自律進化で市場変化に適応
「手動のチューニング」から「自律進化する EA」へ。
めっちゃ可能性感じる。
参考:
引用元・参考リンク
免責事項 — 当記事は情報提供を目的としており、特定の金融商品の売買を推奨するものではありません。投資判断はご自身の責任で行ってください。