Блог им. vtvladim
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import yfinance as yf
import pandas as pd
import numpy as np
import os
from datetime import datetime
class YFinanceDownloader:
def __init__(self, root):
self.root = root
self.root.title(«YFinance Data Downloader»)
self.root.geometry(«600x400»)
self.create_widgets()
def create_widgets(self):
# Заголовок
title_label = ttk.Label(self.root, text=«Выгрузка данных торгов», font=(«Arial», 14, «bold»))
title_label.pack(pady=10)
# Фрейм для ввода дат
date_frame = ttk.Frame(self.root)
date_frame.pack(pady=10, padx=20, fill=«x»)
ttk.Label(date_frame, text=«Период дат (ДД.ММ.ГГГГ — ДД.ММ.ГГГГ):»).pack(anchor=«w»)
self.date_entry = ttk.Entry(date_frame, width=30)
self.date_entry.pack(pady=5, fill=«x»)
self.date_entry.insert(0, «01.10.2025 — 31.10.2025»)
# Фрейм для выбора файла
file_frame = ttk.Frame(self.root)
file_frame.pack(pady=10, padx=20, fill=«x»)
ttk.Label(file_frame, text=«Файл с тикерами:»).pack(anchor=«w»)
file_select_frame = ttk.Frame(file_frame)
file_select_frame.pack(pady=5, fill=«x»)
self.file_path = tk.StringVar()
self.file_entry = ttk.Entry(file_select_frame, textvariable=self.file_path, width=40)
self.file_entry.pack(side=«left», fill=«x», expand=True)
ttk.Button(file_select_frame, text=«Обзор», command=self.browse_file).pack(side=«left», padx=5)
# Кнопка выполнения
ttk.Button(self.root, text=«Выгрузить данные», command=self.download_data).pack(pady=20)
# Прогресс бар
self.progress = ttk.Progressbar(self.root, mode='indeterminate')
self.progress.pack(pady=10, padx=20, fill=«x»)
# Текстовое поле для логов
self.log_text = tk.Text(self.root, height=10, width=70)
self.log_text.pack(pady=10, padx=20, fill=«both», expand=True)
# Добавляем скроллбар для текстового поля
scrollbar = ttk.Scrollbar(self.log_text)
scrollbar.pack(side=«right», fill=«y»)
self.log_text.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=self.log_text.yview)
def browse_file(self):
filename = filedialog.askopenfilename(
initialdir=«InData»,
title=«Выберите файл с тикерами»,
filetypes=((«Text files», "*.txt"), («All files», "*.*"))
)
if filename:
self.file_path.set(filename)
def log_message(self, message):
self.log_text.insert(«end», f"{datetime.now().strftime('%H:%M:%S')} — {message}\n")
self.log_text.see(«end»)
self.root.update()
def parse_dates(self, date_range):
""«Парсинг дат из формата ДД.ММ.ГГГГ»""
try:
start_str, end_str = date_range.split("-")
start_date = datetime.strptime(start_str.strip(), "%d.%m.%Y").strftime("%Y-%m-%d")
end_date = datetime.strptime(end_str.strip(), "%d.%m.%Y").strftime("%Y-%m-%d")
return start_date, end_date
except ValueError as e:
raise ValueError(«Неверный формат даты. Используйте: ДД.ММ.ГГГГ — ДД.ММ.ГГГГ»)
def read_tickers(self, filepath):
""«Чтение тикеров из файла»""
try:
with open(filepath, 'r', encoding='utf-8') as file:
content = file.read().strip()
tickers = [ticker.strip() for ticker in content.split(';') if ticker.strip()]
return tickers
except Exception as e:
raise Exception(f«Ошибка чтения файла: {e}»)
def download_data(self):
try:
self.progress.start()
self.log_text.delete(1.0, «end»)
# Проверка введенных данных
if not self.file_path.get():
messagebox.showerror(«Ошибка», «Выберите файл с тикерами»)
return
if not self.date_entry.get():
messagebox.showerror(«Ошибка», «Введите период дат»)
return
# Парсинг дат
self.log_message(«Парсинг дат...»)
start_date, end_date = self.parse_dates(self.date_entry.get())
self.log_message(f«Период: {start_date} — {end_date}»)
# Чтение тикеров
self.log_message(«Чтение тикеров из файла...»)
tickers = self.read_tickers(self.file_path.get())
self.log_message(f«Найдено тикеров: {len(tickers)}»)
if not tickers:
messagebox.showerror(«Ошибка», «Файл не содержит тикеров»)
return
# Создание папки OutData если её нет
if not os.path.exists(«OutData»):
os.makedirs(«OutData»)
self.log_message(«Создана папка OutData»)
# Создание имени файла с текущей датой
current_date = datetime.now().strftime("%d-%m-%Y")
output_filename = f«OutData/{current_date}.txt»
# Открываем файл для записи
with open(output_filename, 'w', encoding='utf-8') as f:
total_tickers_saved = 0
for ticker in tickers:
try:
self.log_message(f«Обработка тикера {ticker}...»)
# Загружаем данные для текущего тикера
data = yf.download(ticker, start=start_date, end=end_date, progress=False)
if data.empty:
self.log_message(f«Предупреждение: нет данных для {ticker}»)
continue
self.log_message(f«Загружено {len(data)} строк для {ticker}»)
# Записываем заголовок тикера
f.write(f«Тикер {ticker}\n»)
# Записываем названия колонок
f.write(«Date;Open;High;Low;Close;Volume\n»)
# Подготовка и запись данных
rows_written = 0
for index, row in data.iterrows():
try:
# Преобразуем дату в формат ДД.ММ.ГГГГ
date_str = index.strftime('%d.%m.%Y')
# Получаем значения как числа
open_price = float(row['Open'])
high_price = float(row['High'])
low_price = float(row['Low'])
close_price = float(row['Close'])
volume = int(row['Volume'])
# Форматируем строку данных
data_line = f"{date_str};{open_price:.2f};{high_price:.2f};{low_price:.2f};{close_price:.2f};{volume}\n"
f.write(data_line)
rows_written += 1
except Exception as row_error:
continue
# Добавляем пустую строку между тикерами (кроме последнего)
if ticker != tickers[-1]:
f.write("\n")
total_tickers_saved += 1
self.log_message(f«Записано {rows_written} строк для {ticker}»)
except Exception as e:
self.log_message(f«Ошибка при обработке {ticker}: {str(e)}»)
self.progress.stop()
# Проверяем содержимое файла
if os.path.exists(output_filename):
with open(output_filename, 'r', encoding='utf-8') as check_file:
content = check_file.read()
file_size = len(content)
self.log_message(f«Файл создан: {output_filename}»)
self.log_message(f«Размер файла: {file_size} байт»)
if file_size > 0:
messagebox.showinfo(«Успех», f«Данные успешно выгружены для {total_tickers_saved} из {len(tickers)} тикеров\nФайл: {output_filename}»)
else:
messagebox.showwarning(«Предупреждение», f«Файл создан, но пустой: {output_filename}»)
else:
messagebox.showerror(«Ошибка», f«Файл не был создан: {output_filename}»)
except Exception as e:
self.progress.stop()
self.log_message(f«Ошибка: {str(e)}»)
messagebox.showerror(«Ошибка», str(e))
def main():
# Создаем папки если их нет
if not os.path.exists(«InData»):
os.makedirs(«InData»)
print(«Создана папка InData — поместите туда файлы с тикерами»)
if not os.path.exists(«OutData»):
os.makedirs(«OutData»)
print(«Создана папка OutData — туда будут сохраняться результаты»)
root = tk.Tk()
app = YFinanceDownloader(root)
root.mainloop()
if __name__ == "__main__":
main()