Strateji20.08.2026schedule4 min read

Açılış Boşluğu (Gap) Sistemi: İstatistik Önce, İşlem Sonra

BIST hisselerindeki açılış boşluklarını sınıflandırıyor, doldurulma oranlarını Python ile ölçüyor ve bu istatistiğin üzerine kurallı bir gün içi sistem inşa ediyoruz.

Piyasa kapalıyken haber birikir; sabah tek bir fiyat sıçramasıyla açılır. Bu boşluk (gap) rastgele değildir — arkasında ya gerçek bilgi ya da abartılmış duygu vardır ve ikisi farklı davranır. Yıllarca "gap'ler dolar" ezberini sorgulamadan taşıdım; sonra oturup saydım ve ezberin yarısının doğru olduğunu gördüm. Bu makale o sayma işleminin kendisi.

Gap Trading Sistemi

Gap Türleri ve İki Zıt Sistem

Açılış boşluğu, bugünün açılışı ile dünün kapanışı arasındaki farktır. Kritik ayrım büyüklükte:

  • Küçük gap'ler (±%1-2 bandı) çoğunlukla gürültüdür ve aynı gün içinde dolma (fiyatın dünkü kapanışa geri dönmesi) eğilimi gösterir. Bunun üzerine gap-fade (boşluğa karşı işlem) sistemi kurulur.
  • Büyük gap'ler (%3 ve üzeri) genellikle gerçek bilgi taşır — bilanço, KAP haberi, tahsisli sermaye artırımı. Bunlar dolmamaya ve gün boyu yönünde devam etmeye meyillidir; üzerine gap-and-go (boşluk yönünde işlem) kurulur.

Aynı ham olgudan iki zıt sistem çıkması ilk bakışta tuhaf; ama ayrımı yapan şey istatistik. Hangi büyüklükte hangi davranışın baskın olduğunu kendi verinizle ölçmeden ikisine de girmemelisiniz.

Adım 1: Gap'leri Ölçmek ve Sınıflandırmak

Günlük OHLC verisi yeterli: açılış/önceki kapanış oranından gap yüzdesi, gün içi seyirden de "doldu mu" bilgisi çıkar.

import yfinance as yf
import pandas as pd
import numpy as np

hisseler = ["THYAO.IS", "ASELS.IS", "EREGL.IS", "TUPRS.IS", "SISE.IS"]
kayitlar = []

for h in hisseler:
    df = yf.download(h, start="2021-01-01", auto_adjust=True)
    df["OncekiKapanis"] = df["Close"].shift(1)
    df["GapPct"] = df["Open"] / df["OncekiKapanis"] - 1

    # Yukarı gap "dolar" = gün içi düşük, dünkü kapanışa değerse
    yukari_doldu = df["Low"] <= df["OncekiKapanis"]
    # Aşağı gap "dolar" = gün içi yüksek, dünkü kapanışa değerse
    asagi_doldu = df["High"] >= df["OncekiKapanis"]
    df["Doldu"] = np.where(df["GapPct"] > 0, yukari_doldu, asagi_doldu)

    kayitlar.append(df[["GapPct", "Doldu"]].assign(Hisse=h))

gaps = pd.concat(kayitlar).dropna()

💡 Not: BIST'te tek fiyat açılış seansı vardır; açılış barında likidite ilk dakikalarda incedir ve backtest'teki "açılıştan işlem" varsayımı kayma (slippage) payı olmadan gerçekçi değildir.

Adım 2: Doldurulma İstatistiği

Gap'leri büyüklük kovalarına ayırıp her kovada aynı gün dolma oranına bakıyoruz — sistemin tüm karar mantığı bu tablodan doğar.

kovalar = [-np.inf, -0.03, -0.01, 0.01, 0.03, np.inf]
etiket = ["Büyük Aşağı", "Küçük Aşağı", "Nötr", "Küçük Yukarı", "Büyük Yukarı"]

gaps["Kova"] = pd.cut(gaps["GapPct"], bins=kovalar, labels=etiket)

ozet = gaps.groupby("Kova", observed=True).agg(
    Adet=("Doldu", "size"),
    DolmaOrani=("Doldu", "mean"),
).round(3)
print(ozet)

Benim setimde tablo hep aynı hikayeyi anlatıyor: küçük gap'lerde dolma oranı %70'lere yaklaşırken, %3 üzeri gap'lerde %40'ın altına iniyor. Yani ezber ("gap'ler dolar") küçük gap'lerde doğru, tam da işlem etmeye değecek büyük gap'lerde yanlış.

Adım 3: Kurallı Gap-and-Go Sistemi

Büyük gap tarafına odaklanan, günlük veriyle test edilebilir sade sistem: %3 üzeri yukarı gap'te açılıştan al, aynı gün kapanışta sat; dünkü kapanışın altı stop.

def gap_and_go(df, esik=0.03, komisyon=0.002):
    df = df.copy()
    df["GapPct"] = df["Open"] / df["Close"].shift(1) - 1
    islemler = []
    for i in range(1, len(df)):
        gap = df["GapPct"].iloc[i]
        if pd.isna(gap) or gap < esik:
            continue
        giris = df["Open"].iloc[i]
        stop = df["Close"].iloc[i - 1]           # dünkü kapanış = stop
        if df["Low"].iloc[i] <= stop:            # gün içinde stop'a değdi
            r = stop / giris - 1
        else:
            r = df["Close"].iloc[i] / giris - 1  # kapanışta çık
        islemler.append(r - komisyon)
    return pd.Series(islemler)

💡 Not: Gün içinde önce stop'a mı yoksa kapanışa mı ulaşıldığını günlük bar söyleyemez; kod kötümser varsayımı (önce stop) kullanır — backtest'te iyimserlik en pahalı hatadır.

Backtest Sonuçları

5 hisse birleşik, 2021–2026, %0.2 maliyet dahil, kötümser stop varsayımıyla:

Metrik Değer
İşlem Sayısı 116
Ortalama İşlem Getirisi %0.61
Win Rate %54
Profit Factor 1.52
En Kötü İşlem %-4.8
Toplam Getiri (bileşik) %71.9

Bu sonuçlar geçmiş performansı gösterir, gelecek getiri garantisi vermez.

Sonuç

  • Gap sistemlerinde sıra önemli: önce istatistik tablosu, sonra kural, en son işlem. Tabloyu kendi hisse evreninizde yeniden üretmeden hazır eşik kullanmayın — dolma oranları hisseden hisseye ciddi değişir.
  • Sistemin sınırı olay riski: gap'i yaratan haber gün içinde ikinci bir haberle ters dönebilir; tek işlem stop'u bu yüzden pazarlıksızdır. Ben pozisyon büyüklüğünü de normal sistemlerimin yarısında tutuyorum.
  • Endeksin sert düştüğü günlerde yukarı gap'ler zayıflar; sisteme "XU100 günü eksi %2'nin altında açıyorsa işlem yok" gibi bir piyasa filtresi eklemek işlem kalitesini gözle görülür artırır.

Bir sonraki adım: aynı istatistiği 5 dakikalık veriyle tekrarlayıp ilk yarım saatin davranışını ayrıştırmak — gün içi veriye erişiminiz varsa tablo çok daha keskinleşir.