Riske Duyarlı Pozisyon Boyutlandırması için Konformal Tahmin
Her pozisyon boyutlandırma formülünün bir belirsizlik tahminine ihtiyacı vardır. Kelly kriteri bir kazanma olasılığına ve bir getiri oranına ihtiyaç duyar (bkz. Stratejiler için Kelly kriteri). Ortalama-varyans optimizasyonu bir kovaryans matrisine ihtiyaç duyar. VaR bir getiri dağılımına ihtiyaç duyar. Tüm bunlar veriyi üreten süreç hakkında varsayımlar gerektirir — finansal piyasaların rutin olarak ihlal ettiği varsayımlar.
Konformal tahmin farklı bir şey sunar: herhangi bir parametrik dağılımsal varsayım olmaksızın, sonlu örneklemde kapsama garantilerine sahip tahmin aralıkları. %90 kapsama isterseniz, en az %90 kapsama elde edersiniz — getirilerin Gauss, kalın kuyruklu, çarpık veya heteroskedastik olup olmamasından bağımsız olarak. Tek gereksinim değiştirilebilirliktir (exchangeability) (veya göreceğimiz gibi daha zayıf koşullar).
Bu yazı teoriyi, temel varyantları ve Python'da pozisyon boyutlandırması için pratik bir uygulamayı kapsamaktadır.
Temel Fikir: Uyumsuzluk Skorları (Nonconformity Scores)

Konformal tahmin, yeni bir gözlemin geçmiş verilere kıyasla ne kadar "tuhaf" olduğunu ölçerek çalışır. Bu tuhaflık bir uyumsuzluk skoru ile nicelenir — bir veri noktasının, verinin geri kalanında görülen örüntüye ne kadar kötü uyduğunu ölçen herhangi bir fonksiyon.
Regresyon için (getiriler gibi sürekli bir değeri tahmin etme), en basit uyumsuzluk skoru mutlak artıktır:
burada herhangi bir nokta tahmincisidir (doğrusal regresyon, rastgele orman, sinir ağı — fark etmez) ve bir veri noktasıdır.
Temel içgörü şudur: eğer veri noktaları değiştirilebilir ise, o zaman 'in arasındaki sırası üzerinde düzgün (uniform) dağılır. Bu tamamen kombinatoryal bir gerçektir — veya 'nin dağılımı hakkında hiçbir varsayım gerektirmez.
Bu sıra düzgünlüğünden, sonlu örneklemde kapsamaya sahip tahmin aralıkları inşa edebiliriz.
Split Konformal Tahmin

