Plato Analizi: Sağlam Bir Optimumu Aşırı Uyumdan Nasıl Ayırt Edilir
"Yanılsamasız Backtestler" serisinin 6. makalesi
study.optimize() çalıştırdınız, Optuna +%87 PnL ile bir parametre seti buldu. Heyecanlandınız ve stratejiyi üretime hazırlıyorsunuz. İki hafta canlı işlem sonrasında PnL sıfır civarında. Ne oldu?
Optimizer, parametre uzayında bir iğnenin ucunu buldu. Parametreler geçmiş işlem dizisine mükemmel biçimde uydurulmuştur; ancak piyasa koşullarındaki en ufak sapma tüm yapıyı çökertiyor. Bu klasik aşırı uyumdur ve başlatmadan önce tespit edilebilirdi.
Önceki makalede koordinat inişini Bayes optimizasyonuyla karşılaştırdık ve Optuna'nın optimumu neden daha verimli bulduğunu gösterdik. Bugün — sonraki adım: bulunan optimumun gürültüye uyum sonucu değil, gerçekten sağlam olduğundan nasıl emin olunur.
"En İyi" Parametreleri Bulmak Neden Sadece İşin Yarısıdır
Gerçek optimumu aramak için geniş çok boyutlu parametre manzarasında gezinen bir optimizer
Strateji parametre optimizasyonu, çok boyutlu bir uzayda maksimum arayışıdır. Sorun şu ki maksimumlar iki türe ayrılır:
-
Plato — parametre değişimlerinde PnL'nin sürekli yüksek kaldığı geniş, düz bir bölge. Piyasa koşulları etkin parametreleri %10-20 kaydırsa bile strateji kâr etmeye devam eder.
-
Keskin zirve — PnL'nin yalnızca tam parametre değerinde yüksek olduğu dar bir tepe. Bir adım kayma kârlılığı çöküyor. Bu neredeyse kesinlikle aşırı uyumdur: optimizer, kararlı bir örüntü değil, tarihsel verinin bir artefaktını bulmuştur.
Dağcılık metaforu: plato, güvenle yürünebilen dağ tablası. Keskin zirve ise ancak dengelenebileceğiniz bir iğne ucu.
Keskin Zirve ile Düz Plato — Görsel Sezgi
Sol: sağlam bir plato (geniş, yavaş eğimli masa dağı). Sağ: kırılgan bir keskin zirve (derin vadilerle çevrili iğne ucu)
Eksenlerinin iki strateji parametresi, rengin ise PnL'yi temsil ettiği bir kontur haritası hayal edin. İki örüntü görsel olarak kolayca ayırt edilir:
Plato (sağlam optimum):
- Aynı rengin geniş alanları
- PnL seviyeleri arasında yumuşak geçişler
- Birbirinden uzak izoyigitler
- Optimumdan +/-%20 kayma PnL'yi en fazla %10 değiştiriyor
Bir ısı haritası hayal edin: ortada — haritanın yaklaşık üçte biri kadar parlak sarı bir dikdörtgen. Renk kenarlara doğru yavaşça turuncuya, ardından kırmızıya geçiyor. Optimum bir nokta değil, bir bölge.
Keskin zirve (aşırı uyum):
- Soğuk renklerle çevrili dar parlak bir nokta
- Ani geçişler: optimumun hemen yanında çöküş
- Tek bir noktanın etrafında sıkışık izoyigitler
- +/-%5 kayma PnL'yi %50 veya daha fazla düşürüyor
Aynı ısı haritasını, ancak ortada hemen mavi ve morla çevrili küçük sarı bir nokta olduğunu hayal edin. Tek bir "doğru" parametre kombinasyonu.
Parametre Duyarlılığı Analizi
PnL'nin bireysel parametre değerlerine nasıl bağlı olduğunu gösteren dilim grafikleri — geniş bantlar sağlamlığı, dar kümeler kırılganlığı gösterir
Tek Boyutlu Analiz: PnL ile Tek Parametre
En basit yaklaşım — biri hariç tüm parametreleri sabit tutmak ve PnL'nin değerine nasıl bağlı olduğunu görmek. Optuna bunun için plot_slice sağlar:
import optuna
from optuna.visualization import plot_slice
study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=500)
fig = plot_slice(study, params=["htf_entry_sell", "ltf_momentum", "stop_loss_pct"])
fig.show()
Dilim grafiğinde nelere bakılır:
- Sağlam parametre: nokta bulutu, optimum yakınında geniş yatay bir bant oluşturur. En iyi denemeler, parametre değerlerinin geniş bir aralığına yayılmıştır.
- Kırılgan parametre: en iyi denemeler dar bir aralıkta yoğunlaşmıştır. Parametreyi bir veya iki adım kaydırın — kârlılık çöker.
İki Boyutlu Analiz: Kontur Grafikleri (Isı Haritaları)
Kontur grafiği, iki parametrenin etkileşimini aynı anda gösterir. Bu, plato analizi için temel araçtır; çünkü parametreler nadiren bağımsız hareket eder — giriş ve çıkış eşikleri, zaman dilimleri ve pozisyon boyutları birbirine bağlıdır.
from optuna.visualization import plot_contour
fig = plot_contour(study, params=["htf_entry_sell", "htf_exit_buy"])
fig.show()
Sağlam bir parametre çifti için kontur grafiği, engebeli bir oyanın topografik haritasına benzer: yumuşak geniş izoyigitler, aynı rengin büyük alanları. Kırılgan bir çift için kontur grafiği — yanardağ konisinin haritası gibi: tek bir noktanın etrafında sıkışık eş merkezli halkalar.
12 ayrıştırma parametreli bir strateji için bu, ikili kontur grafiği verir. Hepsini incelemenize gerek yok — Optuna'nın en önemli olarak değerlendirdiği parametrelerle başlayın.
Çok Boyutlu Analiz: Parametre Önem Sıralaması
Optuna, her parametrenin hedef fonksiyona katkısını tahmin edebilir:
from optuna.visualization import plot_param_importances
fig = plot_param_importances(study)
fig.show()
Parametre önem grafiği yatay bir histogramdır. Parametreler, PnL varyansına katkılarına göre azalan sırayla sıralanır. İlk 3-4 parametre genellikle varyansın %70-80'ini açıklar.
Kural: bir parametre PnL varyansının %2'sinden azını açıklıyorsa, değeri pratikte sonuç için önemsizdir — tanım gereği sağlamdır. Plato analizini en önemli 5 parametreye odaklayın.
Optuna Görselleştirme Araçları
Önem sıralamasının yanında parametre etkileşim manzarasını gösteren kontur ısı haritaları
plot_slice — Tek Boyutlu Dilimler
import optuna
from optuna.visualization import plot_slice
fig = plot_slice(study, params=[
"htf_entry_sell", "htf_entry_buy",
"ltf_momentum_threshold", "stop_loss_pct",
"take_profit_pct", "trailing_stop_pct"
])
fig.update_layout(height=800, title="Parameter Slice Plots")
fig.show()
Sonuç — bir dağılım grafiği ızgarası. Her alt grafik, hedef fonksiyon değerini (PnL, Y ekseni) tek bir parametre değerine (X ekseni) karşı gösterir. Noktalar bireysel denemelerdir. Sağlam bir parametre için en iyi noktalar (en yüksek PnL), X'in geniş bir aralığına dağılmıştır. Kırılgan biri için — dar bir sütunda gruplandırılmıştır.
plot_contour — İki Boyutlu Konturlar
from optuna.visualization import plot_contour
important_pairs = [
["htf_entry_sell", "htf_entry_buy"],
["htf_entry_sell", "stop_loss_pct"],
["ltf_momentum_threshold", "take_profit_pct"],
]
for params in important_pairs:
fig = plot_contour(study, params=params)
fig.update_layout(title=f"Contour: {params[0]} vs {params[1]}")
fig.show()
Her kontur grafiği, eksenlerde iki parametre bulunan bir ısı haritasıdır. Renk, parametre uzayının belirli bir bölgesindeki ortalama PnL'yi kodlar. Sarı/yeşil — yüksek PnL, mavi/mor — düşük. İzoyigitler aynı PnL'ye sahip noktaları bağlar.
plot_param_importances — Parametre Katkıları
from optuna.visualization import plot_param_importances
fig = plot_param_importances(
study,
evaluator=optuna.importance.FanovaImportanceEvaluator()
)
fig.show()
fANOVA (fonksiyonel ANOVA), hedef fonksiyonun varyansını parametreler ve etkileşimleri genelinde ayrıştırır. Bu, doğrusal olmayan etkileri hesaba kattığı için basit korelasyondan daha güçlüdür.
Plato İçin Sayısal Metrikler
Duyarlılık oranı, plato genişliği ve sağlamlık skoru — plato kalitesini resmileştiren üç metrik
Görsel değerlendirme özneldir. Sayılara ihtiyacımız var. İşte "plato" kavramını resmileştiren üç metrik.
Duyarlılık Oranı
PnL değişiminin parametre değişimine oranı:
burada , parametresi optimumdan kadar saptığında meydana gelen PnL düşüşüdür.
Yorum:
- — parametre sağlamdır: %10'luk kayma %5'ten az PnL düşüşüne neden olur
- — orta düzey duyarlılık
- — parametre kırılgandır: %10'luk kayma PnL'yi %20+ çöküyor
Plato Genişliği
PnL'nin optimumun dahilinde kaldığı parametre bölgesinin genişliği:
Göreli plato genişliği:
burada payda, parametrenin tam arama aralığıdır.
Yorum:
- — plato, %10 eşiğinde aralığın %30'undan fazlasını kapsıyor. Sağlam parametre.
- — plato, aralığın %5'inden dardır. Kırmızı bayrak.
Sağlamlık Skoru
Tüm parametreler genelinde birleşik bir metrik:
burada , fANOVA'dan elde edilen parametresinin normalleştirilmiş önemidir ().
Ağırlıklı genişliklerin çarpımı katı bir metriktir: önemli bir parametre bile dar bir platoya sahipse, düşük olacaktır. Önemsiz parametrelerin (küçük ile) neredeyse hiç etkisi yoktur.
Yorum:
- — strateji sağlamdır
- — ek doğrulama gerekli (walk-forward)
- — aşırı uyum çok olası
Otomatik Plato Tespiti İçin Python Kodu
Sağlam platoları ve kırılgan zirveleri belirlemek için parametre manzarasını tarayan otomatik sistem
import numpy as np
import optuna
from optuna.importance import FanovaImportanceEvaluator
from typing import Dict, List, Tuple
def compute_sensitivity_ratio(
study: optuna.Study,
param_name: str,
n_steps: int = 20,
) -> float:
"""
Tek bir parametre için duyarlılık oranını hesaplar.
Diğer tüm parametreleri en iyi değerlerinde sabitler, param_name'i değiştirir,
deneme enterpolasyonu aracılığıyla PnL düşüşünü tahmin eder.
"""
best_trial = study.best_trial
best_value = best_trial.values[0]
best_param = best_trial.params[param_name]
all_trials = [t for t in study.trials if t.state == optuna.trial.TrialState.COMPLETE]
all_trials.sort(key=lambda t: t.values[0], reverse=True)
top_trials = all_trials[:max(10, len(all_trials) // 5)]
param_values = np.array([t.params[param_name] for t in top_trials])
pnl_values = np.array([t.values[0] for t in top_trials])
if best_param == 0 or best_value == 0:
return float('inf')
from numpy.polynomial import polynomial as P
coeffs = np.polyfit(param_values, pnl_values, deg=2)
dpnl_dparam = 2 * coeffs[0] * best_param + coeffs[1]
sensitivity = abs(dpnl_dparam * best_param / best_value)
return sensitivity
def compute_plateau_width(
study: optuna.Study,
param_name: str,
threshold_pct: float = 10.0,
) -> Tuple[float, float]:
"""
Mutlak ve göreli plato genişliğini hesaplar.
Döndürür:
(absolute_width, relative_width)
"""
best_value = study.best_value
threshold = best_value * (1 - threshold_pct / 100)
trials = [t for t in study.trials if t.state == optuna.trial.TrialState.COMPLETE]
good_trials = [t for t in trials if t.values[0] >= threshold]
if not good_trials:
return 0.0, 0.0
good_params = [t.params[param_name] for t in good_trials]
all_params = [t.params[param_name] for t in trials]
plateau_min = min(good_params)
plateau_max = max(good_params)
absolute_width = plateau_max - plateau_min
search_range = max(all_params) - min(all_params)
relative_width = absolute_width / search_range if search_range > 0 else 0
return absolute_width, relative_width
def compute_robustness_score(
study: optuna.Study,
threshold_pct: float = 10.0,
) -> Dict:
"""
Birleşik sağlamlık skorunu hesaplar.
Döndürür:
parametre başına metrikler ve nihai skoru içeren dict
"""
evaluator = FanovaImportanceEvaluator()
importances = optuna.importance.get_param_importances(
study, evaluator=evaluator
)
results = {}
total_importance = sum(importances.values())
for param_name, importance in importances.items():
sensitivity = compute_sensitivity_ratio(study, param_name)
abs_width, rel_width = compute_plateau_width(
study, param_name, threshold_pct
)
weight = importance / total_importance
results[param_name] = {
"importance": importance,
"weight": weight,
"sensitivity_ratio": sensitivity,
"plateau_width_abs": abs_width,
"plateau_width_rel": rel_width,
}
log_score = sum(
r["weight"] * np.log(max(r["plateau_width_rel"], 1e-10))
for r in results.values()
)
robustness_score = np.exp(log_score)
return {
"robustness_score": robustness_score,
"parameters": results,
"verdict": (
"robust" if robustness_score > 0.1
else "check" if robustness_score > 0.01
else "overfitting"
),
}
Kullanım
report = compute_robustness_score(study, threshold_pct=10.0)
print(f"Robustness score: {report['robustness_score']:.4f}")
print(f"Verdict: {report['verdict']}")
print()
for name, metrics in report["parameters"].items():
print(f" {name}:")
print(f" Importance: {metrics['importance']:.3f}")
print(f" Sensitivity: {metrics['sensitivity_ratio']:.2f}")
print(f" Plateau width: {metrics['plateau_width_rel']:.1%}")
print()
Örnek çıktı:
Robustness score: 0.1482
Verdict: robust
htf_entry_sell:
Importance: 0.312
Sensitivity: 0.38
Plateau width: 42.5%
htf_entry_buy:
Importance: 0.251
Sensitivity: 0.45
Plateau width: 38.1%
ltf_momentum_threshold:
Importance: 0.187
Sensitivity: 1.21
Plateau width: 22.3%
stop_loss_pct:
Importance: 0.098
Sensitivity: 0.67
Plateau width: 31.0%
take_profit_pct:
Importance: 0.072
Sensitivity: 0.89
Plateau width: 28.4%
trailing_delta:
Importance: 0.031
Sensitivity: 0.22
Plateau width: 55.2%
Ayrıştırma Stratejileriyle Pratik Örnekler
Strateji A (geniş plato, sağlam), Strateji B (orta), ve Strateji C (keskin zirve, aşırı uyumlu) karşılaştırması
12 ayrıştırma parametreli üç stratejiyi inceleyelim. Her strateji 500 denemeyle Optuna optimizasyonuna tabi tutuldu.
Strateji A (~%55 PnL, ~500 işlem, ~%15 zaman)
Strateji A'nın parametreleri geniş bir plato oluşturuyor. Anahtar parametre htf_entry_sell'i alalım:
- Optimal değer: 0.020
- 0.015'teki PnL: +%51 (%7 düşüş)
- 0.025'teki PnL: +%49 (%11 düşüş)
- 0.010'daki PnL: +%43 (%22 düşüş)
- 0.030'daki PnL: +%41 (%25 düşüş)
Bunu tek boyutlu bir grafik olarak hayal ederseniz (X ekseni — htf_entry_sell değeri, Y ekseni — PnL), düz tepeli yumuşak bir parabol göreceksiniz. 0.010-0.030 aralığı platodur; burada PnL optimumun +/-%25'i içinde kalır.
Duyarlılık oranı: — sağlam.
%10 eşiğinde plato genişliği: 0.013'ten 0.027'ye, .
Strateji B (~%25 PnL, ~40 işlem, ~%5 zaman)
Strateji B az sayıda işlem üzerinde optimize edilmiştir. htf_entry_sell parametresi:
- Optimal değer: 0.018
- 0.015'teki PnL: +%24 (%4 düşüş)
- 0.025'teki PnL: +%9 (%64 düşüş)
- 0.012'deki PnL: +%11 (%56 düşüş)
Grafikte — asimetrik ve dik bir eğri. Plato yalnızca 0.015-0.020 aralığında mevcuttur. Optimumun sağında — bir uçurum.
Duyarlılık oranı: — orta düzey duyarlılık, ancak 40 işlemle bu kırmızı bayraktır. Küçük örneklem + dar plato = yüksek aşırı uyum olasılığı.
%10 eşiğinde plato genişliği: 0.016'dan 0.020'ye, .
Strateji C (~%300 PnL, ~400 işlem, ~%45 zaman)
Strateji C çarpıcı PnL gösteriyor, ancak plato analizi sorunları ortaya koyuyor:
htf_entry_sell'in optimal değeri: 0.022- 0.020'deki PnL: +%295 (%2 düşüş)
- 0.025'teki PnL: +%142 (%53 düşüş)
- 0.019'daki PnL: +%128 (%57 düşüş)
Grafikte — karakteristik "iğne": 0.022'de çok yüksek bir zirve, tüm yönlerde ani düşüş. Kontur grafiği soğuk renklerle hemen çevrili parlak bir nokta gösteriyor.
Duyarlılık oranı: — kırılgan. 400 işleme rağmen strateji, tek bir parametrenin tam değerine aşırı bağımlıdır.
%10 eşiğinde plato genişliği: 0.021'den 0.023'e, .
Özet Tablo
| Strateji | PnL | İşlemler | Duyarlılık | Plato genişliği | Sağlamlık skoru | Karar |
|---|---|---|---|---|---|---|
| Strateji A | +%55 | ~500 | 0.44 | %35 | 0.148 | Sağlam |
| Strateji B | +%25 | ~40 | 1.64 | %10 | 0.032 | Kontrol Et (küçük örneklem) |
| Strateji C | +%300 | ~400 | 3.79 | %5 | 0.008 | Aşırı Uyum |
Paradoks: +%300 PnL ile Strateji C en düşük sağlamlık skoruna sahip. "Mütevazı" +%55 ile Strateji A en sağlamdır. Bu tipik bir plato analizi sonucudur: etkileyici sayılar çoğunlukla kırılganlığı maskeler.
Her stratejinin güven aralıkları Monte Carlo bootstrap aracılığıyla ayrıca doğrulanabilir — işlemleri yeniden örneklerken PnL dağılımını gösterecektir.
3D Görselleştirme ve Isı Haritaları
İki parametrede PnL'nin taban düzlemine yansıtılan kontur çizgileriyle 3D yüzey grafiği
En önemli parametre çiftleri için 3D yüzey ve ısı haritası oluşturmak faydalıdır. Bu, manzara şekli hakkında sezgisel anlayış sağlar.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
def plot_parameter_landscape(
study: "optuna.Study",
param_x: str,
param_y: str,
grid_size: int = 50,
):
"""
Bir parametre çifti için 3D yüzey grafiği ve ısı haritası oluşturur.
"""
trials = [t for t in study.trials
if t.state == optuna.trial.TrialState.COMPLETE]
x_vals = np.array([t.params[param_x] for t in trials])
y_vals = np.array([t.params[param_y] for t in trials])
z_vals = np.array([t.values[0] for t in trials])
from scipy.interpolate import griddata
xi = np.linspace(x_vals.min(), x_vals.max(), grid_size)
yi = np.linspace(y_vals.min(), y_vals.max(), grid_size)
Xi, Yi = np.meshgrid(xi, yi)
Zi = griddata((x_vals, y_vals), z_vals, (Xi, Yi), method='cubic')
fig = plt.figure(figsize=(18, 7))
ax1 = fig.add_subplot(121, projection='3d')
surf = ax1.plot_surface(Xi, Yi, Zi, cmap=cm.viridis, alpha=0.85,
edgecolor='none')
ax1.set_xlabel(param_x)
ax1.set_ylabel(param_y)
ax1.set_zlabel('PnL, %')
ax1.set_title('3D Parameter Landscape')
fig.colorbar(surf, ax=ax1, shrink=0.5)
ax2 = fig.add_subplot(122)
hm = ax2.pcolormesh(Xi, Yi, Zi, cmap=cm.viridis, shading='auto')
contours = ax2.contour(Xi, Yi, Zi, levels=10, colors='white',
linewidths=0.8, alpha=0.7)
ax2.clabel(contours, inline=True, fontsize=8, fmt='%.0f%%')
best = study.best_trial
ax2.scatter(best.params[param_x], best.params[param_y],
color='red', s=100, marker='*', zorder=5, label='Optimum')
ax2.set_xlabel(param_x)
ax2.set_ylabel(param_y)
ax2.set_title('Contour Heatmap')
ax2.legend()
fig.colorbar(hm, ax=ax2)
plt.tight_layout()
plt.savefig(f'landscape_{param_x}_vs_{param_y}.png', dpi=150)
plt.show()
Sağlam bir strateji için 3D yüzey grafiği bir masa dağına benzer — düz tepe, yumuşak eğimler. Kırılgan bir strateji için — Matterhorn gibi keskin bir zirve. Isı haritası, 3D görünümünü tamamlar ve aynı bilgiyi izoyigitlerle birlikte tepeden aşağıya bir projeksiyonda gösterir.
Kırmızı Bayraklar: Optimizasyon Sonuçları Şüpheli Göründüğünde
Optimizasyon sonuçlarında potansiyel aşırı uyumu işaret eden uyarı göstergeleri
Optimizasyonun gerçek bir örüntü yerine aşırı uyum bulduğunu gösteren sekiz işaret:
1. Anahtar Parametre İçin Duyarlılık Oranı > 2
PnL, %10'luk parametre kaymasıyla %20'den fazla düşüyorsa — optimum kırılgandır.
2. Plato Genişliği < Arama Aralığının %10'u
"İyi" bölge, keşfedilen aralığın %10'undan azını kaplıyorsa — optimizer büyük olasılıkla bir artefakt bulmuştur.
3. İlk 3 Deneme, Medyanın 2-3 Katı PnL Veriyor
En iyi denemeler, "tepedeki" denemeler değil de geri kalanların arasında aykırı değerlerse — bu bir plato değildir.
top_3_mean = np.mean(sorted([t.values[0] for t in study.trials
if t.state == optuna.trial.TrialState.COMPLETE],
reverse=True)[:3])
median_pnl = np.median([t.values[0] for t in study.trials
if t.state == optuna.trial.TrialState.COMPLETE])
outlier_ratio = top_3_mean / median_pnl
if outlier_ratio > 2.5:
print(f"UYARI: İlk denemeler medyanın {outlier_ratio:.1f} katı — olası aşırı uyum")
4. Düşük İşlem Sayısı (< 50) ile Yüksek PnL
Küçük örneklem + yüksek PnL = tahminlerde yüksek varyans. 40 işlemde plato analizi başlı başına güvenilmezdir. Bu tür stratejiler için Monte Carlo bootstrap kritiktir.
5. Tek "Sihirli" Parametre Kombinasyonu
Kontur grafiği gri bir alan ortasında tek parlak nokta gösteriyorsa — bu bir strateji değil, veriye uydurulmuş bir kombinasyondur.
6. Çok Fazla Parametre
Her biri 10 değer alan 12 parametre için arama uzayı kombinasyon içerir. Optuna yaklaşık 500'ünü keşfeder. Böyle bir uzayda "iyi" bir artefakt bulma olasılığı yüksektir. Parametre sayısı ne kadar fazlaysa, plato analizi o kadar sıkı olmalıdır.
7. Örneklem Dışında PnL Keskin Düşüş Gösteriyor
Örneklem içi PnL +%87 ise ve walk-forward +%12 gösteriyorsa — optimizasyon parametreleri eğitim dönemine uydurmuştur. Bu konuda daha fazla bilgi Walk-Forward optimizasyonu makalesinde.
8. Parametreler Aralık Sınırlarına "Yapışmış"
Optimal değer arama ızgarası sınırıyla örtüşüyorsa — optimum aralığın dışında olabilir. Aralığı genişletip optimizasyonu yeniden çalıştırın.
Otomatik Plato Analizi Raporu
Her optimizasyondan sonra oluşturulan tek bir raporda hepsini bir araya getirmek:
import json
from datetime import datetime
def generate_plateau_report(
study: "optuna.Study",
strategy_name: str,
n_trades: int,
threshold_pct: float = 10.0,
) -> dict:
"""
Eksiksiz bir plato analizi raporu oluşturur.
"""
robustness = compute_robustness_score(study, threshold_pct)
red_flags = []
sorted_params = sorted(
robustness["parameters"].items(),
key=lambda x: x[1]["importance"],
reverse=True
)
for name, metrics in sorted_params[:3]:
if metrics["sensitivity_ratio"] > 2.0:
red_flags.append(
f"High sensitivity for {name}: "
f"S={metrics['sensitivity_ratio']:.2f}"
)
for name, metrics in robustness["parameters"].items():
if metrics["plateau_width_rel"] < 0.05:
red_flags.append(
f"Narrow plateau for {name}: "
f"W={metrics['plateau_width_rel']:.1%}"
)
all_values = sorted(
[t.values[0] for t in study.trials
if t.state == optuna.trial.TrialState.COMPLETE],
reverse=True
)
if len(all_values) > 10:
top3 = np.mean(all_values[:3])
med = np.median(all_values)
if med > 0 and top3 / med > 2.5:
red_flags.append(
f"Top trials are outliers: "
f"{top3:.1f} vs median {med:.1f} "
f"({top3/med:.1f}x)"
)
if n_trades < 50:
red_flags.append(f"Low trade count: {n_trades}")
report = {
"strategy": strategy_name,
"timestamp": datetime.now().isoformat(),
"best_pnl": study.best_value,
"n_trials": len(study.trials),
"n_trades": n_trades,
"robustness_score": robustness["robustness_score"],
"verdict": robustness["verdict"],
"red_flags": red_flags,
"parameters": robustness["parameters"],
}
return report
report = generate_plateau_report(
study, strategy_name="Strategy A", n_trades=491
)
print(json.dumps(report, indent=2, default=str))
Örnek çıktı:
{
"strategy": "Strategy A",
"best_pnl": 55.2,
"n_trials": 500,
"n_trades": 491,
"robustness_score": 0.1482,
"verdict": "robust",
"red_flags": [],
"parameters": {
"htf_entry_sell": {
"importance": 0.312,
"sensitivity_ratio": 0.44,
"plateau_width_rel": 0.35
}
}
}
Walk-Forward Doğrulama ile İlişki
İki tamamlayıcı doğrulama sistemi olarak parametrik sağlamlık (plato analizi) ve zamansal sağlamlık (walk-forward)
Plato analizi ve walk-forward doğrulama (WFO) tamamlayıcı yöntemlerdir:
- Plato analizi şu soruyu yanıtlar: "Küçük parametre kaymalarında optimum ne kadar kararlıdır?" Bu, parametrik sağlamlık kontrolüdür.
- Walk-forward şu soruyu yanıtlar: "Parametreler optimizerin görmediği veriler üzerinde işe yarıyor mu?" Bu, zamansal sağlamlık kontrolüdür.
Bir strateji plato analizini geçebilir (geniş plato) ancak walk-forward'da başarısız olabilir (piyasa rejimi değişti). Ve tam tersi — sabit parametrelerle walk-forward'ı geçebilir ancak kırılgan bir optimuma sahip olabilir.
Öneri: her zaman her iki yöntemi kullanın. Bir strateji plato analizini () ve walk-forward'ı () geçerse — bu güçlü bir sağlamlık sinyalidir. Daha fazla ayrıntı Walk-Forward optimizasyonu makalesinde.
Her aşamada PnL güven aralıklarını değerlendirmek için Monte Carlo bootstrap uygulayın. Farklı aktif süreli stratejileri doğru karşılaştırmak için aktif süre başına PnL metriğini kullanın.
Öneriler
Optimizasyon Öncesi
-
Parametre sayısını sınırlayın. Ne kadar az parametre — o kadar güvenilir plato. 5-7 parametre makul bir maksimum. 12'si zaten artırılmış dikkat gerektirir.
-
Anlamlı aralıklar belirleyin. Gerçekçi aralık 0.005-0.05 ise
htf_entry_sell'i 0.001'den 1.0'a ayarlamayın. Gereksiz geniş aralıklar plato yanılsaması yaratır. -
Yeterli deneme sayısı kullanın. 12 parametre için minimum 300-500 deneme. Güvenilir plato analizi için — 1000+.
Optimizasyon Sırasında
-
Yakınsama izleyin. Optuna 400 denemeden sonra önemli ölçüde daha iyi çözümler bulmaya devam ediyorsa — süreç yakınsamadı ve plato analizi güvenilmez olacak.
-
Budamayı dikkatli kullanın. Agresif budama (MedianPruner), erken adımlarda kötü görünen ancak tam bir manzara resmi oluşturmak için önemli olan denemeleri kesebilir.
Optimizasyon Sonrasında
-
Plato raporunu otomatik olarak oluşturun.
generate_plateau_report()işlevini optimizasyon boru hattına entegre edin. Görsel değerlendirmeye güvenmeyin — sayıları kullanın. -
İlk 5 parametreyi kontrol edin. fANOVA, 3 parametrenin varyansın %80'ini açıkladığını gösteriyorsa — kalan 9'u daha az titizlikle kontrol edebilirsiniz.
-
Temel stratejiyle karşılaştırın. Varsayılan parametreli strateji (optimizasyon yok) +%30 gösteriyorsa ve optimize edilmiş +%55 gösteriyorsa — fark yalnızca 25 pp ve plato büyük olasılıkla geniştir. Varsayılan %0 gösteriyorsa ve optimize edilmiş +%300 gösteriyorsa — tüm kârlılık kesin parametre uyumuna bağlıdır.
-
Son kontrol — walk-forward. Plato analizi, sağlamlık için gerekli ama yeterli bir koşul değildir. Her zaman örneklem dışını doğrulayın.
Sonuç
Parametre optimizasyonu güçlü bir araçtır, ancak plato analizi olmadan bir rulet oyunudur. Kararlı bir örüntü mü buldunuz yoksa modeli gürültüye mi uydurdunuz bilmiyorsunuz.
Plato analizinin üç kuralı:
-
Sağlamlık skorunu hesaplayın. Ağırlıklı plato genişliklerinin çarpımı, tüm parametrelerin sağlamlığını özetleyen tek bir sayı verir. — yeşil ışık.
-
Anahtar parametreler için duyarlılık oranı < 1. %10'luk parametre kayması %10'dan az PnL düşüşüne neden oluyorsa — parametre sağlamdır. Daha fazlaysa — dikkatli olun.
-
Kontur grafiklerini görselleştirin. Hiçbir metrik manzara şeklini anlamanın yerini tutamaz. Düz masa dağı — iyi. Keskin iğne — kötü.
Plato analizi optimizasyondan sonra 5 dakika alır ve haftalarca kârsız canlı işlemden kurtarabilir. study.optimize() ile botu başlatmak arasında zorunlu bir adımdır.
Faydalı Bağlantılar
- Optuna Belgeleri — Görselleştirme
- Hutter, F., Hoos, H., Leyton-Brown, K. — An Efficient Approach for Assessing Hyperparameter Importance (fANOVA, 2014)
- Pardo, R. — The Evaluation and Optimization of Trading Strategies
- Marcos Lopez de Prado — Advances in Financial Machine Learning, Chapter 11: Dangers of Backtesting
- Bailey, D.H. et al. — The Probability of Backtest Overfitting (2015)
- Optuna — optuna.visualization.plot_contour
- Optuna — optuna.importance.FanovaImportanceEvaluator
- Bergstra, J. & Bengio, Y. — Random Search for Hyper-Parameter Optimization (2012)
Atıf
@article{soloviov2026plateauanalysis,
author = {Soloviov, Eugen},
title = {Plateau Analysis: How to Distinguish a Robust Optimum from Overfitting},
year = {2026},
url = {https://marketmaker.cc/tr/blog/post/plateau-analysis-overfitting},
version = {0.1.0},
description = {En iyi strateji parametrelerini bulmak neden işin yalnızca yarısıdır. Kararlı bir platoyu kırılgan bir zirveden görsel ve sayısal olarak nasıl ayırt edersiniz ve neden Optuna kontur grafikleri optimize edilmiş bir stratejiyi üretime geçirmeden önce zorunlu bir adımdır.}
}
Yazarlar
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.