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

Ticarette Gizli Markov Modelleri: Piyasa Rejimlerine Göre Stratejinizi Nasıl Uyarlarsınız

Ticarette Gizli Markov Modelleri: Piyasa Rejimlerine Göre Stratejinizi Nasıl Uyarlarsınız
#hmm
#piyasa-rejimleri
#makine-ogrenimi
#algotrading
#uyarlanabilir-stratejiler
#volatilite

Her algo yatırımcısının varoluşsal bir kriz anı gelir. Bir strateji üzerinde üç ay harcadınız. Geri test Sharpe 2.4 gösteriyor. Öz sermaye eğrisi bir sanat eseri. Botu başlatıyorsunuz. İlk iki hafta öforya getiriyor — strateji alfa üretiyor. Sonra piyasa "değişiyor" — ve momentum botunuz, her yerel zirveden alım yapıp her yerel dipten satış yaparak bir aralıkta sistematik olarak sermaye yitiyor.

Sorun strateji değil. Sorun, piyasanın tek bir sistem değil, birkaç sistem olması ve bunların uyarı vermeksizin birbirine geçiş yapmasıdır. Trend için mükemmel olan bir momentum stratejisi, aralıkta hesabı mahveder. Yatay piyasada para basan bir ızgara stratejisi, yönlü harekette patlar. Sakin piyasada istikrarlı olan mean-reversion, kara kuğu olayında margin call yer.

Soru "hangi strateji daha iyi" değil, "mevcut piyasa rejimi nedir ve hangi strateji buna uyar." İşte tam da burada Gizli Markov Modelleri (HMM) devreye giriyor — bu sezgiyi formalize etmenizi sağlayan matematiksel bir çerçeve.

Piyasalar Durağan Değildir ve Bu Bir Hata Değil, Bir Özelliktir

Hoş olmayan bir gerçekle başlayalım: neredeyse tüm temel istatistiksel modeller, verilerin durağanlığını varsayar. Ortalama ve varyans zaman içinde değişmez, otokorelasyonlar sabittir, dağılım kararlıdır. Finansal zaman serileri bu varsayımların hepsini eş zamanlı olarak ihlal eder.

Son 5 yıl içindeki BTC günlük getirilerine bakın. 2024 boğa rallisinde ortalama günlük getiri yaklaşık +%0,3, standart sapma ~%2,5. 2022 ayı piyasasında — ortalama -%0,15, standart sapma ~%4. 2023 yazının yatay piyasasında — ortalama ~%0, standart sapma ~%1,5. Bunlar farklı dağılımlara sahip üç temelden farklı istatistiksel rejimdir.

Formal olarak: tt anındaki getiri rtr_t olsun. Durağan bir dünyada, rtN(μ,σ2)r_t \sim \mathcal{N}(\mu, \sigma^2), sabit parametrelerle. Gerçekte, parametreler bizzat rassal süreçlerdir: rtN(μSt,σSt2)r_t \sim \mathcal{N}(\mu_{S_t}, \sigma^2_{S_t}), burada StS_t gizli durum (piyasa rejimi) olup sonlu sayıda değer arasında geçiş yapar.

Bu fikir 1989'da James Hamilton tarafından "Durağan Olmayan Zaman Serilerinin ve İş Çevrimlerinin Ekonomik Analizine Yeni Bir Yaklaşım" başlıklı temel makalesinde formalize edildi. İş çevrimlerinin, Markov mekanizması kullanılarak iki gizli durum arasında — durgunluk ve genişleme — geçiş olarak modellenebileceğini gösterdi. O günden bu yana Hamilton'ın modeli, ekonometride en çok atıfta bulunulan araçlardan biri haline geldi.

Üç piyasa rejimi Üç piyasa rejimi — boğa (yeşil), ayı (kırmızı) ve yatay (sarı) — geriye dönük bakıldığında görsel olarak açıkça bellidir; ancak geçişi gerçek zamanlı olarak tespit etmek önemli ölçüde daha zordur.

HMM: Analoji Yoluyla Sezgi

Formüllere dalmadan önce biraz sezgi oluşturalım.

Markov Zincirleri: Belleksiz

Markov zinciri, geleceğin yalnızca bugüne bağlı olduğu, geçmişe değil, rassal bir süreçtir. Yarınki hava bugünkü havaya bağlıdır, bir hafta önceki havaya değil (güçlü bir basitleştirme, ama model olarak işe yarar).

Piyasa rejimleri benzer şekilde davranır. Bugün piyasa boğa rejimindeyse, yarın da orada kalma olasılığı yüksektir (diyelim ki %95). Ayıya geçiş olasılığı düşüktür (%3). Yataya geçiş — daha da düşük (%2). Bu, geçiş olasılık matrisidir.

         Boğa    Ayı     Yatay
Boğa    [0.95    0.03    0.02  ]
Ayı     [0.04    0.93    0.03  ]
Yatay   [0.05    0.05    0.90  ]

Dikkat edin: köşegen elemanlar yüksektir — rejimler "yapışkandır." Piyasa her gün boğadan ayıya atlamaz. Geçiş yapmadan önce haftalarca, aylarca bir rejimde kalır. Bir rejimin beklenen süresi di=11aiid_i = \frac{1}{1 - a_{ii}}'dir. a11=0,95a_{11} = 0,95 olan boğa rejimi için bu 20 gündür. a22=0,93a_{22} = 0,93 olan ayı rejimi için — yaklaşık 14 gün.

Gizli Durumlar: Yalnızca Gölgeyi Görüyoruz

Anahtar kelime "gizli." Piyasa rejimini doğrudan gözlemlemiyoruz. Kimse "Dikkat, ayı rejimine geçiliyor" diye bir tabela asmıyor. Yalnızca gözlemleri görüyoruz — getiriler, volatilite, hacimler. Rejim, gözlemlerden çıkarılması gereken gizli bir değişkendir.

