Блог им. vtvladim

Выгрузка исторических данных

  Сегодня обсуждалась тема о том, что использование ряда зарубежных сайтов  для скачивания исторических данных стало недоступно. Добрый человек подсказал решение проблемы на питоне с использованием yfinance. При помощи DeepSeak создал программу для выгрузки данных. Возможно кому-то еще будет полезно.
   Для использования программы надо создать в текущей папке с кодом две папки: InData и OutData. В первой папке создайте текстовый файл со списком тикеров (активов), разделенных точкой с запятой (;) с расширением txt. Во второй папке будет сохранен файл «текущая дата.txt» с данными разделителем точка с запятой. Данные по всем заданным тикерам записываются в один файл последовательно. Формат вывода:
                              Тикер / Data  Open  High  Low  Close Volume /  данные по дням за период
   После запуска — выбрать период дат, выбрать файл с исходным списком активов, запустить скачивание данных.
     Сам код следующий:

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()



587 | ★1

Читайте на SMART-LAB:
Фото
NZD/CHF: Медведи возвращаются к ударным трудам?
Кросс-курс NZD/CHF протестировал ключевую область сопротивления, сформированную между уровнями 0.4622 и 0.4663, достигнув даже ее верхней границы....
Какие инвестиционные стратегии оказались самыми прибыльными в 2025 году
В 2025 году снижение ключевой ставки и геополитическая неопределённость создали волатильность и почти вернули рынок акций к прошлогодним...
Фото
Итоги первичных размещений ВДО и некоторых розничных выпусков на 11 декабря 2025 г.
Следите за нашими новостями в удобном формате:  Telegram ,  Youtube ,  Смартлаб ,  Вконтакте ,  Сайт

теги блога Владимиров Владимир

....все тэги



UPDONW
Новый дизайн