← Makalelere geri dön
March 6, 2026
5 dakikalık okuma

Monte Carlo Bootstrap: Bir Backtestin Güven Aralıklarını 10 Satır Kodla Nasıl Elde Edersiniz

Monte Carlo Bootstrap: Bir Backtestin Güven Aralıklarını 10 Satır Kodla Nasıl Elde Edersiniz
#algotrading
#backtest
#Monte Carlo
#bootstrap
#güven aralıkları
#risk yönetimi
#istatistik

Bir stratejiyi backtest'ten geçirdiniz. PnL +%42, Sharpe 1,8, MaxDD -%12 sonuçlarını elde ettiniz. Sonuçlar harika görünüyor. Botu üretime alıyorsunuz ve bir ay sonra düşüşün zaten -%28'e ulaştığını ve PnL'nin sıfıra doğru ilerlediğini keşfediyorsunuz.

Ne yanlış gitti? Bu bir hata değil, "değişen piyasa" da değil. Sorun, tek bir sayı — tek nokta tahmini — temelinde karar vermiş olmanızdır. Stratejinin +%42 gösterdiğini öğrendiniz, ancak bu sayıya ne kadar güvenebileceğinizi öğrenmediniz.

Tek Nokta Tahminlerinin Sorunu

Tek nokta tahmini ile tam olasılık dağılımı karşılaştırması Tek bir veri noktası (sol) yanıltıcı bir tablo ortaya koyarken, tam dağılım (sağ) olası sonuçların gerçek aralığını ortaya çıkarır.

Tarihsel veriler üzerindeki bir backtest, belirli bir piyasa olayları dizisinden tek bir geçiştir. Sonuç, işlemlerin sırasına bağlıdır: aynı işlemlere sahip aynı strateji, farklı bir sırada tamamen farklı bir maksimum düşüş gösterebilir.

491 işlem hayal edin. Her işlem, belirli bir getiri dağılımına sahip rastgele bir olaydır. Tarihsel backtest, bu sürecin yalnızca bir gerçekleşmesini gösterir. Bu, bir zarı bir kez atıp zarın her zaman dörde geldiği sonucuna varmak gibidir.

Aslında ihtiyacımız olan şey:

  • Nokta tahmini değil, bir aralık: "%95 olasılıkla, nihai PnL X ile Y arasında olacak"
  • Tek bir maksimum düşüş değil, bir dağılım: "En kötü %5 senaryoda, düşüş Z%'yi aşıyor"
  • Ortalama değil, kuyruklar: Şans sizin tarafınızda değilse ne olur?

Monte Carlo bootstrap tam olarak bunun içindir.

Monte Carlo Bootstrap Nedir

Monte Carlo bootstrap yeniden örneklemesi: işlem verilerinden oluşturulan binlerce alternatif özkaynak yolu Bootstrap, orijinal veri setinden yerine koyarak işlemleri yeniden örnekleyerek binlerce alternatif özkaynak yörüngesi oluşturur.

Bootstrap, Bradley Efron tarafından 1979'da önerilen bir yeniden örnekleme yöntemidir. Fikir şıktır: Bir veri örneğimiz varsa, orijinalden yerine koyarak rastgele öğeler seçerek binlerce "yeni" örnek oluşturabiliriz.

Bir backtest bağlamında şu şekilde çalışır:

  1. Her işlem için bir getiri diziniz var — örneğin 491 değer
  2. Bu diziden yerine koyarak rastgele 491 değer seçiyorsunuz — bazı işlemler iki kez görünecek, bazıları hiç görünmeyecek
  3. Bu yeni örnekten bir özkaynak eğrisi oluşturuyorsunuz
  4. 10.000 kez tekrarlıyorsunuz
  5. Tek bir sayı yerine nihai metriklerin dağılımını elde ediyorsunuz

Her yineleme bir "alternatif senaryo"dur: işlemlerin sırası ve kümesi biraz farklı olsaydı ne olabilirdi.

10 Satırda Uygulama

İşte eksiksiz bir çalışan uygulama:

import numpy as np

def max_drawdown(equity_curve):
    """Calculate the maximum drawdown of an equity curve."""
    peak = np.maximum.accumulate(equity_curve)
    drawdown = (equity_curve - peak) / peak
    return drawdown.min()

trade_returns = [...]  # 491 values, e.g. [0.012, -0.005, 0.008, ...]

n_simulations = 10000
results = []

for _ in range(n_simulations):
    sampled = np.random.choice(trade_returns, size=len(trade_returns), replace=True)
    equity = np.cumprod(1 + sampled)
    results.append({
        "final_pnl": equity[-1] - 1,
        "max_dd": max_drawdown(equity),
        "sharpe": np.mean(sampled) / np.std(sampled) * np.sqrt(252)
    })