Camı olmayan bir odada olduğunuzu ve dışarıdan girenler nasıl giyinmiş diye bakarak havayı tahmin etmeye çalıştığınızı düşünün. Şemsiye? Muhtemelen yağmur. Şort ve güneş gözlüğü? Güneşli. Ama şortlu bir kişi, kesinlikle güneşli olduğu anlamına gelmez — belki sadece iyimserdir. Gözlemleri biriktirmeli ve gizli durumu olasılıksal olarak tahmin etmelisiniz.

HMM'de her gizli rejim, kendine ait dağılımından gözlemler "yayar":

  • Boğa rejimiN(μboga,σboga2)\mathcal{N}(\mu_{boga}, \sigma^2_{boga})'dan getiriler, μboga>0\mu_{boga} > 0, σboga\sigma_{boga} ılımlı
  • Ayı rejimiN(μayi,σayi2)\mathcal{N}(\mu_{ayi}, \sigma^2_{ayi})'dan getiriler, μayi<0\mu_{ayi} < 0, σayi\sigma_{ayi} yüksek
  • YatayN(μyatay,σyatay2)\mathcal{N}(\mu_{yatay}, \sigma^2_{yatay})'dan getiriler, μyatay0\mu_{yatay} \approx 0, σyatay\sigma_{yatay} düşük

Karakteristik örüntüye dikkat edin: ayı rejimi genellikle yalnızca negatif ortalamaya değil, aynı zamanda yüksek volatiliteye de sahiptir. Piyasalar aşağı gitmek için asansörü, yukarı gitmek için merdiveni kullanır — ve HMM bunu otomatik olarak yakalar.

HMM mimarisi Gizli Markov Modeli mimarisi: gizli durumlar (rejimler) Markov zincirine göre geçiş yapar, her durum kendi Gaussian dağılımından gözlemlenebilir getiriler üretir.

Üç HMM Algoritması: Forward, Viterbi, Baum-Welch

HMM ile tüm çalışma, her birinin kendi algoritmasına sahip olduğu üç temel soruna indirgenir.

Sorun 1: Bu Gözlemlerin Olasılığı Nedir? (Forward Algoritması)

Soru: Bir getiri dizisi verildiğinde, model parametreleri göz önüne alındığında tam olarak bu dizinin gözlemlenme olasılığı nedir?

Neden: Model karşılaştırması (AIC/BIC), yeterlilik kontrolü.

Nasıl çalışır: Forward Algoritması dinamik programlamadır. Her tt adımında, "forward değişken" αt(i)\alpha_t(i)'yi hesaplarız — o1,o2,,oto_1, o_2, \ldots, o_t dizisini gözlemleme ve tt anında ii durumunda olma olasılığı.

Özyineleme: αt(j)=[iαt1(i)aij]bj(ot)\alpha_t(j) = \left[\sum_i \alpha_{t-1}(i) \cdot a_{ij}\right] \cdot b_j(o_t)

Burada aija_{ij}, ii durumundan jj durumuna geçiş olasılığı; bj(ot)b_j(o_t), jj durumunda oto_t gözleminin olasılığıdır. Özetle: jj durumuna gelmiş olabileceğimiz tüm yolları toplayıp gözlem olasılığıyla çarpıyoruz.

Karmaşıklık: naif O(NT)O(N^T) yerine O(N2T)O(N^2 T); NN durum sayısı, TT dizi uzunluğu. 3 rejim ve 1000 gözlem için bu 310003^{1000} yerine 9000 işlem demektir. Fark, diyebiliriz ki, kayda değerdir.

Sorun 2: En Olası Rejim Dizisi Nedir? (Viterbi Algoritması)

Soru: Bir getiri dizisi verildiğinde, onu büyük olasılıkla hangi gizli durumlar (rejimler) dizisi üretti?

Neden: İşte tam da ticaret için ihtiyacımız olan şey — her zaman noktasındaki rejimi belirlemek.

Nasıl çalışır: Viterbi Algoritması, Forward ile aynıdır; ancak tüm yollar üzerinde toplamak yerine maksimumu alır. Tüm olası yolların olasılığını değil, en olası yolu arıyoruz.

δt(j)=maxi[δt1(i)aij]bj(ot)\delta_t(j) = \max_i \left[\delta_{t-1}(i) \cdot a_{ij}\right] \cdot b_j(o_t)

Artı, durum dizisini kendisini kurtarmak için geriye doğru geçiş (geri izleme). Sonuç, çözülmüş bir rejim dizisidir: "boğa-boğa-boğa-ayı-ayı-yatay-..."

Pratikte, ticaret için genellikle Viterbi (global optimum) değil, filtreleme kullanılır — her anda geriye yönelik durum olasılıkları: P(St=io1,,ot)P(S_t = i \mid o_1, \ldots, o_t). Bu, tüm diziyi beklemeden çevrimiçi çalışmayı ve "boğada %70, yatayda %25, ayıda %5" gibi "yumuşak" tahminler elde etmeyi mümkün kılar.

Sorun 3: Model Nasıl Eğitilir? (Baum-Welch Algoritması)

Soru: Yalnızca gözlemler verildiğinde, veri olasılığını maksimize eden model parametreleri (AA, BB, π\pi) nelerdir?

Neden: Modeli tarihsel veriler üzerinde eğitmek.

Nasıl çalışır: Baum-Welch Algoritması, EM algoritmasının (Beklenti-Maksimizasyon) özel bir halidir:

  1. E-adımı: Mevcut parametreleri kullanarak, beklenen gizli durumları hesaplayın (Forward-Backward ile)
  2. M-adımı: Bu beklenen durumlar verildiğinde olasılığı maksimize ederek parametreleri güncelleyin
  3. Yakınsama sağlanana kadar tekrarlayın

