TEFAS (Türkiye Elektronik Fon Alım Satım Platformu) için modern Python sarmalayıcısı — Akamai TSPD bypass için curl_cffi TLS impersonation kullanır.
Project description
tefasmak
TEFAS (Türkiye Elektronik Fon Alım Satım Platformu) için modern bir Python sarmalayıcısı. Yeni TEFAS sitesinin (Nisan 2026'dan itibaren Next.js'e taşındı) public JSON endpoint'lerine erişir.
pip install tefasmak
from tefasmak import fon_anlik_bilgi, fon_5y_fiyat, fon_portfoy_dagilimi
info = fon_anlik_bilgi("IPB")
print(info["sonFiyat"], "·", info["fonUnvan"])
# 0.846063 · İSTANBUL PORTFÖY BİRİNCİ DEĞİŞKEN FON
Neden bu paket?
TEFAS sitesi 2026 Nisan'da baştan aşağı yeniden yazıldı. Site Next.js'e taşındı, eski /api/DB/BindHistoryInfo endpoint'i kalıcı olarak kapatıldı, önüne Akamai TSPD bot koruması kondu. Bunun pratik sonucu: yıllardır kullanılan tefas-crawler paketi bir gece içinde çalışmaz hale geldi. Aynı şey, TEFAS sayfalarını requests veya BeautifulSoup ile kazıyan tüm scriptler için geçerli.
Yeni site aslında temiz bir JSON API sunuyor — sayfanın kendisi React tarafında bu API'leri çağırıyor. Sorun bu API'lerin ham HTTP istemcileriyle çağrılamaması: Akamai, requests'in TLS fingerprint'ini hemen tanıyıp boş yanıt döndürüyor (200 OK ama body boş). Çözüm, isteklerin TLS handshake'ini gerçek bir Chrome'a benzetmek — bu da curl_cffi ile mümkün. tefasmak bu işin çoğunu kapatıp arkasında temiz Python fonksiyonları sunuyor.
Kapsadığı endpoint'ler genel: tek fon için günlük fiyat geçmişi (5 yıla kadar), anlık bilgi, portföy kategori dağılımı; tüm fonlar için bulk günlük detay, dönemsel getiriler, portföy büyüklüğü, yönetim ücretleri; ve istatistikler (işlem hacmi, üye stok bakiyeleri). 60'tan fazla portföy kategorisi (hisse, repo, mevduat, kıymetli madenler, eurobond, kira sertifikası, BYF/GYF/GSYF varyasyonları) insan-okur etiketlere normalize edilir.
Hızlı tur
Tek bir fonun anlık durumunu çek
from tefasmak import fon_anlik_bilgi
info = fon_anlik_bilgi("IPB")
print(f"{info['fonKodu']} · {info['sonFiyat']} TL · günlük {info['gunlukGetiri']}%")
print(f"Kategori: {info['fonKategori']}, sıralama {info['kategoriDerece']}/{info['kategoriFonSay']}")
print(f"Büyüklük: {info['portBuyukluk']:,.0f} TL · {info['yatirimciSayi']:,} yatırımcı")
5 yıllık geçmiş — getiri grafiği için
from tefasmak import fon_5y_fiyat
seri = fon_5y_fiyat("IPB") # ~1250 günlük {tarih, fiyat} listesi
ilk, son = seri[0], seri[-1]
toplam_getiri = (son["fiyat"] / ilk["fiyat"] - 1) * 100
print(f"{ilk['tarih']} → {son['tarih']}: %{toplam_getiri:.1f}")
Portföy dağılımı — kısa kodlardan insan-okur etiketlere
TEFAS API'si dağılımı hs, tr, vint, yyf, khau gibi kısa kodlarla döndürür. portfoy_dagilimi_normalize bunları "Hisse Senedi", "Ters Repo", "Altın Katılma Hesabı" gibi etiketlere çevirir ve sıfır olanları eler.
from tefasmak import fon_portfoy_dagilimi, portfoy_dagilimi_normalize
ham = fon_portfoy_dagilimi("IPB")
print(portfoy_dagilimi_normalize(ham))
# {'Hisse Senedi': 34.46,
# 'Ters Repo': 38.3,
# 'Yatırım Fonları Katılma Payları': 16.01,
# 'Vadeli İşlemler Nakit Teminatları': 2.77,
# 'Finansman Bonosu': 3.67,
# 'Girişim Sermayesi YF Katılma Belgesi': 4.19,
# 'Gayrimenkul Yatırım Fonu Katılma Belgesi': 0.56,
# 'TL Vadeli Mevduat': 0.04}
Tüm fonların güncel fiyatı — tek seferde
from tefasmak import fonlar_son_fiyat_bulk
bulk = fonlar_son_fiyat_bulk("YAT") # yaklaşık 2000 fon, 2 sayfa
print(f"{len(bulk)} fon")
print(bulk["IPB"]) # {'fonKodu': 'IPB', 'fiyat': 0.846063, ...}
Tüm fonların dönemsel getirisi — tek istekte
from tefasmak import fonlar_donemsel_getiri
rows = fonlar_donemsel_getiri()
# her satırda 1 ay, 3 ay, 6 ay, yıl başı, 1 yıl, 3 yıl, 5 yıl getirileri
en_iyi_1y = sorted(rows, key=lambda r: r.get("getiri1y") or 0, reverse=True)[:5]
for r in en_iyi_1y:
print(f"{r['fonKodu']:6} · {r['fonUnvan'][:60]:<60} · %{r['getiri1y']}")
Uzun tarih aralığı — chunked + paginated + dedupe
TEFAS tek istekte yaklaşık 1 ayla sınırlı bir aralık verir. _aralik ile biten fonksiyonlar bunu otomatik 28-gün pencerelere böler, her pencerede sayfalama yapar ve (fonKodu, tarih) çiftlerini dedupe eder. Çağrılar arasında rate-limit (TEFAS dakikada 6 istek) otomatik uygulanır.
from tefasmak import fonlar_gunluk_detay_aralik
# 4 aylık çekim — yaklaşık 5 chunk, her birinde 2 sayfa
satirlar = fonlar_gunluk_detay_aralik(
fon_tipi="YAT",
bas_tarih="20260101",
bit_tarih="20260430",
)
print(f"{len(satirlar)} satır")
Endpoint kapsamı
Tek fon
fon_fiyat_gecmisi(kod, periyod)— günlük fiyat (hafta / 1ay / 3ay / 6ay / 1yıl / 3yıl / 5yıl)fon_5y_fiyat(kod)— kısayol, 5 yıllık tam geçmişfon_son_iki_fiyat(kod)— son iki iş günü ve günlük getirifon_anlik_bilgi(kod)— sonFiyat, gunlukGetiri, portBuyukluk, payAdet, kategoriDerece, yatirimciSayifon_profil_detay(kod, periyod)— kategori derece + tür ortalama getirisifon_portfoy_dagilimi(kod, tarih=None)— portföy kategorileri (kısa kodlar)fon_son_fiyat_ve_getiri(kod)— fiyat + günlük getiri + tarih üçlüsü
Bulk / aralık
fonlar_gunluk_detay(...)— sayfalı, tek tarih veya kısa aralıkfonlar_gunluk_detay_hepsi(...)— otomatik sayfalamafonlar_gunluk_detay_aralik(...)— chunked uzun aralık + dedupefonlar_portfoy_dagilimi(...)vefonlar_portfoy_dagilimi_aralik(...)fonlar_donemsel_getiri(...)— TÜM fonlar 1a/3a/6a/yb/1y/3y/5y, tek istekfonlar_buyukluk(...)— portföy büyüklüğü ve pay adedi değişimifonlar_yonetim_ucretleri(...)— yönetim ücreti, gider kesintisifonlar_son_fiyat_bulk(...)—{fonKodu: satır}sözlüğü
Liste / arama
tum_fonlar(fon_tipi)— kod, ünvan, kurucu sözlüğüfon_unvan_ara(arama)fon_grup_listesi(),fon_tur_listesi(),doviz_listesi()
İstatistik
islem_hacmi(...),uye_stok_bakiye(...)fon_bazli_islem_hacmi(),uye_bazli_islem_hacmi()hafta_listesi()
Diğer
duyurular()fund_returns_export(listing_type, fon_tipi)— TEFAS Excel export'unun JSON karşılığı
Fon tipleri
| Kod | |
|---|---|
YAT |
Yatırım Fonları (varsayılan) |
EMK |
Emeklilik Fonları |
BYF |
Borsa Yatırım Fonu (ETF) |
GYF |
Gayrimenkul Yatırım Fonu |
GSYF |
Girişim Sermayesi Yatırım Fonu |
Kaputun altında
tefasmak her POST öncesi paylaşılan bir curl_cffi.Session kullanır. Session ilk açıldığında Chrome 131 olarak https://www.tefas.gov.tr/tr/ adresine bir GET atar — TSPD challenge cookie'leri o anda alınır. Bundan sonra API çağrıları doğrudan POST ile yapılabilir, ilk denemede temiz JSON döner. Önceki nesil requests tabanlı çözümlerin gereksindiği "ısıtma turu + 5 retry + boş-yanıt loop'u" ortadan kalkar.
Diğer kararlar:
- Rate-limit. TEFAS dakikada yaklaşık 6 istek sınırı uyguluyor; aşılırsa boş 200 dönüyor (bazen 429).
_post, ardışık çağrılar arasında 8 saniye bekler ve 429 yakalarsa exponential backoff ile 5 kez tekrar dener (Retry-After header'ı varsa onu kullanır). - Session TTL. 10 dakika sonra session yeniden açılır, böylece Akamai tarafından expire edilmiş çerezlerle takılı kalmazsın.
- Chunking. TEFAS tek POST'ta yaklaşık 1 aylık aralık verir; daha uzun aralıklar sessizce kırpılır.
_aralikfonksiyonları aralığı 28 günlük pencerelere böler, sayfalama ve dedupe işini halleder. - Sayfa boyutu. Bulk endpoint'lerin varsayılanı 1000 — yaklaşık 2000 yatırım fonu için iki sayfa yetiyor. Daha küçük sayfa istersen parametre olarak verebilirsin.
- Fallback.
curl_cffiyüklenemediği ortamlarda (örneğin bazı Linux containerları)requestsüzerine geçilir.pip install "tefasmak[requests]"ile bu fallback bağımlılığını çekebilirsin; kod zaten ImportError'a karşı korunaklı.
Hata yönetimi
from tefasmak import (
fon_anlik_bilgi,
TefasAPIError,
TefasRateLimitError,
TefasInvalidParameterError,
)
try:
info = fon_anlik_bilgi("IPB")
except TefasRateLimitError:
# 429 — exponential backoff'un sonunda fırlatılır
...
except TefasInvalidParameterError:
# geçersiz tarih formatı, geçersiz aralık, vs.
...
except TefasAPIError:
# genel TEFAS hatası (boş yanıt loop'u dahil)
...
TefasInvalidParameterError aynı zamanda ValueError alt sınıfıdır — eski kodun except ValueError blokları aynen çalışmaya devam eder.
Bilinmesi gerekenler
- TEFAS API public; kimlik bilgisi gerektirmez. Yine de aşırı yüklenmemek için rate-limit otomatik uygulanır — yine de uzun çekimler için ilave throttling ekleyebilirsin.
- Bu paket bağımsız bir projedir. TEFAS, MKK veya başka bir kurumun resmi bir ürünü değildir. Veri kaynağı: https://www.tefas.gov.tr
- Endpoint'ler TEFAS tarafından değiştirilirse paket güncellenmek zorunda kalır. Issue açmaktan çekinmeyin.
- AAK gibi artık TEFAS'ta işlem görmeyen fonlar için bazı endpoint'ler boş
resultListdöndürür — kodun "yok" durumu ile "hata" durumu arasındaki ayrımı yakalayabilmesi için bu davranışa dikkat edin.
Lisans
MIT — bkz. LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tefasmak-1.0.1.tar.gz.
File metadata
- Download URL: tefasmak-1.0.1.tar.gz
- Upload date:
- Size: 15.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8584a7d97e400adcda742b286a92cc62604d217b636f4b94e21b96f9a1cf36eb
|
|
| MD5 |
52b1e13bd3e3ebbed9875a0db4b61c83
|
|
| BLAKE2b-256 |
ca60507693816aa5c63b357906cae0915cc2841aaccceaa780c72ff016dba29c
|
File details
Details for the file tefasmak-1.0.1-py3-none-any.whl.
File metadata
- Download URL: tefasmak-1.0.1-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ba349c6f0a3da090ab3115b26ab3666572c6827ea573400f99ffa5082d608a2
|
|
| MD5 |
3c403ebc56d1775ee4a59a44df42cda2
|
|
| BLAKE2b-256 |
e817d0b79e097a0f21172d486a6f0aac1624877e4237d05e74149057b0c06626
|