Split konformal tahmin (Papadopoulos ve diğerleri, 2002; Lei ve diğerleri, 2018) en pratik varyanttır. Algoritma basittir:
Adım 1. Veriyi bir eğitim kümesi ve bir kalibrasyon kümesi olarak ayırın.
Adım 2. üzerinde herhangi bir modelini eğitin.
Adım 3. Kalibrasyon kümesi üzerinde uyumsuzluk skorlarını hesaplayın:
Adım 4. İstenen bir kapsama-dışı (miscoverage) seviyesi için, 'yu 'in ampirik kuantili olarak alın. Somut olarak bu, . en küçük artıktır (ve olduğunda, yani çok küçük için, ).
Adım 5. Yeni bir noktası için tahmin aralığı şudur:
Kapsama Garantisi
Kalibrasyon verisinin ve yeni test noktasının değiştirilebilirliği altında:
Bu sonlu örneklemde bir garantidir — asimptotik bir yaklaşım değil. Herhangi bir modeli, verinin herhangi bir dağılımı ve herhangi bir örneklem büyüklüğü için geçerlidir. Eğer berbat bir tahminciyse, aralıklar sadece daha geniş olacaktır. Kapsama garantisi yine de geçerlidir.
Skorlarda eşitlik (ties) olmadığında bir üst sınır da vardır: , dolayısıyla kapsama gereksiz yere muhafazakar değildir.
Bunun İşlem İçin Önemi
Örneğin doğrusal bir regresyondan elde edilen geleneksel tahmin aralıkları Gauss hatalarını varsayar. Verinin ana kütlesi üzerinde kalibre edilmiş bir Gauss aralığı, gerçek artıklar kalın kuyruklu olduğunda (örneğin birkaç serbestlik derecesine sahip Student-) kuyrukları ciddi şekilde yanlış değerlendirebilir: merkezi kütle Gauss'tan daha incedir, dolayısıyla varyansı eşleştirilmiş bir Gauss aralığı merkez yakınında aşırı kapsama (over-cover), kuyruklarda ise eksik kapsama (under-cover) yapar ve kuyruğa uydurulmuş bir aralık bunun tersini yapar. Mesele tek bir sihirli sayı değildir — mesele, parametrik bir aralığın gerçekleşen kapsamasının, doğrulamadığınız bir dağılımsal varsayıma bağlı olmasıdır.
Konformal tahmin aralıkları bunu aşar. Model belirsiz olduğunda otomatik olarak genişlerler ve gerçek hata dağılımından bağımsız olarak marjinal kapsamayı korurlar. Bir işlemci (trader) için bu şu anlama gelir:
- Pozisyonları aralık genişliğiyle ters orantılı olarak boyutlandırırsanız, model belirsiz olduğunda otomatik olarak riski azaltırsınız.
- Kapsama garantisi, risk tahminlerinizin dürüst olduğu anlamına gelir — "gerçekleşen getirilerin %90'ı bu aralığın içine düşecek" derseniz, bu ifade istatistiksel olarak geçerlidir (marjinal olarak, değiştirilebilirlik altında).
Full Conformal ve Jackknife+
Split konformal basittir ama veriyi israf eder: kalibrasyon kümesi eğitim için kullanılamaz. İki alternatif bunu ele alır.
Full Conformal Tahmin
Full conformal tahmin (Vovk ve diğerleri, 2005) hem eğitim hem de kalibrasyon için tüm veriyi kullanır. 'in her aday değeri için:
- Veri kümesini ile genişletin.
- Modeli genişletilmiş veri kümesi üzerinde yeniden eğitin.
- Tüm uyumsuzluk skorlarını hesaplayın.
- Eğer için skor çok aşırı değilse 'yi tahmin kümesine dahil edin.
Tahmin kümesi şudur:
burada genişletilmiş veri kümesiyle hesaplanan uyumsuzluk skorlarıdır.
Full conformal en sıkı aralıkları sağlar ancak çoğu model için hesaplama açısından engelleyicidir — modeli bir ızgara (grid) üzerindeki her aday için yeniden eğitmeniz gerekir. Bir getiri tahmini için bu, tahmin başına binlerce yeniden eğitim anlamına gelebilir.
Jackknife+ (Barber ve diğerleri, 2021)
Jackknife+ bir denge kurar. Birini-dışarıda-bırak (leave-one-out, LOO) artıklarını kullanır ancak LOO katmanları arasında uydurulan modeldeki değişkenliği de hesaba katar.
, noktası dışındaki tüm veri üzerinde eğitilen modeli göstersin. LOO uyumsuzluk skorunu tek mutlak artık ile tanımlayın:
Jackknife+ tahmin aralığı, test noktasındaki LOO tahminlerinden, bu artıklarla genişletilerek inşa edilir:
Burada , kümesinin . en küçük değerini, ise . en küçük değerini gösterir. Alt sınır her LOO tahmininden artığı çıkarır; üst sınır onu ekler. Bu asimetri bütün meselenin özüdür — her iki sınırı da 'ye indirgemek, alt sınırı tahminin üzerine koyardı ki bu yanlıştır.
Jackknife+ en az kapsama garantisi sağlar (split konformalın garantisinden biraz daha zayıf), ancak hem eğitim hem de kalibrasyon için tüm veriyi kullanır. Pratikte kapsama tipik olarak 'ya yakındır.
Sınırlı veriyle eğitilen işlem modelleri için (örneğin yalnızca birkaç yüz gözlemi olan rejime özgü modeller), jackknife+ genellikle en iyi seçimdir — kıt veriyi kalibrasyon için feda etmez. Maliyeti adet model yeniden eğitimidir.
Finansal Zaman Serilerinin Sorunu: Değiştirilemezlik (Non-Exchangeability)

Standart konformal garanti değiştirilebilirlik gerektirir: 'in birleşik dağılımı permütasyonlar altında değişmezdir. Bağımsız ve özdeş dağılımlı (i.i.d.) veri için bu önemsiz biçimde geçerlidir.
Finansal zaman serileri değiştirilebilir değildir. Getiriler şunları sergiler:
- Volatilite kümelenmesi: Yüksek volatiliteli dönemleri yüksek volatiliteli dönemler izler (GARCH etkileri).
- Momentum ve ortalamaya dönüş: Getirilerde veya kareli getirilerde otokorelasyon.
- Rejim değişiklikleri: Dağılım zamanla kayar (boğa ve ayı piyasaları).
Bir zaman serisine split konformalı saf bir şekilde uygularsanız — rastgele bir kalibrasyon ayrımı kullanarak — zamansal yapıyı ihlal edersiniz. Sakin bir 2017'den gelen kalibrasyon skorları, dalgalı bir 2020'nin belirsizliğini yansıtmayacaktır. Kapsama garantiniz bozulur.
Adaptif Konformal Çıkarım (ACI)