Önemli bir nüans: EM yalnızca yerel bir maksimuma yakınsama garantisi verir. Farklı başlangıç koşulları farklı sonuçlar doğurabilir. Pratikte model, farklı başlatmalarla birden çok kez eğitilir ve log-olasılığına göre en iyi sonuç seçilir. hmmlearn'de bu, n_init parametresiyle otomatik olarak yapılır.

Kripto Piyasa Rejimleri: Ne Arıyoruz

Kriptopara birimleri için, belirgin piyasa aşamaları nedeniyle klasik üç rejimli bölünme özellikle iyi işler.

Rejim 1: Boğa

  • Ortalama getiri: günde +%0,15 ... +%0,5
  • Volatilite (std): günde %2-3
  • Karakter: ılımlı geri çekilmelerle sürekli büyüme
  • Süre: kesintisiz 2-6 ay
  • Hacimler: yükselen, özellikle spot piyasalarda
  • On-zincir: MVRV > 1,5, büyüyen aktif adresler

Rejim 2: Ayı

  • Ortalama getiri: günde -%0,1 ... -%0,4
  • Volatilite (std): günde %3-6
  • Karakter: ani çöküşler, tasfiye kaskadları, ölü kedi sıçramaları
  • Süre: 1-4 ay (genellikle boğadan kısa)
  • Hacimler: panik satışlarında ani artışlar, ardından azalma
  • On-zincir: MVRV < 1, borsaya artan giriş akışı

Rejim 3: Yatay (birikim)

  • Ortalama getiri: günde ~%0
  • Volatilite (std): günde %1-2
  • Karakter: aralık içi hareket, sahte kırılmalar
  • Süre: 1-3 ay
  • Hacimler: düşük, azalan
  • On-zincir: kararlı metrikler, azalan aktivite

Neden tam olarak üç rejim, iki ya da beş değil? İki çok kabadır — yatay faz hakkındaki bilgiyi kaybedersiniz (ve piyasa yapımı botları için bu en karlı rejimdir). Beş ya da daha fazla — model aşırı uyuma kayar, geçiş olasılıkları kararsız olur, yorumlama zorlaşır. Üç, hem bilgi kriterleri (AIC/BIC) hem de ekonomik sezgi tarafından doğrulanan optimal dengedir.

Bununla birlikte, durum sayısı bir hiperparametredir ve test edilmelidir. Guidolin ve Timmermann (2007), "Çok Değişkenli Rejim Değişimi Altında Varlık Tahsisi" makalesinde karma hisse senedi ve tahvil portföyü için dört rejim buldu: çöküş, yavaş büyüme, boğa ve toparlanma.

Özellik Mühendisliği: Modele Ne Besleyeceğiz

En basit seçenek, yalnızca günlük getirileri beslemektir. Bu işe yarar, ancak geliştirilebilir. İşte pratikte kendini iyi kanıtlamış bir özellik seti:

Fiyat Özellikleri

  • Günlük log getiri: rt=ln(Pt/Pt1)r_t = \ln(P_t / P_{t-1})
  • Kayan volatilite: σt=std(rtw,,rt)\sigma_t = \text{std}(r_{t-w}, \ldots, r_t), ww penceresi üzerinden (örneğin 20 gün)
  • Kayan ortalama getiri: rˉt=mean(rtw,,rt)\bar{r}_t = \text{mean}(r_{t-w}, \ldots, r_t)

Hacim Özellikleri

  • Normalleştirilmiş hacim: Vtnorm=Vt/SMA(V,20)V_t^{norm} = V_t / \text{SMA}(V, 20)
  • Hacim-fiyat korelasyonu: kayan pencere üzerinden hacim ile mutlak getiri arasındaki korelasyon

On-Zincir Özellikleri (kriptopara birimleri için)

  • MVRV Oranı: piyasa değerinin gerçekleşen değere oranı. MVRV > 2 — piyasa aşırı ısındı, < 1 — düşük değerli
  • NVT Oranı: ağ değerinin işlem hacmine oranı. Blockchain'in F/K eşdeğeri
  • Borsa Net Akışı: borsalara net akış. Pozitif — satış baskısı, negatif — birikim
  • Aktif Adresler: aktif adres sayısı (artış = ilgi, düşüş = ilgisizlik)
import numpy as np
import pandas as pd

def prepare_features(df: pd.DataFrame, window: int = 20) -> pd.DataFrame:
    """
    HMM için özellikler hazırla.
    df, close ve volume sütunlarını içermelidir
    """
    features = pd.DataFrame(index=df.index)

    features['log_return'] = np.log(df['close'] / df['close'].shift(1))

    features['rolling_vol'] = features['log_return'].rolling(window).std()

    features['norm_volume'] = df['volume'] / df['volume'].rolling(window).mean()

    features['rolling_mean_return'] = features['log_return'].rolling(window).mean()

    features['abs_return'] = features['log_return'].abs()

    return features.dropna()

Önemli: tüm özellikler durağan olmalıdır (ya da en azından yaklaşık olarak). Log getiriler durağandır. Fiyat değildir. Hacmin normalleştirilmesi daha iyidir. Volatilite olduğu gibi bırakılabilir — o da yarı-durağandır.

Bir diğer nüans: çok değişkenli HMM (girdi olarak bir özellik vektörü beslendiğinde) tek değişkenliden daha iyi çalışır, ancak eğitim için daha fazla veri gerektirir. 5+ yıllık geçmişe sahip kripto için bu genellikle sorun değildir. 3 aylık geçmişe sahip yeni bir altcoin için — bir veya iki özelliğe bağlı kalmak daha iyidir.

Python'da hmmlearn ile Adım Adım Uygulama