Çalıştırma süresi: Normal bir dizüstü bilgisayarda ~2 saniye. Stratejinizin 10.000 alternatif tarihi.

Güven Aralıklarını Çıkarma

PnL, MaxDD ve Sharpe Oranı için 5., 50. ve 95. yüzdeliklerle güven aralıkları Temel strateji metrikleri için güven aralıkları: PnL, MaxDD ve Sharpe Oranı; 5. (en kötü), 50. (medyan) ve 95. (en iyi) yüzdelik bantları gösterilmektedir.

Artık tek bir sayımız değil, bir dağılımımız var. İşte ondan yararlı bilgileri çıkarmanın yolu:

import pandas as pd

df = pd.DataFrame(results)

pnl_5 = np.percentile(df['final_pnl'], 5)
pnl_50 = np.percentile(df['final_pnl'], 50)
pnl_95 = np.percentile(df['final_pnl'], 95)

dd_5 = np.percentile(df['max_dd'], 5)    # 5th — worst case
dd_50 = np.percentile(df['max_dd'], 50)
dd_95 = np.percentile(df['max_dd'], 95)  # 95th — best case

print(f"PnL:   {pnl_5:.1%} | {pnl_50:.1%} | {pnl_95:.1%}")
print(f"MaxDD: {dd_5:.1%} | {dd_50:.1%} | {dd_95:.1%}")
print(f"Sharpe: {np.percentile(df['sharpe'], 5):.2f}{np.percentile(df['sharpe'], 95):.2f}")

Gerçek bir strateji için örnek çıktı:

Metrik 5. yüzdelik (en kötü) Medyan 95. yüzdelik (en iyi)
PnL +%18,3 +%41,7 +%72,1
MaxDD -%23,4 -%12,8 -%5,1
Sharpe 1,12 1,76 2,41

Artık fark açıkça ortada:

  • Backtest PnL +%42 gösterdi — ancak en kötü %5 senaryoda, PnL yalnızca +%18,3
  • Backtest MaxDD -%12 gösterdi — ancak en kötü %5 senaryoda, düşüş -%23,4
  • Sharpe 1,8 — ancak alt sınır 1,12

5. yüzdelik, "gerçekçi en kötü durum"unuzdur. Strateji 5. yüzdelikte kârlı olmaktan çıkıyorsa, onu üretime almak risklidir.

Görselleştirme: Yelpaze Grafiği

Monte Carlo bootstrap doğal olarak bir yelpaze grafiği olarak görselleştirilir — özkaynak eğrilerinden oluşan bir yelpaze:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(16, 6))

ax = axes[0]
for i in range(min(500, n_simulations)):
    sampled = np.random.choice(trade_returns, size=len(trade_returns), replace=True)
    equity = np.cumprod(1 + sampled)
    ax.plot(equity, alpha=0.02, color='#4FC3F7')

all_equities = []
for _ in range(n_simulations):
    sampled = np.random.choice(trade_returns, size=len(trade_returns), replace=True)
    equity = np.cumprod(1 + sampled)
    all_equities.append(equity)

all_equities = np.array(all_equities)
p5 = np.percentile(all_equities, 5, axis=0)
p50 = np.percentile(all_equities, 50, axis=0)
p95 = np.percentile(all_equities, 95, axis=0)

ax.fill_between(range(len(p5)), p5, p95, alpha=0.3, color='#7C4DFF', label='90% CI')
ax.plot(p50, color='#E040FB', linewidth=2, label='Median')
ax.set_title('Monte Carlo Bootstrap: Equity Curves')
ax.legend()

ax = axes[1]
ax.hist(df['final_pnl'] * 100, bins=80, color='#4FC3F7', alpha=0.7, edgecolor='#1A237E')
ax.axvline(pnl_5 * 100, color='#FF5252', linestyle='--', label=f'5th: {pnl_5:.1%}')
ax.axvline(pnl_50 * 100, color='#E040FB', linestyle='--', label=f'Median: {pnl_50:.1%}')
ax.axvline(pnl_95 * 100, color='#69F0AE', linestyle='--', label=f'95th: {pnl_95:.1%}')
ax.set_title('Distribution of Final PnL')
ax.set_xlabel('PnL, %')
ax.legend()

plt.tight_layout()
plt.savefig('monte_carlo_fan_chart.png', dpi=150)
plt.show()

Yelpaze grafiği, olası sonuçların yayılımı hakkında sezgisel bir anlayış sağlar. Dar bir yelpaze, stratejinin istikrarlı olduğu anlamına gelir. Geniş bir yelpaze ise sonucun işlem sırasıyla "şans" faktörüne büyük ölçüde bağlı olduğu anlamına gelir.