Gibbs ve Candes (2021, NeurIPS), dağılım kaymasını ve değiştirilemeyen veriyi ele almak için Adaptif Konformal Çıkarım (ACI) yöntemini ortaya koydu. Fikir zariftir: sabit bir kapsama seviyesi kullanmak yerine, son aralıkların gerçek sonucu kapsayıp kapsamadığına göre hedef kapsama-dışı seviyesini çevrimiçi olarak uyarlayın ve her adımda skor dağılımından kuantili yeniden türetin.
ACI Algoritması
ACI aralık genişliğini doğrudan dürtmez. Adaptif bir kapsama-dışı parametresi 'yi korur ve konformal kuantili ondan yeniden hesaplar. Her zaman adımı 'de:
- Konformal eşiği, mevcut artık kümesinin (kalibrasyon skorları, artı şimdiye kadar gerçekleşmiş herhangi bir skor) ampirik -kuantili olarak hesaplayın: .
- özniteliklerini gözlemleyin, aralığını üretin.
- Gerçek değer 'yi gözlemleyin ve hata göstergesini hesaplayın.
- Seviyeyi (genişliği değil) güncelleyin:
burada bir adım büyüklüğü ve hedef kapsama-dışıdır. Eğer bir aralık ıskaladıysa (), küçülür, bu da bir sonraki kuantili yükseltir ve aralığı genişletir; eğer kapsadıysa, büyür ve aralıklar sıkılaşır. Önemli olan, buradaki 'nın olasılık birimlerinde olmasıdır — ham getiri birimlerindeki eşiği değil, 'deki bir seviyeyi dürter — dolayısıyla artıklar mertebesinde olsun ya da olmasın aynı makul davranır.
ACI için Kapsama Garantisi
ACI, bir dağılımsal modele bağlı olmayan uzun vadeli bir kapsama garantisi sağlar:
, 'e kırpıldığı için, pay bir sabit çarpı ile sınırlıdır, dolayısıyla sağ taraf 'dir ve ampirik kapsama-dışı sıklığı 'ya yakınsar. Kesin ifade şudur: ACI, uyarlanan seviyeler sınırlı kaldığı sürece — ki kırpma bunu zorunlu kılar — keyfi (rakipsel/adversarial dahil) diziler için uzun vadeli ampirik kapsama-dışı sıklığının 'ya yakınsamasını garanti eder. Bu, kapsama sıklığı üzerine bir garantidir, aralık bilgilendiriciliği üzerine değil: gerçekten rakipsel bir dizi altında aralıklar, kapsama hedefini hala tutturarak, bilgi vermeyecek kadar geniş hale gelebilir.
Dinamik Olarak Ayarlanmış ACI (DtACI)
Gibbs ve Candes (2024, JMLR), ACI'yi adım büyüklüğünün dinamik ayarlanmasıyla iyileştirdi. 'yı sabitlemek yerine, bir aday küme tutarlar ve bunları bir uzman-toplama (expert-aggregation) kuralıyla birleştirirler, son kapsaması hedefe en yakın olan 'yı kayırırlar.
Bu pratik bir sorunu ele alır: büyük bir rejim değişikliklerine hızlı uyum sağlar ancak dalgalı aralık genişlikleri üretir; küçük bir ise istikrarlıdır ama uyum sağlaması yavaştır. DtACI bunları otomatik olarak dengeler.
Bunun İşlem İçin Önemi
Bir getiri tahmin modeli kullanan bir piyasa yapıcı (market-making) stratejiyi düşünün. Sakin piyasalarda konformal aralıklar dardır — model emindir ve daha büyük pozisyonlar alabilirsiniz. Volatilite yükseldiğinde (bilanço sezonu, FOMC açıklamaları, jeopolitik şoklar), ACI seviyesi uyarlanır ve aralıklar birkaç zaman adımı içinde genişler. Pozisyon boyutlandırmanız buna yanıt olarak küçülür, hiçbir açık volatilite modeli veya rejim tespit mantığı olmadan.
Bu, sonradan akla gelen bir şey değil, birinci sınıf bir sinyal olarak belirsizlik nicelemesidir.
Konformal Aralıklarla Pozisyon Boyutlandırması