Koda geçelim. hmmlearn kütüphanesi, Python'da HMM için fiili standarttır. Basit API, scikit-learn uyumluluğu, kutudan çıkar çıkmaz çalışır.

Adım 1: Veri Yükleme

import ccxt
import pandas as pd
import numpy as np
from datetime import datetime

def fetch_ohlcv(symbol='BTC/USDT', timeframe='1d', since='2020-01-01'):
    """CCXT aracılığıyla veri yükle."""
    exchange = ccxt.binance()
    since_ts = exchange.parse8601(f'{since}T00:00:00Z')
    all_ohlcv = []

    while True:
        ohlcv = exchange.fetch_ohlcv(symbol, timeframe, since=since_ts, limit=1000)
        if not ohlcv:
            break
        all_ohlcv.extend(ohlcv)
        since_ts = ohlcv[-1][0] + 1
        if len(ohlcv) < 1000:
            break

    df = pd.DataFrame(all_ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
    df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
    df.set_index('timestamp', inplace=True)
    return df

df = fetch_ohlcv('BTC/USDT', '1d', '2020-01-01')
print(f"Yüklendi {len(df)} günlük mum")
print(f"Dönem: {df.index[0]}{df.index[-1]}")

Adım 2: Özellik Hazırlama ve HMM Eğitimi

from hmmlearn.hmm import GaussianHMM
from sklearn.preprocessing import StandardScaler

features = prepare_features(df, window=20)

feature_cols = ['log_return', 'rolling_vol', 'norm_volume']
X = features[feature_cols].values

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

model = GaussianHMM(
    n_components=3,          # 3 rejim
    covariance_type='full',  # tam kovaryans matrisi
    n_iter=200,              # maksimum EM iterasyon
    random_state=42,
    tol=1e-4,                # yakınsama eşiği
    verbose=False
)

model.fit(X_scaled)

print(f"Model yakınsadı: {model.monitor_.converged}")
print(f"İterasyonlar: {model.monitor_.iter}")
print(f"Log-olasılık: {model.score(X_scaled):.2f}")

Adım 3: Rejim Çözümleme

hidden_states = model.predict(X_scaled)

state_probs = model.predict_proba(X_scaled)

features['regime'] = hidden_states
features['prob_state_0'] = state_probs[:, 0]
features['prob_state_1'] = state_probs[:, 1]
features['prob_state_2'] = state_probs[:, 2]

print(f"\nRejimler arasındaki dağılım:")
print(features['regime'].value_counts().sort_index())

Adım 4: Rejim Yorumlama

İşte ilginç — ve zorlu — kısım burasıdır. HMM, rejim 0'ın "boğa" olduğunu bilmez. Gözlem uzayında sadece üç küme bulur. Numaralandırma keyfidir ve çalıştırmadan çalıştırmaya değişebilir.

Her rejimin istatistiklerine bakmanız ve etiketleri elle atamanız gerekir:

def interpret_regimes(features, model, scaler, feature_cols):
    """
    Rejim yorumlama: ortalama getiri ve volatiliteye göre
    boğa/ayı/yatay etiketleri ata.
    """
    means_scaled = model.means_
    means_original = scaler.inverse_transform(means_scaled)

    regime_stats = {}
    for i in range(model.n_components):
        mask = features['regime'] == i
        regime_stats[i] = {
            'count': mask.sum(),
            'pct': mask.mean() * 100,
            'mean_return': features.loc[mask, 'log_return'].mean() * 100,
            'std_return': features.loc[mask, 'log_return'].std() * 100,
            'mean_vol': features.loc[mask, 'rolling_vol'].mean() * 100,
            'sharpe_daily': (features.loc[mask, 'log_return'].mean()
                           / features.loc[mask, 'log_return'].std())
        }
        print(f"\nRejim {i}: {regime_stats[i]['count']} gün "
              f"({regime_stats[i]['pct']:.1f}%)")
        print(f"  Ortalama getiri:    {regime_stats[i]['mean_return']:.3f}%/gün")
        print(f"  Volatilite:         {regime_stats[i]['std_return']:.3f}%/gün")
        print(f"  Sharpe (günlük):    {regime_stats[i]['sharpe_daily']:.3f}")

    sorted_by_return = sorted(regime_stats.keys(),
                               key=lambda x: regime_stats[x]['mean_return'])

    label_map = {
        sorted_by_return[0]: 'bear',      # en düşük getiri
        sorted_by_return[2]: 'bull',       # en yüksek getiri
        sorted_by_return[1]: 'sideways',   # orta
    }

    features['regime_label'] = features['regime'].map(label_map)
    return features, label_map

features, label_map = interpret_regimes(features, model, scaler, feature_cols)
print(f"\nRejim eşlemesi: {label_map}")

BTC için tipik çıktı kabaca şöyle görünür:

Rejim 0: 412 gün (23.8%)
  Ortalama getiri:    -0.182%/gün
  Volatilite:         4.127%/gün
  Sharpe (günlük):    -0.044

Rejim 1: 847 gün (48.9%)
  Ortalama getiri:    0.021%/gün
  Volatilite:         1.634%/gün
  Sharpe (günlük):    0.013

Rejim 2: 473 gün (27.3%)
  Ortalama getiri:    0.312%/gün
  Volatilite:         2.851%/gün
  Sharpe (günlük):    0.109

Rejim eşlemesi: {0: 'bear', 1: 'sideways', 2: 'bull'}

Dikkat: ayı rejimi yalnızca negatif getirilere değil, aynı zamanda en yüksek volatiliteye de sahiptir (%4,1'e karşı yatayda %1,6). Bu, "kaldıraç etkisi" olarak bilinen klasik ampirik bir gözlemdir — düşen piyasalar, yükselen piyasalardan daha volatildir.

Geçiş Matrisi ve Rejim Süreleri

Geçiş olasılık matrisi, HMM'nin en bilgilendirici eserlerinden biridir:

def analyze_transitions(model, label_map):
    """Geçiş matrisini ve beklenen süreleri analiz et."""
    trans_mat = model.transmat_

    inv_map = {v: k for k, v in label_map.items()}
    order = [inv_map['bull'], inv_map['bear'], inv_map['sideways']]
    labels = ['bull', 'bear', 'sideways']

    print("Geçiş olasılık matrisi:")
    print(f"{'':>10}", end='')
    for l in labels:
        print(f"{l:>10}", end='')
    print()

    for i, li in enumerate(labels):
        print(f"{li:>10}", end='')
        for j, lj in enumerate(labels):
            print(f"{trans_mat[order[i], order[j]]:>10.3f}", end='')
        print()

    print("\nBeklenen rejim süreleri (gün):")
    for i, l in enumerate(labels):
        duration = 1 / (1 - trans_mat[order[i], order[i]])
        print(f"  {l}: {duration:.1f} gün")

analyze_transitions(model, label_map)

Tipik sonuç:

Geçiş olasılık matrisi:
               bull      bear  sideways
      bull    0.952     0.018     0.030
      bear    0.031     0.937     0.032
   sideways   0.043     0.027     0.930

Beklenen rejim süreleri (gün):
  bull: 20.8 gün
  bear: 15.9 gün
  sideways: 14.3 gün

Gözlemlediklerimiz:

  1. Rejimler yapışkandır: mevcut rejimde kalma olasılığı tüm durumlar için >%93
  2. Boğa rejimi, ayıdan daha uzun sürer (20,8'e karşı 15,9 gün) — yine, piyasalar düştüklerinden daha yavaş yükselir
  3. Doğrudan boğadan ayıya geçiş düşük olasılıklıdır (%1,8) — genellikle piyasa yatay bir fazdan geçer

Son nokta ekonomik olarak sezgiseldir: piyasa nadiren aniden tersine döner. Bir ayı piyasasından önce genellikle bir dağıtım fazı (zirvede yatay), bir boğa piyasasından önce bir birikim fazı (dipte yatay) vardır.

Ticaret Stratejisi: Bir Rejim — Bir Strateji

Şimdi öğrendiklerimizi uyguluyoruz. Fikir: her zaman tek bir strateji ticaret yapmak değil, tespit edilen rejime bağlı olarak stratejiler arasında geçiş yapmak.

Boğa → Agresif Momentum

  • Artırılmış pozisyon büyüklüğü (sermayenin %100'üne kadar)
  • Trend stratejileri: kırılmalar, hareketli ortalama takibi
  • Geniş stop-loss'lar (geri çekilmelerde durdurulmayın)
  • Short yapmayın (ya da minimal short yapın)

Ayı → Savunmacı / Short Pozisyon

  • Azaltılmış pozisyon büyüklüğü (sermayenin %30-50'si)
  • Short stratejiler veya tam nakit
  • Dar stop-loss'lar
  • Put opsiyonları veya vadeli işlemler aracılığıyla hedge

Yatay → Mean-Reversion / Grid

  • Orta pozisyon büyüklüğü (sermayenin %50-70'i)
  • Grid ticaret stratejileri
  • Mean-reversion: alt sınırdan al, üst sınırdan sat
  • Dar spreadlerle piyasa yapımı
def regime_adaptive_strategy(features, initial_capital=10000):
    """
    Basit rejim uyarlamalı strateji.
    Boğa: %100 long, Ayı: %50 short, Yatay: %30 long.
    """
    capital = initial_capital
    position = 0  # 1 = long, -1 = short, 0 = pozisyon yok
    equity = [capital]
    positions = []

    for i in range(1, len(features)):
        regime = features.iloc[i]['regime_label']
        ret = features.iloc[i]['log_return']

        if regime == 'bull':
            target_exposure = 1.0   # %100 long
        elif regime == 'bear':
            target_exposure = -0.5  # %50 short
        elif regime == 'sideways':
            target_exposure = 0.3   # %30 long (ya da grid)
        else:
            target_exposure = 0.0

        daily_pnl = capital * target_exposure * ret

        capital += daily_pnl
        equity.append(capital)
        positions.append(target_exposure)

    features = features.copy()
    features['equity'] = equity
    features['position'] = [0] + positions

    return features

Geri Test: HMM-Uyarlamalı Strateji vs Sat-Al-Beklet

Şimdi asıl soru: bu, sade Sat-Al-Beklet'ten daha iyi çalışıyor mu?

def run_backtest(features, initial_capital=10000):
    """Karşılaştırmalı geri test: Buy-and-Hold vs HMM-Adaptive."""

    cumulative_returns = (1 + features['log_return']).cumprod()
    bnh_equity = initial_capital * cumulative_returns

    features = regime_adaptive_strategy(features, initial_capital)

    def calc_metrics(equity_series):
        returns = pd.Series(equity_series).pct_change().dropna()
        total_return = (equity_series.iloc[-1] / equity_series.iloc[0] - 1) * 100
        annual_return = ((1 + total_return / 100) ** (365 / len(returns)) - 1) * 100
        sharpe = returns.mean() / returns.std() * np.sqrt(365)
        max_dd = ((equity_series / equity_series.cummax()) - 1).min() * 100
        return {
            'Toplam Getiri (%)': total_return,
            'Yıllık Getiri (%)': annual_return,
            'Sharpe Oranı': sharpe,
            'Maks. Düşüş (%)': max_dd
        }

    bnh_metrics = calc_metrics(bnh_equity)
    hmm_metrics = calc_metrics(features['equity'])

    print(f"{'Metrik':<25} {'Buy&Hold':>12} {'HMM-Adaptive':>14}")
    print("-" * 53)
    for key in bnh_metrics:
        print(f"{key:<25} {bnh_metrics[key]:>12.2f} {hmm_metrics[key]:>14.2f}")

    return features, bnh_equity

features, bnh_equity = run_backtest(features)

Geri test sonuçları Öz sermaye eğrisi karşılaştırması: Sat-Al-Beklet (mavi) ve HMM-uyarlamalı strateji (turuncu). Uyarlamalı strateji, ayı fazlarında düşüşleri önemli ölçüde azaltır.

BTC için tipik sonuçlar (2020-2025):

Metrik                     Buy&Hold   HMM-Adaptive
-----------------------------------------------------
Toplam Getiri (%)            487.32         623.18
Yıllık Getiri (%)             42.71          49.84
Sharpe Oranı                   1.12           1.68
Maks. Düşüş (%)              -76.42         -38.17

Temel gözlem: HMM-uyarlamalı strateji, mutlaka daha yüksek toplam getiri sağlamak zorunda değildir (bu örnekte sağlasa da), ancak maksimum düşüşü dramatik biçimde azaltır — %76'dan %38'e. Sharpe 1,12'den 1,68'e yükseldi. Bu, risk-ayarlı getiride bir iyileşmedir, sadece "daha fazla para" değil.

Neden? Çünkü ayı rejiminde strateji, büyük çöküşlerden kaçınarak savunmacı ya da short moduna geçer. Bunun bedeli, trendlere gecikmeli giriştir (model, boğa rejimini birkaç günlük bir gecikmeyle tespit eder) ve geçiş dönemlerinde yanlış geçişlerdir.

Sonuçların Görselleştirilmesi

import matplotlib.pyplot as plt
import matplotlib.dates as mdates

fig, axes = plt.subplots(3, 1, figsize=(14, 10), sharex=True)

axes[0].plot(features.index, bnh_equity, label='Buy & Hold', alpha=0.8)
axes[0].plot(features.index, features['equity'], label='HMM-Adaptive', alpha=0.8)
axes[0].set_ylabel('Sermaye ($)')
axes[0].legend()
axes[0].set_title('Öz Sermaye Eğrisi: Buy & Hold vs HMM-Adaptive')

colors = {'bull': '#2ecc71', 'bear': '#e74c3c', 'sideways': '#f39c12'}
for regime in ['bull', 'bear', 'sideways']:
    mask = features['regime_label'] == regime
    axes[1].scatter(features.index[mask], df.loc[features.index[mask], 'close'],
                    c=colors[regime], s=2, label=regime, alpha=0.7)
axes[1].set_ylabel('BTC Fiyatı ($)')
axes[1].set_yscale('log')
axes[1].legend()
axes[1].set_title('Rejime Göre Renklendirilmiş BTC Fiyatı')

for i, (regime, color) in enumerate(colors.items()):
    inv_map = {v: k for k, v in label_map.items()}
    state_idx = inv_map[regime]
    axes[2].fill_between(features.index,
                          features[f'prob_state_{state_idx}'],
                          alpha=0.4, color=color, label=regime)
axes[2].set_ylabel('Rejim Olasılığı')
axes[2].legend()
axes[2].set_title('Geriye Yönelik Rejim Olasılıkları')

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

Gelişmiş Teknikler

Temel HMM iyi bir başlangıç noktasıdır, ancak sınırdan çok uzaktır.

Hiyerarşik HMM

Hiyerarşik bir HMM'de, üst seviye "makro-rejimi" (küresel trend, yıllık döngüler) belirler ve alt seviye "mikro-rejimi" (hafta içi/ay içi dalgalanmalar) belirler. R için fHMM paketi, Journal of Statistical Software'de 2024 yılında yayımlanan (Oelschlager, Adam, Michels) finansal zaman serileri için tam olarak bu fikri uygular.

Örnek: "boğa döngüsü" makro-rejimi içinde "ralli", "düzeltme" ve "konsolidasyon" mikro-rejimlerini barındırır. Bu, boğa piyasasındaki her %10'luk geri çekilmede paniklemekten alıkoyar — model, boğa döngüsündeki bir düzeltmenin normal olduğunu anlar.

Genişletilmiş Özelliklerle Çok Değişkenli HMM

Tek değişkenli getiri yerine bir özellik vektörü besleriz: getiri + volatilite + hacim + on-zincir verisi. Bu, modelin piyasa durumu hakkında "daha fazla bilgi görmesini" sağlar.

from hmmlearn.hmm import GaussianHMM

extended_features = ['log_return', 'rolling_vol', 'norm_volume',
                     'rolling_mean_return', 'abs_return']

X_extended = features[extended_features].values
scaler_ext = StandardScaler()
X_ext_scaled = scaler_ext.fit_transform(X_extended)

model_mv = GaussianHMM(
    n_components=3,
    covariance_type='full',     # tam kovaryans matrisi
    n_iter=300,
    random_state=42,
    init_params='stmc',         # tüm parametreleri başlat
    verbose=False
)
model_mv.fit(X_ext_scaled)

n_params_base = 3 * (3 + 3 + 3*4/2) + 3*2    # basitleştirilmiş tahmin
n_params_ext = 3 * (5 + 5 + 5*6/2) + 3*2

bic_base = -2 * model.score(X_scaled) * len(X_scaled) + n_params_base * np.log(len(X_scaled))
bic_ext = -2 * model_mv.score(X_ext_scaled) * len(X_ext_scaled) + n_params_ext * np.log(len(X_ext_scaled))

print(f"BIC temel model:      {bic_base:.0f}")
print(f"BIC genişletilmiş model: {bic_ext:.0f}")
print(f"Genişletilmiş daha iyi: {bic_ext < bic_base}")

HMM + ML Ensemble

Modern yaklaşım: HMM'yi bir ticaret sistemi olarak değil, bir sonraki model için özellik üretici olarak kullanmak. Gupta ve diğerleri (2025) "Görüşlerin ormanı: Piyasa rejimi değişimi tespiti ve ticareti için çok modelli ensemble-HMM oylama çerçevesi" makalesinde açıklanan fikir:

  1. HMM mevcut rejimi (ya da rejim olasılıklarını) belirler
  2. Rejim, Random Forest / Gradient Boosting'e ek özellik olarak beslenir
  3. ML modeli, rejimi hesaba katarak belirli ticaret kararları alır
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import TimeSeriesSplit

features['regime_0_prob'] = state_probs[:, 0]
features['regime_1_prob'] = state_probs[:, 1]
features['regime_2_prob'] = state_probs[:, 2]

features['target'] = (features['log_return'].shift(-1) > 0).astype(int)

ml_features = ['log_return', 'rolling_vol', 'norm_volume',
               'regime_0_prob', 'regime_1_prob', 'regime_2_prob']

X_ml = features[ml_features].dropna()
y_ml = features.loc[X_ml.index, 'target'].dropna()

common_idx = X_ml.index.intersection(y_ml.index)
X_ml = X_ml.loc[common_idx]
y_ml = y_ml.loc[common_idx]

tscv = TimeSeriesSplit(n_splits=5)
scores = []

for train_idx, test_idx in tscv.split(X_ml):
    X_train, X_test = X_ml.iloc[train_idx], X_ml.iloc[test_idx]
    y_train, y_test = y_ml.iloc[train_idx], y_ml.iloc[test_idx]

    clf = GradientBoostingClassifier(n_estimators=100, max_depth=3, random_state=42)
    clf.fit(X_train, y_train)
    score = clf.score(X_test, y_test)
    scores.append(score)

print(f"Walk-Forward Doğruluğu: {np.mean(scores):.3f} +/- {np.std(scores):.3f}")

Prodüksiyon: Tuzaklar

Güzel bir geri test, işin yalnızca yarısıdır. Prodüksiyonda birkaç hoş olmayan sürpriz bekler.

Gecikme Sorunu (Look-Ahead Bias)

HMM, rejimi mevcut ve geçmiş verilere dayalı olarak belirler; ancak bir geri testte tüm veri seti üzerinde, gelecek verileri de dahil olmak üzere model eğitme ayartısı vardır. Bu, look-ahead bias'tır ve geri testi kurguya dönüştürür.

Çözüm: Walk-Forward yaklaşımı. Modeli tt anına kadar olan veriler üzerinde eğitin, tt anında rejimi tahmin edin, ardından pencereyi kaydırın. Tam olarak Walk-Forward Optimizasyonu hakkındaki makalemizde açıklandığı gibi.

def walk_forward_hmm(features, feature_cols, train_window=252, retrain_freq=21):
    """
    Walk-Forward HMM: kayan pencere üzerinde eğit,
    sonraki retrain_freq günlerde tahmin et.
    """
    regimes_wf = pd.Series(index=features.index, dtype=float)

    for start in range(train_window, len(features), retrain_freq):
        train_data = features.iloc[start - train_window:start]
        X_train = train_data[feature_cols].values

        scaler = StandardScaler()
        X_train_scaled = scaler.fit_transform(X_train)

        model = GaussianHMM(n_components=3, covariance_type='full',
                            n_iter=100, random_state=42)
        try:
            model.fit(X_train_scaled)
        except Exception:
            continue

        end = min(start + retrain_freq, len(features))
        test_data = features.iloc[start:end]
        X_test = test_data[feature_cols].values
        X_test_scaled = scaler.transform(X_test)

        predicted = model.predict(X_test_scaled)
        regimes_wf.iloc[start:end] = predicted

    return regimes_wf

Yeniden Eğitim Takvimi

Modeli ne sıklıkla yeniden eğitmelisiniz? Çok seyrek — model bayatlar, piyasa değişir. Çok sık — model kararsız hale gelir, rejimler "sıçrar."

Ampirik öneriler:

  • Günlük veriler için: her 1-4 haftada bir yeniden eğit (21 işlem günü iyi bir varsayılandır)
  • Eğitim penceresi: 6-12 ay (252 işlem günü — bir yıl)
  • İzleme: yeni verilerdeki log-olasılığı bir eşiğin altına düşerse — planlanmamış yeniden eğitim

Etiket Kararsızlığı

Her yeniden eğitimde, durum numaralandırması değişebilir: "rejim 0" (boğa) olan şey "rejim 2" olabilir. Durumları istatistiklerine göre (ortalama getiri, volatilite) otomatik olarak eşleştirmeniz gerekir.

Çevrimiçi Güncelleme

Gerçek zamanlı ticaret için, tam günlük yeniden eğitim fazla maliyetlidir. Forward filtreleme kullanabilirsiniz: model parametrelerini sabitleyin, ancak her yeni gözlemle birlikte geriye yönelik durum olasılıklarını güncelleyin. Bu anlık bir işlemdir.

def online_regime_update(model, scaler, new_observation, prev_state_probs):
    """
    Tüm modeli yeniden eğitmeden rejim olasılıklarının
    çevrimiçi güncellemesi.
    """
    obs_scaled = scaler.transform(new_observation.reshape(1, -1))

    from scipy.stats import multivariate_normal
    emission_probs = np.array([
        multivariate_normal.pdf(obs_scaled[0],
                                 mean=model.means_[i],
                                 cov=model.covars_[i])
        for i in range(model.n_components)
    ])

    transition = model.transmat_.T  # sütundan satıra transpoz
    predicted = transition @ prev_state_probs
    updated = emission_probs * predicted
    updated /= updated.sum()  # normalizasyon

    return updated

Durum Sayısını Seçme

Üç rejim iyi bir varsayılan olsa da, alternatifler test edilmelidir:

from hmmlearn.hmm import GaussianHMM

def select_n_components(X_scaled, max_components=6):
    """BIC ile optimal durum sayısını seç."""
    results = []
    for n in range(2, max_components + 1):
        model = GaussianHMM(n_components=n, covariance_type='full',
                            n_iter=200, random_state=42)
        model.fit(X_scaled)

        log_likelihood = model.score(X_scaled) * len(X_scaled)
        n_features = X_scaled.shape[1]
        n_params = (n * (n - 1)
                   + n * n_features
                   + n * n_features * (n_features + 1) / 2
                   + (n - 1))
        bic = -2 * log_likelihood + n_params * np.log(len(X_scaled))

        results.append({'n_components': n, 'BIC': bic,
                        'log_likelihood': log_likelihood})
        print(f"n={n}: BIC={bic:.0f}, LL={log_likelihood:.0f}")

    best = min(results, key=lambda x: x['BIC'])
    print(f"\nBIC'e göre optimal durum sayısı: {best['n_components']}")
    return results

results = select_n_components(X_scaled)

Sınırlılıklar ve Uyarılar

Sorunlar hakkında sessiz kalmak dürüst olmaz.

Gaussian varsayımı. Temel GaussianHMM, her rejimdeki getirilerin normal dağıldığını varsayar. Gerçek dağılımlar ağır kuyruklar ve asimetri içerir. Kısmi çözüm, Student-t dağılımı veya GMMHMM (durum başına Gaussian Karışımı) kullanmaktır.

Durum sayısı sizin seçiminizdir. BIC yardımcı olur, ama her zaman kesin değildir. İki farklı araştırmacı farklı sayıda rejime ulaşabilir ve her ikisi de "haklı" olacaktır.

Geçiş dönemleri. Model, rejim geçişleri sırasında belirsizdir. Olasılıklar yaklaşık eşit olarak dağılır ve strateji "bulanık" bir sinyal alır. Çözüm, eşik kuralıdır: yeni rejimin olasılığı %70-80'i geçtiğinde stratejileri değiştirin.

Aşırı uyum. Her model gibi, HMM de aşırı uyuma kayabilir. Özellikle çok sayıda durum ya da özellikle. Walk-Forward doğrulaması zorunludur.

Kripto'ya özgü sorunlar. Kriptopara piyasası genç ve yapısal olarak kararsızdır. 2017'nin "boğa piyasası" ve 2024'ün "boğa piyasası" istatistiksel olarak farklı olgulardır. Model döngüler arasında genelleştiremeyebilir.

Daha Fazla Okuma

Daha derine inmek isteyenler için:

Temel çalışmalar:

  • Hamilton, J.D. (1989). A New Approach to the Economic Analysis of Nonstationary Time Series and the Business Cycle. Econometrica, 57(2), 357-384. — Markov-switching modeller üzerine temel çalışma
  • Guidolin, M., & Timmermann, A. (2007). Asset Allocation under Multivariate Regime Switching. Journal of Economic Dynamics and Control, 31(11), 3503-3544. — Varlık tahsisine pratik uygulama
  • Ang, A., & Bekaert, G. (2002). Regime Switches in Interest Rates. Journal of Business & Economic Statistics, 20(2), 163-182. — Faiz oranlarındaki rejimler

Modern araştırma:

  • Gupta, R., Kapoor, S., Gupta, H., & Natesan, S. (2025). A forest of opinions: A multi-model ensemble-HMM voting framework for market regime shift detection and trading. Data Science in Finance and Economics. — Rejim tespitine ensemble yaklaşımı
  • Oelschlager, L., Adam, T., & Michels, R. (2024). fHMM: Hidden Markov Models for Financial Time Series in R. Journal of Statistical Software. — Finans için hiyerarşik HMM
  • Bitcoin Price Regime Shifts: A Bayesian MCMC and Hidden Markov Model Analysis of Macroeconomic Influence. Mathematics, 2025. — Bayesian yaklaşımıyla Bitcoin için HMM

Pratik kılavuzlar:

Sonuç

Gizli Markov Modelleri sihirli bir mermi değil, bir araçtır. Kullanışlı, matematiksel olarak temelli, istatistikte yarım asır, finansta ise üç on yıllık bir geçmişe sahip.

HMM'nin ticaret için temel değeri, "piyasayı tahmin etmesi" değildir (kimse yapmıyor), deneyimli bir yatırımcının sezgisini formalize etmesidir: piyasa farklı aşamalardan geçer ve strateji uyum sağlamalıdır. "Piyasanın şu an ayı olduğunu hissediyorum" yerine "ayı rejimi olasılığı %82, bir ayı döngüsünün ortalama süresi 16 gün, 5. gündeyiz" ifadesini elde edersiniz.

HMM'yi ticaret yığınınıza entegre etmeli misiniz? Farklı piyasa koşulları için birden fazla stratejiniz varsa ve bunları manuel olarak değiştirmekten yorduysanız — kesinlikle evet. Tek bir strateji ticareti yapıyor ve genişletmeyi planlamıyorsanız — şimdilik bir kenara bırakın, ama aklınızda tutun.

Ve unutmayın: en iyi model, bir geri testte kazanan değil, prodüksiyonda çalışandır.


Atıf: Bu makaledeki materyalleri araştırmanızda veya projelerinizde kullanıyorsanız, lütfen şunu atıfta bulunun:

Ticarette Gizli Markov Modelleri: Piyasa Rejimlerine Göre Stratejinizi Nasıl Uyarlarsınız. marketmaker.cc, 2026. URL: https://marketmaker.cc/tr/blog/post/regime-detection-hmm-adaptive-trading

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.