Finansal analiz ve algoritmik işlem geliştirmek isteyen herkesin ilk adımı, güvenilir hisse senedi kapanış verilerini elde etmektir. Bu veriler, teknik analizden sinyal üretimine kadar pek çok işlemin temelini oluşturur. Elinizdeki veriler ne kadar doğru ve güncelse, analizleriniz de o kadar isabetli olur.
Python ve yfinance kütüphanesi kullanılarak oluşturulmuş, Borsa İstanbul (BIST) hisselerine ait kapanış verilerini otomatik olarak indiren gelişmiş bir scripti detaylıca ele alacağız. Script, .xlsx formatında çıktılar üreterek analizlerinize doğrudan entegre edilebilir veriler sunar.
hisselistesi_txt.txt adlı dosyadan hisse senedi sembollerini okumak
Yahoo Finance üzerinden kapanış verilerini çekmek (yfinance)
Verileri işleyip Excel’e kaydetmek (pandas ve openpyxl)
Başarısız işlemleri tespit edip yeniden denemek
Kullanıcıya görsel ve metinsel özet rapor sunmak
Otomatik Hisse Formatlama
Yahoo Finance üzerinde işlem gören BIST hisseleri .IS uzantısına sahiptir.
Örneğin THYAO → THYAO.IS formatına otomatik olarak dönüştürülür.
Yeniden Deneme Mekanizması
Veri çekimi sırasında yaşanan geçici sorunlar için belirli aralıklarla otomatik yeniden deneme yapılır (max_retries, retry_delay).
Excel Kaydı ve Türkçe Sütunlar
Çekilen veriler şu sütunlar ile .xlsx dosyasına kaydedilir:
Tarih Açılış Yüksek Düşük Kapanış Hacim
Eksik Veri ve NaN Temizliği
İndirilen verilerdeki eksik veya bozuk kayıtlar otomatik olarak temizlenir. Bu sayede daha sağlıklı analizler yapılabilir.
Kullanıcı Dostu Konsol Çıktıları
colorama kütüphanesi sayesinde kullanıcıya renkli ve bilgilendirici çıktılar sunulur (örn. yeşil = başarı, kırmızı = hata).
Klasör Yapısı ve Çıktı
Kaydedilen dosyalar StokData/Kapanis/ klasörü altında saklanır. Her hisse senedi için ayrı bir Excel dosyası oluşturulur:
StokData/Kapanis/THYAO.xlsx gibi.
Kullanım Adımları
hisselistesi_txt.txt dosyasına BIST hisse sembollerini yazın (her satıra bir hisse, örn. AKBNK).
Temeli sağlam şirketleri listeleyebilirsiniz. Ya da belirli sektör yada endeks şirketlerin sembollerini de yazabilirsiniz. (XU100, XU030)
Scripti çalıştırdığınızda
Kapanış verileri indirilecek, işlenecek ve .xlsx olarak kaydedilecektir. Başarısız olan hisseler için sistem size yeniden deneme opsiyonu sunacaktır. Süreç sonunda konsolda özet rapor gösterilecektir.
Örnek Konsol Çıktısı
Veri çekiliyor: AKBNK (Deneme 1/3)…
✅ AKBNK verisi başarıyla kaydedildi.
Veri çekiliyor: THYAO (Deneme 1/3)…
❌ THYAO için hata (Deneme 1): Connection timed out.
⏳ 2 saniye bekleniyor…
…
===== ÖZET RAPOR =====
✅ Başarılı: 18
❌ Başarısız: 2
Başarı oranı: 90.0%
Başarısız hisseler: THYAO, TAVHL
Sonraki Adım
X_01_BorsaPin_StokData.py olarak kayıt edebilirsiniz.
Pyhon Kodumuz
import yfinance as yf import os import pandas as pd from datetime import datetime, timedelta from colorama import Fore, init import time from typing import List, Optional """ Borsapin StokData Yahoo Finans Üzerinden Kapanış Datalarını çekmeye yarar www.kursatsenturk.com """ init(autoreset=True) class StockDownloader: def __init__(self, max_retries: int = 3, retry_delay: int = 2): """ Hisse senedi veri indirici sınıfı Args: max_retries: Maksimum yeniden deneme sayısı retry_delay: Denemeler arası bekleme süresi (saniye) """ self.max_retries = max_retries self.retry_delay = retry_delay self.failed_tickers: List[str] = [] self.successful_tickers: List[str] = [] @staticmethod def read_tickers(file_path: str) -> List[str]: """Hisse kodlarını dosyadan okuma fonksiyonu""" try: with open(file_path, 'r', encoding='utf-8') as f: tickers = [line.strip() for line in f.readlines() if line.strip()] return tickers except FileNotFoundError: print(f"{Fore.RED}❌ {file_path} dosyası bulunamadı!") return [] except Exception as e: print(f"{Fore.RED}❌ Dosya okuma hatası: {e}") return [] @staticmethod def format_ticker(ticker: str) -> str: """Hisse sembolüne .IS eklemek""" if not ticker.endswith('.IS'): ticker = ticker + '.IS' return ticker @staticmethod def save_to_excel(data: pd.DataFrame, file_path: str) -> bool: """Veriyi Excel'e kaydetme fonksiyonu""" try: data.to_excel(file_path, index=False) return True except Exception as e: print(f"{Fore.RED}❌ Excel kaydetme hatası: {e}") return False def download_single_ticker(self, ticker: str, start_date: str, end_date: str, attempt: int = 1) -> bool: """Tek hisse için veri çekme fonksiyonu""" formatted_ticker = self.format_ticker(ticker) ticker_name = formatted_ticker.replace(".IS", "") print(f"{Fore.YELLOW} Veri çekiliyor: {ticker_name} (Deneme {attempt}/{self.max_retries})...") try: # Veri çekme stock_data = yf.download( formatted_ticker, start=start_date, end=end_date, progress=False, timeout=30, auto_adjust=True, # Uyarıyı önlemek için explicit olarak True prepost=True, threads=True ) if stock_data is None or stock_data.empty: raise ValueError("Veri boş veya None") # MultiIndex sütunlarını düzelt if isinstance(stock_data.columns, pd.MultiIndex): # MultiIndex'i tek seviyeye indir stock_data.columns = stock_data.columns.droplevel(1) # Sütun isimlerini temizle stock_data.columns = [str(col).strip() for col in stock_data.columns] # Veri işleme - sadece gerekli sütunları al required_columns = ['Open', 'High', 'Low', 'Close', 'Volume'] available_columns = [col for col in required_columns if col in stock_data.columns] if not available_columns: raise ValueError("Gerekli sütunlar bulunamadı") stock_data = stock_data[available_columns] # Sayıları düzgün formatta işleme for column in stock_data.columns: if stock_data[column].dtype == 'object': try: stock_data[column] = pd.to_numeric( stock_data[column].astype(str).str.replace(',', '.'), errors='coerce' ) except Exception: continue # NaN değerleri temizle stock_data = stock_data.dropna() # Boş veri kontrolü if stock_data.empty: raise ValueError("İşlenen veri boş") # Dosya kaydetme folder_path = "StokData/Kapanis/" os.makedirs(folder_path, exist_ok=True) file_path = os.path.join(folder_path, f"{ticker_name}.xlsx") # Tarih formatı düzenleme stock_data_copy = stock_data.copy() # Index'i reset et ve tarih sütununu ekle stock_data_copy.reset_index(inplace=True) # Tarih sütunu varsa formatla if 'Date' in stock_data_copy.columns: stock_data_copy['Date'] = pd.to_datetime(stock_data_copy['Date']).dt.date stock_data_copy.rename(columns={"Date": "Tarih"}, inplace=True) # Sütun isimlerini Türkçeye çevirme column_mapping = { 'Open': 'Açılış', 'High': 'Yüksek', 'Low': 'Düşük', 'Close': 'Kapanış', 'Volume': 'Hacim' } # Mevcut sütunları yeniden adlandır for eng_name, tr_name in column_mapping.items(): if eng_name in stock_data_copy.columns: stock_data_copy.rename(columns={eng_name: tr_name}, inplace=True) # Kaydetme if self.save_to_excel(stock_data_copy, file_path): print(f"{Fore.GREEN}✅ {ticker_name} verisi başarıyla kaydedildi.") return True else: raise Exception("Excel kaydetme başarısız") except Exception as e: print(f"{Fore.RED}❌ {ticker_name} için hata (Deneme {attempt}): {str(e)}") return False def download_with_retry(self, ticker: str, start_date: str, end_date: str) -> bool: """Yeniden deneme mekanizması ile veri çekme""" for attempt in range(1, self.max_retries + 1): if self.download_single_ticker(ticker, start_date, end_date, attempt): self.successful_tickers.append(ticker) return True if attempt < self.max_retries: print(f"{Fore.YELLOW}⏳ {self.retry_delay} saniye bekleniyor...") time.sleep(self.retry_delay) # Tüm denemeler başarısız self.failed_tickers.append(ticker) print(f"{Fore.RED} {ticker} için tüm denemeler başarısız!") return False def retry_failed_tickers(self, start_date: str, end_date: str) -> None: """Başarısız hisseleri tekrar deneme""" if not self.failed_tickers: print(f"{Fore.GREEN} Yeniden denenecek hisse yok!") return print(f"\n{Fore.CYAN} Başarısız {len(self.failed_tickers)} hisse tekrar deneniyor...") print(f"{Fore.CYAN}Başarısız hisseler: {', '.join(self.failed_tickers)}") retry_failed = [] retry_successful = [] # Başarısız hisselerin kopyasını al failed_copy = self.failed_tickers.copy() for ticker in failed_copy: print(f"\n{Fore.MAGENTA} Tekrar deneniyor: {ticker}") if self.download_with_retry(ticker, start_date, end_date): retry_successful.append(ticker) self.failed_tickers.remove(ticker) else: retry_failed.append(ticker) # Sonuçları yazdır if retry_successful: print(f"\n{Fore.GREEN}✅ Tekrar denemede başarılı: {', '.join(retry_successful)}") if retry_failed: print(f"\n{Fore.RED}❌ Hala başarısız: {', '.join(retry_failed)}") def save_failed_list(self, filename: str = "basarisiz_hisseler.txt") -> None: """Başarısız hisseleri dosyaya kaydet""" if self.failed_tickers: try: with open(filename, 'w', encoding='utf-8') as f: f.write('\n'.join(self.failed_tickers)) print(f"{Fore.YELLOW} Başarısız hisseler {filename} dosyasına kaydedildi.") except Exception as e: print(f"{Fore.RED}❌ Başarısız hisse listesi kaydetme hatası: {e}") def print_summary(self) -> None: """Özet rapor yazdır""" total = len(self.successful_tickers) + len(self.failed_tickers) success_rate = (len(self.successful_tickers) / total * 100) if total > 0 else 0 print(f"\n{Fore.CYAN} ===== ÖZET RAPOR =====") print(f"{Fore.GREEN}✅ Başarılı: {len(self.successful_tickers)}") print(f"{Fore.RED}❌ Başarısız: {len(self.failed_tickers)}") print(f"{Fore.BLUE} Başarı oranı: {success_rate:.1f}%") if self.failed_tickers: print(f"{Fore.RED} Başarısız hisseler: {', '.join(self.failed_tickers)}") def main(self) -> None: """Ana fonksiyon""" print(f"{Fore.CYAN} Veri çekme başlıyor...") # Parametreler tickers = self.read_tickers("hisselistesi_txt.txt") if not tickers: print(f"{Fore.RED}❌ Hisse listesi okunamadı, işlem sonlandırılıyor.") return start_date = '2020-01-01' end_date = (datetime.today() + timedelta(days=1)).strftime('%Y-%m-%d') print(f"{Fore.BLUE} Tarih aralığı: {start_date} - {end_date}") print(f"{Fore.BLUE} Toplam hisse sayısı: {len(tickers)}") print(f"{Fore.BLUE} Maksimum deneme sayısı: {self.max_retries}") print(f"{Fore.BLUE}⏱️ Deneme arası bekleme: {self.retry_delay} saniye\n") # İlk deneme for i, ticker in enumerate(tickers, 1): print(f"\n{Fore.BLUE}[{i}/{len(tickers)}] İşleniyor...") self.download_with_retry(ticker, start_date, end_date) # Başarısız hisseleri tekrar deneme if self.failed_tickers: user_input = input( f"\n{Fore.YELLOW}❓ Başarısız {len(self.failed_tickers)} hisseyi tekrar denemek istiyor musunuz? (e/h): " ).lower().strip() if user_input in ['e', 'evet', 'y', 'yes']: self.retry_failed_tickers(start_date, end_date) # Sonuçları kaydet ve yazdır self.save_failed_list() self.print_summary() print(f"\n{Fore.GREEN} İşlem tamamlandı!") # Kullanım if __name__ == "__main__": # Özelleştirilebilir parametreler downloader = StockDownloader( max_retries=3, # Maksimum deneme sayısı retry_delay=2 # Denemeler arası bekleme süresi (saniye) ) downloader.main()
Bu script, ileri seviye analizlerin temelini oluşturur. Bir sonraki yazımızda, bu verileri kullanarak:
5 8 13 21 34 55 89 144 233 370 EMA seviyelerini hesaplayan EMAs script yayınlayacağım.
Ve yatırım kararları için Python tabanlı teknik analiz sistemleri geliştirmeye devam edeceğiz.
Finansal analiz projelerinde Python, sunduğu zengin kütüphane ekosistemi ile güçlü bir araçtır. Borsa İstanbul (BIST) hisselerine ait kapanış verilerini çekmek ve bu veriler üzerinden teknik sinyaller üretmek için öncelikle bazı temel Python kütüphanelerine ihtiyaç duyarız.
Bu yazıda, gerekli kütüphanelerin sisteminizde yüklü olup olmadığını kontrol eden ve eksik olanları otomatik olarak kuran bir Python scriptini ele alacağız. Bu adım, ileri aşamalarda Borsa İstanbul Kapanış ve Hacim verilerini çekme ve analiz etme işlemleri için altyapı hazırlığı niteliğindedir.
Aşağıdaki kütüphaneler, veri çekme ve analiz süreçlerinde kullanılacaktır:
pandas: Veri manipülasyonu ve analiz için temel kütüphane.
numpy: Sayısal hesaplamalar için kullanılır.
colorama: Konsolda renkli yazı yazmak için kullanılır (bilgilendirici çıktılar için).
yfinance: Yahoo Finance üzerinden hisse senedi verilerini çekmeye yarar.
openpyxl: Excel dosyaları oluşturmak ve düzenlemek için kullanılır.
Kod özetle şunları yapar:
1. Belirlenen `required_packages` listesinde yer alan kütüphanelerin sistemde kurulu olup olmadığını kontrol eder.
2. Eğer bir kütüphane yüklü değilse, `pip install` komutu ile yükler.
3. Her bir paket için yükleme durumu kullanıcıya yazdırılır.
GerekliKütüphaneler.py diye kayıt edebilirsiniz.
Python Kodu
import subprocess import sys # Gerekli kütüphaneler listesi required_packages = [ "pandas", "numpy", "colorama", "yfinance", "openpyxl" ] def install_missing_packages(): for package in required_packages: try: __import__(package) print(f"{package} zaten yüklü.") except ImportError: print(f"{package} eksik, yükleniyor...") subprocess.check_call([sys.executable, "-m", "pip", "install", package]) if __name__ == "__main__": install_missing_packages()
Sonraki Adımlar
Eğer farklı bir kütüphaneye ihtiyaç duyduğumuzda bu betiğe ekleme yapacağız.
Şimdi bu temel kurulumu yaptıktan sonra, aşağıdaki adımlarla devam edeceğiz:
Borsa İstanbul Hisse Verilerinin Çekilmesi
yfinance kütüphanesini kullanarak BIST hisselerine ait günlük kapanış verilerini çekeceğiz. (2 Ocak 2020 tarihinden itibaren)
Verilerin Excel’e Aktarılması
pandas ve openpyxl kütüphaneleri sayesinde çekilen veriler .xlsx formatında saklanacak.
Teknik Göstergeler ve Sinyallerin Hesaplanması
EMA, EMA ALIGNMENT (İdeal Ema, Ema Sıralama), WaveTrend, Günlük Haftalık Aylık Yıllık Pivot, Lineer Regresyon kanalları gibi göstergeleri hesaplayıp, yatırım kararlarında kullanılabilecek potansiyel al/sat sinyallerinide analiz edeceğiz.
Sonuç olarak bu script, Python tabanlı finansal veri analizlerine başlamadan önce gerekli kütüphaneleri yükleyerek ortam hazırlığını otomatikleştirir. Böylece kullanıcılar doğrudan veri çekme ve analiz etme adımlarına geçebilirler.
Son Yorumlar