Monte Carlo Görselleştirmesi: Yelpaze Grafiği ve Dağılım Histogramı Yelpaze grafiği (sol) olası özkaynak yörüngelerinin yayılımını gösterirken, histogram (sağ) vurgulanmış güven aralıklarıyla (%5, %50, %95) nihai getirilerin yoğunluk dağılımını gösterir.

Gelişmiş Analiz: İflas Olasılığı

İflas olasılığı analizi: hayatta kalan veya iflasa düşen özkaynak eğrileri İflas olasılığı görselleştirmesi: hayatta kalan özkaynak yolları (cyan) yukarı doğru kıvrılırken, iflas eden yollar (kırmızı) sıfır-özkaynak uçurumunun altına düşer.

Bootstrap, kritik bir soruya yanıt vermenizi sağlar: stratejinin X% sermayeyi kaybetme olasılığı nedir?

ruin_threshold = -0.20
prob_ruin = (df['max_dd'] < ruin_threshold).mean()
print(f"P(MaxDD < -20%) = {prob_ruin:.1%}")

prob_loss = (df['final_pnl'] < 0).mean()
print(f"P(PnL < 0) = {prob_loss:.1%}")

worst_5pct = df['final_pnl'].quantile(0.05)
cvar = df[df['final_pnl'] <= worst_5pct]['final_pnl'].mean()
print(f"CVaR(5%) = {cvar:.1%}")

Bu metrikler tek bir backtest çalıştırmasından elde edilmesi imkânsızdır. Ancak bunlar, bir stratejiyi başlatma kararı vermek için kritiktir.

Derin düşüşlerin matematiksel olarak neden tehlikeli olduğu ve getiri asimetrisinin nasıl çalıştığı hakkında daha fazla bilgi için Kayıp-Kâr Asimetrisi makalemizi okuyun.

Klasik Bootstrap'in İşe Yaramadığı Durumlar

Yöntemin bilmek önemli olan sınırlılıkları vardır.

Getirilerin Otokorelasyonu

Klasik bootstrap, işlemlerin bağımsız olduğunu varsayar. Gerçekte bu genellikle böyle değildir — bir strateji kazanan ve kaybeden seriler yaşayabilir. Otokorelasyon önemliyse, blok bootstrap kullanın:

