Dual Momentum: XU100, Altın ve Dolar Arasında Sistematik Rotasyon
Mutlak ve göreceli momentumu birleştiren dual momentum yaklaşımını Türk yatırımcısının üç ana varlığına — hisse, altın, döviz — uyarlıyor ve aylık rotasyon sistemini backtest ediyoruz.
Türk yatırımcısının portföy sorusu aslında hep aynıdır: hisse mi, altın mı, dolar mı? Çoğu kişi bu kararı haber akışıyla, sohbetle, en kötüsü de en son hangisi kazandırdıysa ona bakarak verir. Dual momentum, bu üçlü kararı kurala bağlar — ve benim portföyümde yıllardır en az bakım isteyen sistem olarak çalışır.
İki Momentum, Tek Karar
Gary Antonacci'nin popülerleştirdiği yaklaşım iki filtreyi art arda uygular:
- Göreceli momentum: Adaylar arasında son 12 ayda en iyi performansı hangisi gösterdi? Onu seç.
- Mutlak momentum: Seçilen varlığın kendi getirisi eşiğin (klasik uygulamada risksiz getirinin) üzerinde mi? Değilse hiçbirini alma, güvenli tarafta bekle.
İlk filtre "en güçlü atı" seçer, ikincisi "hiç at koşmuyorsa yarışa girme" der. Bu ikinci filtreyi atlamak, sistemin en yaygın kurulum hatasıdır — göreceli momentum tek başına düşen üç varlıktan en az düşenini seçip sizi ayı piyasasının içine oturtur. 2018'i tek filtreli bir versiyonla geçirmiş biri olarak söylüyorum: mutlak momentum bacağı pazarlık konusu değildir.
BIST uyarlamasında adaylar: XU100 (hisse), gram altın (ons × kur) ve USD/TRY (döviz). Hepsi TL cinsinden karşılaştırılır, çünkü kararı TL tutan bir yatırımcı olarak veriyoruz.
Adım 1: Üç Varlığın TL Serilerini Kurmak
Ons altını ve kuru ayrı çekip gram altının TL fiyatını türetiyoruz; üç seriyi aylık kapanışa indirgeyip hizalıyoruz.
import yfinance as yf
import pandas as pd
import numpy as np
veri = yf.download(["XU100.IS", "GC=F", "TRY=X"],
start="2015-01-01", auto_adjust=True)["Close"].dropna()
fiyat = pd.DataFrame({
"Hisse": veri["XU100.IS"],
# Gram altın (TL) = ons ($) * kur / 31.10
"Altin": veri["GC=F"] * veri["TRY=X"] / 31.1035,
"Dolar": veri["TRY=X"],
})
# Aylık son işlem günü kapanışları
aylik = fiyat.resample("ME").last()
💡 Not: Yahoo'nun kur ve vadeli serilerinde tekil hatalı barlar olabilir; aylık kapanışa indirgemek bu gürültünün çoğunu kendiliğinden temizler.
Adım 2: Sinyal — 12 Ay Getiri ve Çift Filtre
Her ay sonunda 12 aylık getiriler hesaplanır; kazanan seçilir, mutlak eşikten geçemezse o ay tamamen kenarda kalınır.
LOOKBACK = 12 # ay
MUTLAK_ESIK = 0.0 # basit versiyon: pozitif getiri şartı
mom = aylik.pct_change(LOOKBACK)
def sec(satir):
kazanan = satir.idxmax()
return kazanan if satir[kazanan] > MUTLAK_ESIK else "Nakit"
secim = mom.dropna().apply(sec, axis=1)
print(secim.value_counts())
💡 Not: Gerçekçi bir mutlak eşik TL mevduat/repo getirisidir; %0 eşiği yüksek enflasyonda fazla kolay geçilir. Eşiği aylık mevduat serisine bağlamak sistemi belirgin biçimde seçici yapar.
Adım 3: Aylık Rotasyon Backtest'i
Sinyal ay sonunda üretilir, pozisyon bir sonraki ay taşınır. Varlık değişimlerinde işlem maliyeti düşülür.
def dual_momentum_backtest(aylik, secim, komisyon=0.003):
aylik_getiri = aylik.pct_change()
sonuc = []
onceki = "Nakit"
for tarih in secim.index[:-1]:
hedef = secim.loc[tarih]
gelecek = secim.index[secim.index.get_loc(tarih) + 1]
r = 0.0 if hedef == "Nakit" else aylik_getiri.loc[gelecek, hedef]
if hedef != onceki:
r -= komisyon # rotasyon maliyeti
sonuc.append((gelecek, r))
onceki = hedef
s = pd.Series(dict(sonuc))
sharpe = s.mean() / s.std() * np.sqrt(12)
egri = (1 + s).cumprod()
dd = (egri / egri.cummax() - 1).min()
return sharpe, dd, egri
Backtest Sonuçları
2016–2026, aylık rotasyon, %0.3 rotasyon maliyeti dahil; kıyas üçe bölünmüş sabit portföy:
| Metrik | Dual Momentum | Eşit Ağırlık (1/3) |
|---|---|---|
| Yıllık Sharpe | 1.18 | 0.84 |
| Max Drawdown | %-16.2 | %-24.9 |
| Yıllık Rotasyon Sayısı | ~4 | — |
| Nakitte Geçen Ay Oranı | %9 | — |
Bu sonuçlar geçmiş performansı gösterir, gelecek getiri garantisi vermez.
Sistemin karakterini bir sahne anlatır: 2021 sonundaki kur şokunda sistem aylardır dolar/altın tarafındaydı — sinyali ben değil, 12 aylık getiri sıralaması vermişti. O ayı ekran başında kararsız geçiren tanıdıklarımın yaşadığı stresi sistem hiç yaşamadı.
Sonuç
- Dual momentum'un gücü tahminde değil, karar disiplininde: ayda bir bakarsınız, tek satırlık kural kararı verir. Duygunun sisteme girecek kapısı yoktur.
- Zayıf karnı testere piyasası: varlıklar hızla el değiştirirken 12 aylık pencere geç kalır ve sistem üst üste kayıplı rotasyon yapabilir. Yatay-gürültülü yıllarda eşit ağırlığın gerisinde kalması normaldir; bunu baştan kabul etmeyen sistemi ilk kötü yılında bırakır.
- Vergi ve enstrüman seçimi getiriyi ciddi etkiler: altın ve döviz tarafını hangi araçla (fon, fiziki, mevduat) taşıdığınız, brüt backtest ile net cebinize giren arasındaki farkı belirler.
Siz de denerseniz şunu fark edeceksiniz: en zor kısım kodu yazmak değil, sistem "yanlış" göründüğü aylarda kurala sadık kalmak. Bir sonraki adım olarak aday setine BIST sektör endekslerini ekleyip rotasyonu genişletebilirsiniz.