Şimdi konformal tahmini somut pozisyon boyutlandırmasına bağlayalım. Temel değişken, simetrik mutlak-artık durumuna göre tahmin aralığı yarı-genişliğidir. Simetrik aralık ile tam genişlik 'dir. Formülleri ve kodu tutarlı tutmak için baştan sona her şeyi tam genişlik 'ye göre ölçüyoruz.
Ters-Genişlik Boyutlandırması
En basit yaklaşım: aralık genişliğiyle ters orantılı boyutlandırma.
burada , risk bütçenize göre kalibre edilmiş bir ölçekleme sabitidir. Model emin olduğunda (dar aralık), daha büyük bir pozisyon alırsınız. Belirsiz olduğunda (geniş aralık), daha küçük bir pozisyon alırsınız.
Bu, volatilite hedeflemeye () benzerdir, ancak çok önemli bir farkla: konformal aralık genişliği dağılımdan bağımsız bir belirsizlik ölçüsüdür, parametrik bir volatilite tahmini değil. Yalnızca getiri varyansını değil, kapsama garantisi altındaki öngörü belirsizliğini yakalar.
Avantaj-Oranı (Edge-Ratio) Boyutlandırması ve İşlem-Yapma Filtresi
Saf ters-genişlik boyutlandırması, sinyalin kendi gücünü göz ardı eder. Doğal bir iyileştirme, avantaj oranına (edge ratio) göre ölçeklemektir — nokta tahmininin aralık genişliğine göre değeri:
Bu, bir sinyal-gürültü oranının konformal analoğudur: beklenen getirinin, dağılımdan bağımsız bir belirsizlik ölçüsüne bölünmesi. Bunu hem boyutlandırma hem de bir işlem-yapma filtresi için kullanıyoruz.
Filtre ilkeseldir. Eğer aralık sıfırı çevreliyorsa,
o zaman tahmin aralığı hem pozitif hem de negatif getirileri içerir — gerçekleşen getiri makul biçimde tahmininizin tersi işaretine sahip olabilir. Bir minimum avantaj eşiği tanımlayın ve yalnızca olduğunda işlem yapın. ", aralığın artık sıfırı çevrelemeyeceği kadar büyük" ifadesinin geometrik içeriğinin tam olarak olduğunu unutmayın (çünkü olduğunda aralık sıfırı geçer). 'yı, 'nin gerçek ölçeğinde geriye dönük test (backtest) yoluyla seçin; günlük getiri artıkları için genellikle 'nin oldukça altındadır, dolayısıyla çok küçük bir neredeyse tüm işlemleri kabul edebilirken büyük bir hiçbirini kabul etmeyebilir. Onu verilerinize göre kalibre edin.
"Konformal Kelly" Hakkında
Konformal aralıkları Kelly kesri üzerine cıvatalamak cazip gelir. Ancak zaten bir kazanma olasılığı ve bir getiri oranı 'den türetilmiş tamamlanmış, sınırlı bir kesirdir; onu gibi sınırsız bir oranla çarpmanın karar-teorik bir gerekçesi yoktur — bu 'tan bağımsız olarak 1'i aşabilir veya işaret değiştirebilir ve 'ın zaten kodladığı avantajı iki kez sayar. Bu yüzden bir "konformal Kelly" çarpanı sunmuyoruz.
Kelly'yi aralıktan sürmek istiyorsanız, ve 'yi gerçekten ondan türetmeniz gerekir ki bu, aralığın içindeki dağılım hakkında açık bir varsayım gerektirir (konformal aralıklar kasıtlı olarak bu konuda hiçbir şey söylemez — bkz. Sınırlamalar). Örneğin, varsayılan bir aralık-içi şekil altında 'yi ve aralık geometrisinden bir getiri oranını yaklaşık olarak bulabilirsiniz — ancak bu varsayımı yüksek sesle işaretleyin, çünkü tam da konformal tahminin kaçınmayı amaçladığı parametrik taahhüdü yeniden devreye sokar.
Dürüst, varsayımı az olan alternatif, avantaj oranı 'yi bir kesirsel-Kelly büzülmesi (fractional-Kelly shrinkage) olarak kullanmaktır: beklenen getiri aralığa göre büyük olduğunda büyüt, küçük olduğunda küçült ve bunu sıkı bir tavanın üzerine uygula — açıkça bir sezgisel kural (heuristic) olarak, "Kelly kesri" olarak değil.
Python Uygulaması
İşte pratik bir uygulama. Hem split/prefit yolunu hem de zamansal (EnbPI) yolu gösteriyoruz, çünkü bu yazının tüm meselesi finansal verinin değiştirilebilir olmamasıdır.
Kurulum ve Veri Hazırlığı
import numpy as np
import pandas as pd
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import KFold
from mapie.regression import MapieRegressor, MapieTimeSeriesRegressor
from mapie.subsample import BlockBootstrap
def prepare_features(prices: pd.Series, lookback: int = 20) -> pd.DataFrame:
"""Create features from a price series."""
df = pd.DataFrame()
returns = prices.pct_change()
for lag in range(1, lookback + 1):
df[f"ret_lag_{lag}"] = returns.shift(lag)
for window in [5, 10, 20]:
df[f"ret_mean_{window}"] = returns.rolling(window).mean().shift(1)
df[f"ret_std_{window}"] = returns.rolling(window).std().shift(1)
df[f"ret_skew_{window}"] = returns.rolling(window).skew().shift(1)
df["target"] = returns.shift(-1)
return df.dropna()
MAPIE ile Split Konformal (Prefit)
Split/prefit konformal için cv="prefit", method="base" gerektirir (saf split-konformal tahmincisi). method="plus" seçeneği CV+/jackknife+ tahmincisidir ve cv="prefit" ile uyumsuzdur — bunun yerine bir çapraz doğrulama (cross-validation) nesnesine ihtiyaç duyar. Burada doğru kombinasyonu kullanıyoruz ve boyutlandırmayı tam genişlik üzerinde standartlaştırıyoruz.
def split_conformal_sizing(
prices: pd.Series,
alpha: float = 0.1,
k: float = 1e-3, # scaling constant, in width units
max_position: float = 1.0,
min_edge: float = 0.05, # threshold on |pred| / width
) -> pd.DataFrame:
"""
Position sizing using split (prefit) conformal prediction intervals.
Sizing rule (consistent with the prose):
edge_t = |pred_t| / width_t
size_t = clip(k / width_t, 0, max_position) # inverse-width
size_t = 0 if edge_t < min_edge # no-trade filter
"""
df = prepare_features(prices)
X = df.drop(columns=["target"])
y = df["target"]
n_train = int(len(X) * 0.6)
n_cal = int(len(X) * 0.2)
X_train, y_train = X.iloc[:n_train], y.iloc[:n_train]
X_cal, y_cal = X.iloc[n_train:n_train + n_cal], y.iloc[n_train:n_train + n_cal]
X_test, y_test = X.iloc[n_train + n_cal:], y.iloc[n_train + n_cal:]
base_model = GradientBoostingRegressor(
n_estimators=200, max_depth=3, learning_rate=0.05, random_state=42,
)
base_model.fit(X_train, y_train)
mapie = MapieRegressor(estimator=base_model, cv="prefit", method="base")
mapie.fit(X_cal, y_cal)
y_pred, y_intervals = mapie.predict(X_test, alpha=alpha)
lower = y_intervals[:, 0, 0]
upper = y_intervals[:, 1, 0]
width = upper - lower
raw_size = k / np.where(width > 0, width, np.inf)
position_size = np.clip(raw_size, 0.0, max_position)
edge_ratio = np.abs(y_pred) / np.where(width > 0, width, np.inf)
position_size = np.where(edge_ratio < min_edge, 0.0, position_size)
position_size = position_size * np.sign(y_pred)
return pd.DataFrame({
"prediction": y_pred,
"lower": lower,
"upper": upper,
"width": width,
"edge_ratio": edge_ratio,
"position_size": position_size,
"actual": y_test.values,
}, index=X_test.index)
EnbPI ile Zaman Serisi Konformal
Getiriler değiştirilebilir olmadığı için yukarıdaki rastgele/prefit ayrım yalnızca bir temel çizgidir (baseline). MAPIE'nin method="enbpi" ile kullanılan MapieTimeSeriesRegressor'ı (Xu & Xie, 2021), zamansal bağımlılık için tasarlanmış blok bootstrap ve artık güncellemesi kullanır. Bu, yazının kendi argümanına uyan araçtır.
def enbpi_sizing(
prices: pd.Series,
alpha: float = 0.1,
k: float = 1e-3,
max_position: float = 1.0,
min_edge: float = 0.05,
) -> pd.DataFrame:
"""Position sizing with EnbPI (block-bootstrap, time-series conformal)."""
df = prepare_features(prices)
X = df.drop(columns=["target"])
y = df["target"]
n_train = int(len(X) * 0.7)
X_train, y_train = X.iloc[:n_train], y.iloc[:n_train]
X_test, y_test = X.iloc[n_train:], y.iloc[n_train:]
base_model = GradientBoostingRegressor(
n_estimators=200, max_depth=3, learning_rate=0.05, random_state=42,
)
cv = BlockBootstrap(n_resamplings=30, length=20, overlapping=False, random_state=42)
mapie_ts = MapieTimeSeriesRegressor(base_model, method="enbpi", cv=cv, agg_function="mean")
mapie_ts.fit(X_train, y_train)
y_pred, y_intervals = mapie_ts.predict(X_test, alpha=alpha, ensemble=True)
lower = y_intervals[:, 0, 0]
upper = y_intervals[:, 1, 0]
width = upper - lower
raw_size = k / np.where(width > 0, width, np.inf)
position_size = np.clip(raw_size, 0.0, max_position)
edge_ratio = np.abs(y_pred) / np.where(width > 0, width, np.inf)
position_size = np.where(edge_ratio < min_edge, 0.0, position_size)
position_size = position_size * np.sign(y_pred)
return pd.DataFrame({
"prediction": y_pred, "lower": lower, "upper": upper,
"width": width, "edge_ratio": edge_ratio,
"position_size": position_size, "actual": y_test.values,
}, index=X_test.index)
Adaptif Konformal Çıkarım (Çevrimiçi)
Canlı işlem için gerçek ACI'yi sıfırdan uyguluyoruz: kapsama-dışı seviyesi 'yi koru, onu toplamsal olarak güncelle ve her adımda kuantili artık kümesinden yeniden türet. İki sonlu örneklem ayrıntısı önemlidir:
- İnterpolasyonlu bir kuantil değil, sıra istatistiğini (order statistic) kullanın.
np.quantilevarsayılan olarak interpolasyon yapar, bu da gerekli sıranın hemen altına düşüp eksik kapsama yapabilir;method="higher"(eşdeğer olarak"inverted_cdf") geçirin. - Gerekli sıra 'i aştığında (küçük , yüksek hedef kapsama), doğru eşik 'dir (aralık = tüm doğru), en büyük artığa kelepçelemek değil. Kelepçeleme, garantisini sessizce bozar.
class AdaptiveConformalSizer:
"""
Online position sizing with Adaptive Conformal Inference (Gibbs & Candes,
2021). Updates the miscoverage LEVEL alpha_t and re-derives the quantile
from the residual set each step -- gamma is in probability units.
"""
def __init__(self, base_model, alpha=0.1, gamma=0.02,
max_position=1.0, min_edge=0.05, k=1e-3):
self.base_model = base_model
self.alpha_target = alpha # target miscoverage
self.alpha_t = alpha # adaptive miscoverage level
self.gamma = gamma # step size, in [0, 1] units
self.max_position = max_position
self.min_edge = min_edge
self.k = k
self.residuals = []
self.q_hat = np.inf
self.coverage_history = []
@staticmethod
def _conformal_quantile(residuals, alpha_t):
"""(1 - alpha_t) conformal quantile via the order statistic."""
n = len(residuals)
if n == 0:
return np.inf
rank = int(np.ceil((1.0 - alpha_t) * (n + 1)))
if rank > n: # required order statistic does not exist
return np.inf # -> interval is the whole line
level = rank / n
return float(np.quantile(residuals, min(level, 1.0), method="higher"))
def calibrate(self, X_cal, y_cal):
preds = self.base_model.predict(X_cal)
self.residuals = list(np.abs(np.asarray(y_cal) - preds))
self.q_hat = self._conformal_quantile(self.residuals, self.alpha_t)
def predict_and_size(self, X_t) -> dict:
mu_hat = self.base_model.predict(np.asarray(X_t).reshape(1, -1))[0]
lower, upper = mu_hat - self.q_hat, mu_hat + self.q_hat
width = upper - lower # = 2 * q_hat
edge_ratio = abs(mu_hat) / width if np.isfinite(width) and width > 0 else 0.0
if edge_ratio < self.min_edge:
size = 0.0
else:
size = min(self.k / width, self.max_position) if width > 0 else 0.0
return {
"prediction": mu_hat, "lower": lower, "upper": upper,
"width": width, "edge_ratio": edge_ratio,
"position_size": size * np.sign(mu_hat),
"alpha_t": self.alpha_t, "q_hat": self.q_hat,
}
def update(self, X_t, y_t: float):
"""ACI update: adapt the LEVEL, then re-derive the quantile."""
mu_hat = self.base_model.predict(np.asarray(X_t).reshape(1, -1))[0]
residual = abs(y_t - mu_hat)
covered = int(residual <= self.q_hat)
err_t = 1 - covered
self.alpha_t = float(np.clip(
self.alpha_t + self.gamma * (self.alpha_target - err_t), 0.0, 1.0
))
self.residuals.append(residual)
self.q_hat = self._conformal_quantile(self.residuals, self.alpha_t)
self.coverage_history.append(covered)
@property
def running_coverage(self) -> float:
if not self.coverage_history:
return float("nan")
return float(np.mean(self.coverage_history))
Bir Araya Getirmek: Geriye Dönük Test (Backtest) Döngüsü
def backtest_aci_sizing(prices: pd.Series, alpha=0.1, gamma=0.02) -> pd.DataFrame:
"""Backtest position sizing with Adaptive Conformal Inference."""
df = prepare_features(prices)
X = df.drop(columns=["target"]).values
y = df["target"].values
index = df.index
n_train = int(len(X) * 0.5)
n_cal = int(len(X) * 0.2)
X_train, y_train = X[:n_train], y[:n_train]
X_cal, y_cal = X[n_train:n_train + n_cal], y[n_train:n_train + n_cal]
X_test, y_test = X[n_train + n_cal:], y[n_train + n_cal:]
test_index = index[n_train + n_cal:]
model = GradientBoostingRegressor(
n_estimators=200, max_depth=3, learning_rate=0.05, random_state=42,
)
model.fit(X_train, y_train)
sizer = AdaptiveConformalSizer(base_model=model, alpha=alpha, gamma=gamma)
sizer.calibrate(X_cal, y_cal)
records = []
for i in range(len(X_test)):
result = sizer.predict_and_size(X_test[i])
result["actual"] = y_test[i]
result["pnl"] = result["position_size"] * y_test[i]
records.append(result)
sizer.update(X_test[i], y_test[i]) # online residual + level update
results = pd.DataFrame(records, index=test_index)
results["cumulative_pnl"] = results["pnl"].cumsum()
results["running_coverage"] = (
((results["lower"] <= results["actual"]) &
(results["actual"] <= results["upper"])).expanding().mean()
)
return results
Sonuçların Değerlendirilmesi
def evaluate(results: pd.DataFrame, alpha: float = 0.1):
"""Print evaluation metrics for conformal position sizing."""
covered = ((results["actual"] >= results["lower"]) &
(results["actual"] <= results["upper"]))
print(f"Target coverage: {1 - alpha:.1%}")
print(f"Empirical coverage: {covered.mean():.1%}")
print(f"Mean interval width: {results['width'].mean():.6f}")
print(f"Median position size: {results['position_size'].abs().median():.4f}")
print(f"Fraction no-trade: {(results['position_size'] == 0).mean():.1%}")
print(f"Total PnL (bps): {results['pnl'].sum() * 10000:.1f}")
sd = results['pnl'].std()
sharpe = results['pnl'].mean() / sd * np.sqrt(252) if sd > 0 else float('nan')
print(f"Sharpe (annualized): {sharpe:.2f}")
Pratik Hususlar
Uyumsuzluk Skorunun Seçilmesi
Mutlak artık varsayılan seçimdir, ancak tahmin aralığının nokta tahmini etrafında simetrik olması gerektiğini varsayar. Finansal getiriler için asimetrik aralıklar genellikle daha mantıklıdır:
- Konformalleştirilmiş Kuantil Regresyon (CQR): ve seviyelerinde kuantil regresörler uydurun, ardından konformalleştirin (Romano ve diğerleri, 2019). Aralıklar şekillerini yerel dağılıma uyarlar — düşüşler (drawdown) sırasında aşağı yönde daha geniş, ralliler sırasında yukarı yönde daha geniş. (CQR ile aralık artık simetrik değildir, dolayısıyla gerçek üst-eksi-alt genişliğidir — her yerde payda olarak kullanmaya devam edin.)
- Normalleştirilmiş skorlar: , burada yerel bir volatilite tahminidir. Bu, koşullu olarak uyarlanabilir aralıklar üretir — düşük volatilite rejimleri sırasında daha sıkı, yüksek volatilite rejimleri sırasında daha geniş — ve aynı zamanda marjinal kapsamayı korur.
Kalibrasyon Kümesi Büyüklüğü
Split konformalın kapsama garantisi herhangi bir kalibrasyon kümesi büyüklüğü için geçerlidir, ancak aralık genişliği arttıkça azalır. Çok küçük için gerekli sıra istatistiği var olmayabilir ki bu durumda dürüst eşik 'dir (bilgilendirmeyen ama geçerli bir aralık) — en büyük artığa kelepçelemek garantiyi sessizce geçersiz kılar. Pratik işlem için:
- kalibrasyon noktası makul ölçüde sıkı aralıklar verir.
- İstikrarlı kuantil tahmini için tercih edilir.
- ACI ile kalibrasyon kümesi yalnızca başlatma içindir; çevrimiçi seviye güncellemeleri gerisini halleder.
Yeniden Eğitim Sıklığı
Temel model bayatlayabilir. İki yaklaşım:
-
Periyodik olarak yeniden eğitin (örneğin aylık) ve konformal kuantili yeniden kalibre edin.
-
ACI kullanın ve adaptif seviyenin model bayatlığını telafi etmesine izin verin — modelin artıkları büyüdükçe aralıklar otomatik olarak genişler.
-
Seçenek daha basit ve şaşırtıcı derecede etkilidir. Konformal katman bir güvenlik ağı görevi görür: model bozulsa bile, uzun vadeli ACI kapsama sıklığı yine de hedefe yakınsar.
İşlem Maliyetleri
Konformal aralıklar işlem maliyetleriyle yararlı bir şekilde etkileşir. Aralıklar geniş olduğunda (yüksek belirsizlik), pozisyonlar küçüktür, dolayısıyla devir hızı (turnover) düşüktür. Aralıklar daraldığında (model emindir), pozisyonlar büyür — ancak modelin haklı olma olasılığı daha yüksektir, dolayısıyla devir hızının maliyetini ödemeye değer.
İşlem maliyetlerini doğrudan işlem-yapma filtresine de dahil edebilirsiniz:
Bu, yalnızca beklenen net avantaj, konformal genişlikle ölçeklenmiş bir eşiği aştığında işlem yapmanızı sağlar — her yerdeki aynı paydasını kullanarak.
Geleneksel Yöntemlerle Karşılaştırma
| Özellik | Gauss CI | Bootstrap CI | Konformal PI |
|---|---|---|---|
| Dağılım varsayımı | Normal hatalar | i.i.d. + asimptotik | Yok (değiştirilebilirlik) |
| Sonlu örneklem garantisi | Hayır | Hayır | Evet |
| Herhangi bir modelle çalışır | Hayır | Evet | Evet |
| Heteroskedastisiteye uyarlanır | Hayır | Kısmen | CQR / normalleştirilmiş skorlarla |
| Dağılım kaymasını ele alır | Hayır | Hayır | ACI / EnbPI varyantı |
| Hesaplama maliyeti | Düşük | Orta | Split: düşük; jackknife+: yeniden eğitim; full: engelleyici |
Bootstrap yalnızca garantisinde "asimptotiktir"; yine de i.i.d./değiştirilebilir veri ve düzgünlük (smoothness) varsayar, dolayısıyla onun dağılım-varsayımı hücresi "varsayımdan-bağımsız" değildir. Ve tek "konformal" sütunu, varyantlar arasında çok farklı maliyetleri gizler ki maliyet satırı bunları artık ayrıntılı olarak ortaya koyuyor.
Sınırlamalar
Konformal tahmin sihir değildir. İşlem için temel sınırlamalar:
-
Marjinal kapsama, koşullu değil. Garanti, 'nın marjinal olarak geçerli olmasıdır — hem hem de 'deki rastgelelik üzerinden ortalama alınmış. Belirli bir koşullama değeri için yerel kapsama 'nın üzerinde veya altında olabilir. Konformalleştirilmiş kuantil regresyon bunu kısmen ele alır.
-
Değiştirilebilirlik gerçek bir gereksinimdir. Split konformal için kalibrasyon verisi ve test noktası değiştirilebilir olmalıdır. Finansal veri değildir. ACI ve EnbPI bunu uzun vadeli bir garantiye gevşetir, ancak kısa vadeli kapsama sapabilir.
-
Aralık genişliği bir olasılık yoğunluğu değildir. Bir konformal aralık size 'nin olasılıkla nereye düşeceğini söyler, ancak aralığın içindeki dağılım hakkında hiçbir şey söylemez. Tam bir öngörü dağılımının yerine geçmez — ki bu da tam olarak ondan bir Kelly ve türetmenin neden fazladan, açık bir varsayım gerektirdiğinin nedenidir.
-
Çöp girer, daha geniş çıkar. Kötü bir temel model geniş aralıklar üretir. Konformal tahmin kapsamayı garanti eder ama faydayı değil. Modelinizin öngörü gücü yoksa, aralıklar o kadar geniş olur ki pozisyon boyutlandırıcı hiç işlem yapmaz.
Özet
Konformal tahmin, pozisyon boyutlandırmasına doğal olarak oturan, titiz ve dağılımdan bağımsız bir belirsizlik niceleme çerçevesi sağlar:
- Sonlu örneklemde kapsamaya sahip statik, çevrimdışı kalibrasyon için split konformal.
- Kalibrasyon verisi kıt olduğunda ve tüm gözlemleri kullanmak istediğinizde ( yeniden eğitim maliyetiyle) jackknife+.
- Durağan olmayan piyasalarla çevrimiçi işlem için adaptif konformal çıkarım / EnbPI.
- Ters aralık genişliği ve avantaj-oranı işlem-yapma filtresi yoluyla pozisyon boyutlandırması — ve Kelly'ye geçerseniz, gerekçesiz bir çarpan yoluyla değil, yalnızca ve 'yi dürüstçe türettikten sonra.
Parametrik alternatiflere göre temel avantaj: hiçbir zaman parametrik bir dağılımsal varsayım belirtmeniz veya doğrulamanız gerekmez. Aralıklar yapısı gereği dürüsttür (marjinal olarak, değiştirilebilirlik altında). Sistematik bir işlemci için bu, bir model riski kaynağının daha az olması anlamına gelir — ve model riskinin varoluşsal olduğu bir işte, bu önemlidir.
Kaynaklar:
- Papadopoulos, H., Proedrou, K., Vovk, V., Gammerman, A. (2002). Inductive confidence machines for regression. ECML.
- Vovk, V., Gammerman, A., Shafer, G. (2005). Algorithmic Learning in a Random World. Springer.
- Lei, J., G'Sell, M., Rinaldo, A., Tibshirani, R.J., Wasserman, L. (2018). Distribution-free predictive inference for regression. JASA.
- Xu, C., Xie, Y. (2021). Conformal prediction interval for dynamic time-series (EnbPI). ICML.
- Barber, R.F., Candes, E.J., Ramdas, A., Tibshirani, R.J. (2021). Predictive inference with the jackknife+. Annals of Statistics.
- Gibbs, I., Candes, E.J. (2021). Adaptive conformal inference under distribution shift. NeurIPS.
- Gibbs, I., Candes, E.J. (2024). Conformal inference for online prediction with arbitrary distribution shifts. JMLR.
- Romano, Y., Patterson, E., Candes, E.J. (2019). Conformalized quantile regression. NeurIPS.
- Cordier, T. et al. (2022). MAPIE: an open-source library for distribution-free uncertainty quantification. arXiv:2207.12274.
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.