def block_bootstrap(returns, block_size=10, n_simulations=10000):
    """Bootstrap preserving local dependency structure."""
    n = len(returns)
    results = []

    for _ in range(n_simulations):
        starts = np.random.randint(0, n - block_size + 1, size=n // block_size + 1)
        sampled = np.concatenate([returns[s:s+block_size] for s in starts])[:n]
        equity = np.cumprod(1 + sampled)
        results.append({
            "final_pnl": equity[-1] - 1,
            "max_dd": max_drawdown(equity),
        })

    return pd.DataFrame(results)

Blok bootstrap, ardışık işlemler arasındaki yerel bağımlılıkları koruyarak MaxDD için daha gerçekçi güven aralıkları sağlar.

Blok bootstrap yeniden örneklemesi: sıralı işlem blokları karıştırılmış ve yeniden birleştirilmiş Blok bootstrap, işlem dizisini bloklara bölerek ve onları yerine koyarak yeniden örnekleyerek bloklar içindeki otokorelasyonu korur.

Piyasanın Durağan Olmaması

Bootstrap, orijinal işlem dağılımıyla çalışır. Piyasa yapısal olarak değiştiyse (örneğin volatilite düştü veya likidite değişti), tarihsel işlemler temsili olmayabilir. Bunu hesaba katmak için:

  • Kayan pencere kullanın: yalnızca son N işlem üzerinde bootstrap yapın
  • Son işlemlere daha fazla ağırlık verin: ağırlıklı bootstrap
  • Verileri piyasa rejimlerine göre bölün ve ayrı ayrı bootstrap yapın

Az Sayıda İşlem

Bootstrap, n > 30 işlem olduğunda güvenilirdir. 10 işleminiz varsa — hiçbir miktarda yeniden örnekleme yardımcı olmaz. 491 işlem mükemmel bir örnektir; sonuçlara güvenebilirsiniz.

Backtest Sağlamlığı Değerlendirme Yaklaşımlarının Karşılaştırması

Yöntem Ne sağlar Karmaşıklık Süre Ne zaman kullanılır
Tek backtest Tek nokta tahmini Minimal Saniyeler Asla nihai sonuç olarak
Walk-forward Örnek dışı metrikler Orta Dakikalar Aşırı uyum kontrolü için
Monte Carlo bootstrap Güven aralıkları Minimal ~2 sn Üretime geçmeden önce her zaman
Monte Carlo yolu Yeni fiyat yolları Yüksek Dakikalar-saatler Stres testi için
Çapraz doğrulama Katmanlardaki ortalama metrikler Orta Dakikalar Parametre ayarı için

Monte Carlo bootstrap, minimal sürede risklerin tam resmini sunan tek yöntemdir.

Kontrol Listesi: Sonuçları Yorumlama

Monte Carlo bootstrap sonuçlarını nasıl yorumlamanızı öneriyoruz:

Üretime alın eğer:

  • 5. yüzdelikte PnL pozitifse
    1. yüzdelikte MaxDD risk iştahınız için kabul edilebilirse
  • İflas olasılığı < %1
    1. yüzdelikte Sharpe > 0,5

Çalışma gerektirir eğer:

  • 5. yüzdelikte PnL sıfıra yakınsa
    1. yüzdelikte MaxDD, 50. yüzdeliğe göre önemli ölçüde kötüyse
  • Geniş yelpaze grafiği yayılımı — strateji istikrarsız

Üretime almayın eğer:

  • 5. yüzdelikte PnL negatifse
  • İflas olasılığı > %5
  • Sharpe için güven aralığı 0'ı içeriyorsa

marketmaker.cc'deki Deneyimimiz

marketmaker.cc'de kendi backtest motorumuzu geliştiriyoruz ve Monte Carlo bootstrap, pipeline'ımızın ayrılmaz bir parçasıdır. Her strateji, canlı ticarete onaylanmadan önce bootstrap'ten otomatik olarak geçirilir.

Bootstrap'i doğrudan backtest motoruna entegre ettik: bir çalıştırmanın ardından yalnızca nihai PnL'yi değil, güven aralıkları, yelpaze grafiği, iflas olasılığı ve blok ile standart bootstrap karşılaştırmasını içeren eksiksiz bir rapor alıyorsunuz. Bu 2-3 saniye ek süre alıyor — gerçek riskleri anlamak için önemsiz bir bedel.

Deneyimimizden: Stratejilerin yaklaşık %30'u tek nokta tahminiyle cazip görünen, Monte Carlo bootstrap'ten sonra filtrelenmektedir. 5. yüzdelik PnL'leri negatife dönüyor veya MaxDD kabul edilemez çıkıyor. Bootstrap olmadan, bu stratejiler üretime gidecek ve büyük olasılıkla kayıpla sonuçlanacaktı.

Sonuç

Monte Carlo bootstrap, ~10 satır kod ve ~2 saniyelik hesaplama demektir. Bir backtest'teki tek sayıyı güven aralıklarına sahip tam bir dağılıma dönüştürür. Bu, kantitatif analiz araçları arasında belki de en yüksek ROI'ye sahip olandır:

  • Minimal maliyet: 30 dakikada uygulama
  • Maksimum kazanım: Gerçek strateji risklerini anlama
  • Bağımlılık yok: Yalnızca NumPy

Henüz bootstrap kullanmıyorsanız — bugün pipeline'ınıza ekleyin. Backtest sonuçlarınıza ne kadar güvenebileceğinizi bilmenin tek yolu budur.


Kaynaklar

  1. Efron, B. — Bootstrap Methods: Another Look at the Jackknife (1979)
  2. Davison, A.C., Hinkley, D.V. — Bootstrap Methods and their Application (Cambridge)
  3. Aronson, D.R. — Evidence-Based Technical Analysis: Monte Carlo permutation
  4. QuantStart — Monte Carlo Simulation for Backtest Analysis
  5. Marcos Lopez de Prado — Advances in Financial Machine Learning, Chapter 12: Backtesting
  6. Kevin Davey — Building Winning Algorithmic Trading Systems: Monte Carlo Analysis
  7. NumPy — numpy.random.choice

Atıf

@software{soloviov2026montecarlobootstrap,
  author = {Soloviov, Eugen},
  title = {Monte Carlo Bootstrap: How to Get Confidence Intervals for a Backtest in 10 Lines of Code},
  year = {2026},
  url = {https://marketmaker.cc/tr/blog/post/monte-carlo-bootstrap-backtest},
  version = {0.1.0},
  description = {Bir backtest'ten elde edilen tek nokta tahminin neden tehlikeli bir yanılsama olduğu. Monte Carlo bootstrap'in 2 saniyelik hesaplamayla PnL ve MaxDD için %95 güven aralığı nasıl sağladığı ve bunun bir stratejiyi üretime almadan önce neden zorunlu bir adım olduğu.}
}
Sorumluluk Reddi: Bu makalede sağlanan bilgiler yalnızca eğitim ve bilgilendirme amaçlıdır ve finansal, yatırım veya ticaret tavsiyesi niteliği taşımaz. Kripto para ticareti önemli bir kayıp riski içerir.

Yazarlar

Eugen Soloviov
Eugen Soloviov

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.

Newsletter

Piyasanın Önünde Olun

Özel yapay zeka ticaret içgörüleri, piyasa analizi ve platform güncellemeleri için bültenimize abone olun.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.