Python yfinance: как получить финансовые данные Yahoo в своем коде
Пройдите тест, узнайте какой профессии подходите
Для кого эта статья:
- начинающие и опытные программисты, интересующиеся финансами
- финансовые аналитики и исследователи
- студенты и профессионалы, желающие освоить автоматизацию сбора финансовых данных
Финансовые данные — кровь цифровой экономики. Но как получить доступ к этому драгоценному ресурсу без подписок на дорогостоящие сервисы? Python-библиотека yfinance разрушает барьеры между разработчиками и сокровищницей финансовых данных Yahoo Finance. С несколькими строками кода вы получаете доступ к историческим котировкам, фундаментальным показателям и актуальным рыночным данным. Пришло время прекратить копировать таблицы вручную и автоматизировать сбор финансовой информации на профессиональном уровне. 🚀
Хотите освоить Python с нуля и научиться работать с финансовыми данными как профессионал? Курс «Python-разработчик» с нуля от Skypro даст вам не только фундаментальные знания языка, но и практические навыки работы с библиотеками для анализа данных, включая yfinance. Вы научитесь создавать собственные финансовые дашборды и системы анализа рынка, которые помогут принимать взвешенные инвестиционные решения. Инвестиция в знания — лучшая стратегия в мире финансов!
Возможности библиотеки Python yfinance для финансового анализа
Библиотека yfinance — это неофициальный, но самый популярный инструмент для доступа к данным Yahoo Finance через Python. После прекращения поддержки официального API от Yahoo в 2017 году, yfinance стал незаменимым решением для получения биржевой информации. В 2025 году библиотека предлагает расширенный функционал и продолжает активно поддерживаться сообществом разработчиков. 📊
Ключевые возможности yfinance:
- Загрузка исторических данных о ценах акций, облигаций, ETF и криптовалют
- Доступ к фундаментальным показателям компаний (P/E, EPS, рыночная капитализация)
- Получение финансовых отчетов: балансы, отчеты о прибылях и убытках
- Информация о дивидендах и корпоративных событиях
- Данные по опционам с различными сроками экспирации
- Возможность массовой загрузки данных по нескольким тикерам
- Интеграция с pandas для удобной обработки полученной информации
Библиотека решает критическую проблему доступа к актуальным биржевым данным с минимальными усилиями по внедрению. Ценность этого инструмента сложно переоценить, особенно учитывая, что аналогичные платные API могут стоить до нескольких тысяч долларов в год.
Функциональность | yfinance | Платные альтернативы |
---|---|---|
Исторические данные | ✅ (с ограничениями по частоте) | ✅ (с высоким разрешением) |
Фундаментальный анализ | ✅ | ✅ |
Реальные данные | ⚠️ (задержка 15-20 мин) | ✅ (в реальном времени) |
Стоимость | Бесплатно | $50-$2000/месяц |
Лимиты запросов | ⚠️ (есть ограничения) | ✅ (высокие лимиты) |
Поддержка | Сообщество | Профессиональная |
Несмотря на некоторые ограничения по сравнению с премиальными решениями, yfinance остается золотой серединой для большинства задач анализа рынка, алгоритмической торговли и образовательных целей. В 2025 году разработчики библиотеки внедрили механизмы кэширования и интеллектуальной ротации запросов, что позволило значительно снизить риск блокировки со стороны Yahoo.
Алексей Корнеев, ведущий аналитик-разработчик
Когда я начинал строить свою первую систему скрининга акций, бюджет был ограничен, а премиальные API казались недосягаемой роскошью. Знакомство с yfinance изменило правила игры. Вместо ручного сбора данных по 500 компаниям S&P500, я написал скрипт, который за 10 минут собирал всю необходимую информацию и заполнял мою базу данных. Особенно ценной оказалась возможность получать данные финансовой отчетности — я смог реализовать собственный алгоритм оценки недооцененных компаний. В итоге система не только сэкономила мне десятки часов работы, но и помогла обнаружить несколько перспективных акций, которые за год выросли более чем на 40%.

Установка и настройка yfinance в Python-окружении
Установка yfinance предельно проста — библиотека доступна через менеджер пакетов pip и совместима с большинством версий Python (3.7 и выше). Для начала работы достаточно выполнить одну команду в терминале: 💻
pip install yfinance
Если вы используете Anaconda, альтернативный вариант установки:
conda install -c conda-forge yfinance
Для обеспечения стабильной работы рекомендуется также установить дополнительные зависимости:
pip install pandas numpy matplotlib requests-cache
После установки библиотеки имеет смысл сразу настроить кэширование запросов, чтобы избежать потенциальных блокировок при частых обращениях к API Yahoo Finance:
import requests_cache
from datetime import timedelta
# Настройка кэширования запросов на 4 часа
session = requests_cache.CachedSession('yfinance.cache', expire_after=timedelta(hours=4))
session.headers['User-agent'] = 'my-program/1.0'
import yfinance as yf
yf.set_yfin_session(session)
Для продвинутых пользователей, работающих с большими объемами данных, рекомендуется также настроить параметры многопоточности для ускорения загрузки информации по множеству тикеров:
import yfinance as yf
import concurrent.futures
# Настройка многопоточности для массовой загрузки данных
def download_ticker(ticker):
return yf.Ticker(ticker).history(period="1y")
tickers = ["AAPL", "MSFT", "GOOG", "AMZN", "FB"]
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
data = {ticker: result for ticker, result in
zip(tickers, executor.map(download_ticker, tickers))}
При работе с yfinance полезно учитывать следующие практические аспекты настройки:
- Устанавливайте интервалы между запросами для предотвращения блокировки (минимум 0.5-1 секунда между запросами)
- Используйте прокси-ротацию при работе с большими объемами данных
- Применяйте экспоненциальный backoff при повторных попытках после ошибок соединения
- Настройте логирование для отслеживания проблем с получением данных
- Учитывайте часовые пояса при работе с временными рядами (yfinance возвращает данные в UTC)
Получение биржевых данных Yahoo через API yfinance
После настройки окружения можно приступать к получению финансовых данных. Библиотека yfinance предлагает два основных способа работы: через объект Ticker для детального анализа отдельных инструментов и через функцию download для массовой загрузки исторических данных. 📈
Базовый пример получения исторических данных по одному тикеру:
import yfinance as yf
# Создание объекта тикера для Apple
aapl = yf.Ticker("AAPL")
# Получение исторических данных за последний год
hist_data = aapl.history(period="1y")
# Вывод первых строк данных
print(hist_data.head())
Результатом будет pandas DataFrame с колонками Open, High, Low, Close, Volume и Dividends. Для получения данных можно использовать различные параметры периода и интервала:
Параметр | Описание | Примеры значений |
---|---|---|
period | Период для загрузки данных | "1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "ytd", "max" |
interval | Интервал между точками данных | "1m", "2m", "5m", "15m", "30m", "60m", "90m", "1h", "1d", "5d", "1wk", "1mo", "3mo" |
start | Дата начала периода | "2020-01-01" |
end | Дата окончания периода | "2023-12-31" |
actions | Включить корпоративные события | True, False |
auto_adjust | Автоматическая корректировка цен | True, False |
prepost | Включать данные до/после торговых сессий | True, False |
Для получения фундаментальных данных о компании можно использовать различные свойства объекта Ticker:
import yfinance as yf
import pprint
# Создание объекта тикера для Tesla
tsla = yf.Ticker("TSLA")
# Получение основной информации о компании
info = tsla.info
pprint.pprint({
"Name": info.get("shortName"),
"Sector": info.get("sector"),
"Industry": info.get("industry"),
"Market Cap": info.get("marketCap"),
"Forward P/E": info.get("forwardPE"),
"Dividend Yield": info.get("dividendYield"),
"Profit Margins": info.get("profitMargins")
})
# Получение аналитических рекомендаций
print(tsla.recommendations)
# Получение крупных акционеров
print(tsla.major_holders)
# Получение институциональных держателей
print(tsla.institutional_holders)
Массовая загрузка данных по нескольким тикерам одновременно может быть выполнена с помощью функции download:
import yfinance as yf
# Загрузка данных для нескольких тикеров сразу
data = yf.download(
tickers=["AAPL", "MSFT", "GOOG", "AMZN"],
period="1mo",
interval="1d",
group_by="ticker"
)
# Вывод структуры данных
print(data.head())
Получение данных по опционам для анализа волатильности и настроений рынка:
import yfinance as yf
# Создание объекта тикера для SPY (ETF на S&P 500)
spy = yf.Ticker("SPY")
# Получение доступных дат экспирации
expiration_dates = spy.options
# Вывод доступных дат
print(f"Доступные даты экспирации: {expiration_dates}")
# Получение данных по опционам для первой доступной даты
options_chain = spy.option_chain(expiration_dates[0])
# Вывод данных по колл-опционам
print(options_chain.calls.head())
При работе с API Yahoo Finance через yfinance важно понимать некоторые ограничения:
- Существует неофициальный лимит на количество запросов (около 2000 в час с одного IP-адреса)
- Некоторые данные могут иметь задержку до 15-20 минут относительно рыночных
- Не все типы данных одинаково надежно доступны для всех рынков (особенно вне США)
- При загрузке минутных данных глубина истории ограничена (обычно 7 днями)
- Возможны временные сбои в работе API, которые требуют обработки исключений
Анализ и визуализация финансовых данных с yfinance
Получение данных — лишь первый шаг. Настоящая ценность библиотеки yfinance раскрывается при анализе и визуализации финансовой информации. Благодаря совместимости с экосистемой pandas, numpy и matplotlib, полученные данные легко превращаются в аналитические инсайты. 📉
Начнем с базового технического анализа — расчета скользящих средних для выявления тренда:
import yfinance as yf
import matplotlib.pyplot as plt
import pandas as pd
# Получение данных по Bitcoin за последний год
btc = yf.Ticker("BTC-USD")
data = btc.history(period="1y")
# Расчет скользящих средних
data['MA50'] = data['Close'].rolling(window=50).mean()
data['MA200'] = data['Close'].rolling(window=200).mean()
# Визуализация данных
plt.figure(figsize=(14, 7))
plt.plot(data.index, data['Close'], label='BTC-USD')
plt.plot(data.index, data['MA50'], label='50-дневная СС')
plt.plot(data.index, data['MA200'], label='200-дневная СС')
plt.title('Анализ тренда Bitcoin')
plt.xlabel('Дата')
plt.ylabel('Цена (USD)')
plt.legend()
plt.grid(True)
plt.show()
# Определение сигналов покупки/продажи по пересечению MA
data['Signal'] = 0
data['Signal'] = np.where(data['MA50'] > data['MA200'], 1, 0)
data['Position'] = data['Signal'].diff()
# Подсчет сигналов
signals = data[data['Position'] != 0]
print(f"Найдено {len(signals)} сигналов торговли")
print(signals[['Close', 'MA50', 'MA200', 'Position']])
Для анализа волатильности и оценки риска можно рассчитать исторический показатель Value at Risk (VaR) и построить распределение доходности:
import yfinance as yf
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
# Получение данных по индексу S&P 500
sp500 = yf.Ticker("^GSPC")
data = sp500.history(period="5y")
# Расчет дневной доходности
data['Returns'] = data['Close'].pct_change()
# Удаление пропущенных значений
data = data.dropna()
# Построение гистограммы доходности
plt.figure(figsize=(10, 6))
sns.histplot(data['Returns'], kde=True, bins=50)
plt.title('Распределение дневной доходности S&P 500')
plt.xlabel('Дневная доходность')
plt.ylabel('Частота')
# Расчет Value at Risk (95%)
var_95 = data['Returns'].quantile(0.05)
plt.axvline(var_95, color='r', linestyle='dashed', linewidth=2)
plt.text(var_95, plt.ylim()[1]*0.9, f'VaR 95%: {var_95:.2%}', color='r')
# Проверка на нормальность распределения
k2, p = stats.normaltest(data['Returns'])
plt.text(plt.xlim()[1]*0.7, plt.ylim()[1]*0.8,
f'Тест на нормальность:\np-value: {p:.4f}',
bbox=dict(facecolor='white', alpha=0.5))
plt.grid(True)
plt.show()
# Расчет различных мер риска
print(f"Стандартное отклонение: {data['Returns'].std():.2%}")
print(f"Value at Risk (95%): {var_95:.2%}")
print(f"Expected Shortfall (95%): {data[data['Returns'] <= var_95]['Returns'].mean():.2%}")
Мария Соколова, финансовый аналитик-программист
Я занималась сравнительным анализом ETF для семейного фонда. Традиционно это была ручная работа с десятками таблиц Excel. Внедрение yfinance кардинально изменило процесс. Вместо недели рутинной работы, анализ стал занимать один день. Самым сложным оказалось сопоставление корреляций между различными классами активов в разные рыночные циклы. С помощью библиотеки я смогла загрузить 10-летнюю историю по 30 ETF и провести кластерный анализ, выявив скрытые взаимосвязи. Например, обнаружилось, что некоторые секторальные ETF, считавшиеся диверсифицирующими, на самом деле сильно коррелировали в периоды рыночной турбулентности. Этот анализ помог пересмотреть стратегию аллокации и увеличить устойчивость портфеля к просадкам.
Фундаментальный анализ также возможен с помощью yfinance. Например, можно автоматически создать скрининг акций по мультипликаторам:
import yfinance as yf
import pandas as pd
# Список тикеров для анализа (например, компоненты Dow Jones)
tickers = ['AAPL', 'MSFT', 'AMZN', 'TSLA', 'GOOG', 'BRK-B', 'UNH', 'JNJ',
'XOM', 'V', 'WMT', 'JPM', 'PG', 'MA', 'NVDA', 'HD', 'MRK', 'CVX']
# Функция для получения ключевых метрик компании
def get_company_metrics(ticker):
stock = yf.Ticker(ticker)
info = stock.info
return {
'Name': info.get('shortName', 'N/A'),
'Sector': info.get('sector', 'N/A'),
'Market Cap (B)': info.get('marketCap', 0) / 1e9,
'P/E': info.get('trailingPE', 0),
'Forward P/E': info.get('forwardPE', 0),
'PEG': info.get('pegRatio', 0),
'P/S': info.get('priceToSalesTrailing12Months', 0),
'P/B': info.get('priceToBook', 0),
'EV/EBITDA': info.get('enterpriseToEbitda', 0),
'Dividend Yield (%)': info.get('dividendYield', 0) * 100 if info.get('dividendYield') else 0,
'ROE (%)': info.get('returnOnEquity', 0) * 100 if info.get('returnOnEquity') else 0,
'Debt/Equity': info.get('debtToEquity', 0) / 100 if info.get('debtToEquity') else 0,
'Current Ratio': info.get('currentRatio', 0),
'Analysts Rating': info.get('recommendationMean', 0)
}
# Сбор данных по всем компаниям
metrics_list = []
for ticker in tickers:
try:
metrics = get_company_metrics(ticker)
metrics['Ticker'] = ticker
metrics_list.append(metrics)
except Exception as e:
print(f"Error with {ticker}: {e}")
# Создание DataFrame с результатами
df = pd.DataFrame(metrics_list)
# Сортировка по P/E
df_sorted = df.sort_values('P/E')
# Вывод результатов
print(df_sorted[['Ticker', 'Name', 'Sector', 'Market Cap (B)',
'P/E', 'Forward P/E', 'Dividend Yield (%)', 'ROE (%)']])
Для более сложного анализа можно построить карту тепла корреляций между различными активами:
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# Список активов для анализа корреляций
assets = {
'S&P 500': '^GSPC',
'Nasdaq': '^IXIC',
'Russell 2000': '^RUT',
'Золото': 'GC=F',
'Нефть': 'CL=F',
'US Treasuries': '^TNX',
'USD/EUR': 'EURUSD=X',
'Bitcoin': 'BTC-USD'
}
# Получение данных
data = pd.DataFrame()
for name, ticker in assets.items():
try:
asset_data = yf.download(ticker, period="1y")['Close']
data[name] = asset_data
except Exception as e:
print(f"Ошибка с {name}: {e}")
# Расчет дневных доходностей
returns = data.pct_change().dropna()
# Расчет корреляционной матрицы
corr_matrix = returns.corr()
# Визуализация корреляций
plt.figure(figsize=(12, 10))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f', linewidths=0.5)
plt.title('Корреляционная матрица доходностей различных активов')
plt.tight_layout()
plt.show()
# Вывод пар с наименьшей корреляцией (для диверсификации)
corr_pairs = []
for i in range(len(corr_matrix.columns)):
for j in range(i+1, len(corr_matrix.columns)):
asset1 = corr_matrix.columns[i]
asset2 = corr_matrix.columns[j]
correlation = corr_matrix.iloc[i, j]
corr_pairs.append((asset1, asset2, correlation))
# Сортировка по абсолютному значению корреляции
corr_pairs.sort(key=lambda x: abs(x[2]))
# Вывод наименее коррелированных пар
print("Наименее коррелированные пары активов:")
for asset1, asset2, corr in corr_pairs[:5]:
print(f"{asset1} — {asset2}: {corr:.3f}")
Если вы хотите определиться с направлением своего профессионального развития в сфере финансовых технологий, Тест на профориентацию от Skypro поможет оценить ваши склонности к аналитической работе с данными. Вы узнаете, подходит ли вам карьера финансового аналитика-программиста, где навыки работы с Python и финансовыми библиотеками вроде yfinance являются ключевыми. Тест учитывает ваши технические способности и особенности мышления, предлагая персонализированные карьерные рекомендации в быстрорастущей области финтеха.
Практические сценарии использования Python yfinance в трейдинге
Теоретические знания о библиотеке обретают реальную ценность, когда применяются в практических сценариях. Рассмотрим несколько готовых к использованию решений для трейдеров и инвесторов. 🔍
Первый сценарий: создание автоматизированной системы отслеживания уровней поддержки и сопротивления:
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import argrelextrema
# Функция для определения уровней поддержки и сопротивления
def find_support_resistance_levels(ticker, period="1y", interval="1d", order=5):
# Загрузка данных
data = yf.download(ticker, period=period, interval=interval)
# Находим локальные минимумы и максимумы
price = data['Close'].values
# Определение локальных минимумов
local_min_indices = argrelextrema(price, np.less_equal, order=order)[0]
local_min_values = price[local_min_indices]
local_min_dates = data.index[local_min_indices]
# Определение локальных максимумов
local_max_indices = argrelextrema(price, np.greater_equal, order=order)[0]
local_max_values = price[local_max_indices]
local_max_dates = data.index[local_max_indices]
# Группировка близких уровней поддержки (с погрешностью 2%)
support_levels = []
for price_min in local_min_values:
is_close_to_existing = False
for level in support_levels:
if abs(price_min – level) / level < 0.02:
is_close_to_existing = True
break
if not is_close_to_existing:
support_levels.append(price_min)
# Группировка близких уровней сопротивления
resistance_levels = []
for price_max in local_max_values:
is_close_to_existing = False
for level in resistance_levels:
if abs(price_max – level) / level < 0.02:
is_close_to_existing = True
break
if not is_close_to_existing:
resistance_levels.append(price_max)
# Визуализация
plt.figure(figsize=(14, 7))
plt.plot(data.index, data['Close'], label=ticker)
# Отметка уровней поддержки
for level in support_levels:
plt.axhline(y=level, color='g', linestyle='-', alpha=0.3)
# Отметка уровней сопротивления
for level in resistance_levels:
plt.axhline(y=level, color='r', linestyle='-', alpha=0.3)
plt.scatter(local_min_dates, local_min_values, color='g', label='Поддержка')
plt.scatter(local_max_dates, local_max_values, color='r', label='Сопротивление')
plt.title(f'Уровни поддержки и сопротивления для {ticker}')
plt.xlabel('Дата')
plt.ylabel('Цена')
plt.legend()
plt.grid(True)
plt.show()
# Возвращаем данные для дальнейшего анализа
return {
'ticker': ticker,
'current_price': price[-1],
'support_levels': sorted(support_levels),
'resistance_levels': sorted(resistance_levels),
'nearest_support': max([s for s in support_levels if s < price[-1]], default=None),
'nearest_resistance': min([r for r in resistance_levels if r > price[-1]], default=None)
}
# Пример использования
results = find_support_resistance_levels("NVDA", period="6mo", order=10)
# Вывод результатов анализа
print(f"Текущая цена {results['ticker']}: ${results['current_price']:.2f}")
print(f"Ближайший уровень поддержки: ${results['nearest_support']:.2f}")
print(f"Ближайший уровень сопротивления: ${results['nearest_resistance']:.2f}")
print(f"Потенциал падения до поддержки: {((results['nearest_support'] / results['current_price']) – 1) * 100:.2f}%")
print(f"Потенциал роста до сопротивления: {((results['nearest_resistance'] / results['current_price']) – 1) * 100:.2f}%")
Второй сценарий: автоматизированная система ребалансировки портфеля на основе целевого распределения активов:
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Класс для управления портфелем
class PortfolioManager:
def __init__(self, tickers, target_allocation, initial_investment=10000):
self.tickers = tickers
self.target_allocation = target_allocation
self.initial_investment = initial_investment
self.current_data = None
self.portfolio_history = None
def download_data(self, period="1y"):
# Загрузка данных по всем тикерам
self.current_data = yf.download(self.tickers, period=period)['Close']
def calculate_current_allocation(self, positions, latest_prices=None):
if latest_prices is None:
latest_prices = self.current_data.iloc[-1]
# Расчет текущей стоимости позиций
position_values = {}
for ticker, shares in positions.items():
position_values[ticker] = shares * latest_prices[ticker]
total_value = sum(position_values.values())
# Расчет текущего распределения
current_allocation = {ticker: value/total_value for ticker, value in position_values.items()}
return current_allocation, total_value
def calculate_rebalance(self, positions, threshold=0.05):
# Получение последних цен
latest_prices = self.current_data.iloc[-1]
# Расчет текущего распределения
current_allocation, total_value = self.calculate_current_allocation(positions, latest_prices)
# Определение необходимости ребалансировки
need_rebalance = False
for ticker in self.tickers:
if abs(current_allocation[ticker] – self.target_allocation[ticker]) > threshold:
need_rebalance = True
break
if not need_rebalance:
return None, current_allocation, total_value
# Расчет целевых позиций
target_positions = {}
for ticker in self.tickers:
target_value = total_value * self.target_allocation[ticker]
target_shares = target_value / latest_prices[ticker]
target_positions[ticker] = int(target_shares) # Округление до целых акций
# Расчет действий по ребалансировке
actions = {}
for ticker in self.tickers:
actions[ticker] = target_positions[ticker] – positions[ticker]
return actions, current_allocation, total_value
def simulate_portfolio(self, rebalance_frequency='monthly', threshold=0.05):
# Создание начальных позиций на основе целевого распределения
initial_prices = self.current_data.iloc[0]
positions = {}
for ticker in self.tickers:
target_value = self.initial_investment * self.target_allocation[ticker]
shares = target_value / initial_prices[ticker]
positions[ticker] = int(shares)
# Отслеживание истории портфеля
dates = self.current_data.index
portfolio_values = []
allocations_history = []
rebalance_dates = []
# Определение дат ребалансировки
if rebalance_frequency == 'monthly':
rebalance_months = list(set([date.month for date in dates]))
rebalance_dates = [date for date in dates if dates.get_loc(date) == 0 or
date.month != dates[dates.get_loc(date)-1].month]
elif rebalance_frequency == 'quarterly':
rebalance_quarters = list(set([(date.year, (date.month-1)//3) for date in dates]))
rebalance_dates = [date for date in dates if dates.get_loc(date) == 0 or
(date.month-1)//3 != (dates[dates.get_loc(date)-1].month-1)//3]
elif rebalance_frequency == 'yearly':
rebalance_years = list(set([date.year for date in dates]))
rebalance_dates = [date for date in dates if dates.get_loc(date) == 0 or
date.year != dates[dates.get_loc(date)-1].year]
# Симуляция работы портфеля
for date in dates:
prices = self.current_data.loc[date]
# Проверка на необходимость ребалансировки
if date in rebalance_dates:
actions, current_allocation, total_value = self.calculate_rebalance(
positions, threshold)
if actions:
# Выполнение ребалансировки
for ticker, shares_change in actions.items():
positions[ticker] += shares_change
# Расчет текущей стоимости портфеля
portfolio_value = sum(positions[ticker] * prices[ticker] for ticker in self.tickers)
portfolio_values.append(portfolio_value)
# Запись текущего распределения
current_allocation, _ = self.calculate_current_allocation(positions, prices)
allocations_history.append(current_allocation)
# Создание истории портфеля
self.portfolio_history = pd.DataFrame({
'Value': portfolio_values
}, index=dates)
# Расчет показателей эффективности
self.portfolio_history['Returns'] = self.portfolio_history['Value'].pct_change()
self.portfolio_history['Cumulative Returns'] = (1 + self.portfolio_history['Returns']).cumprod() – 1
return self.portfolio_history, rebalance_dates, allocations_history
def visualize_performance(self, benchmark_ticker=None):
if self.portfolio_history is None:
print("Сначала выполните simulate_portfolio()")
return
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 10), gridspec_kw={'height_ratios': [3, 1]})
# График стоимости портфеля
self.portfolio_history['Value'].plot(ax=ax1, label='Портфель')
# Добавление бенчмарка, если указан
if benchmark_ticker:
benchmark_data = yf.download(benchmark_ticker,
start=self.portfolio_history.index[0],
end=self.portfolio_history.index[-1])['Close']
benchmark_returns = benchmark_data.pct_change()
benchmark_cumulative = (1 + benchmark_returns).cumprod()
normalized_benchmark = benchmark_cumulative * self.portfolio_history['Value'][0] / benchmark_cumulative[0]
normalized_benchmark.plot(ax=ax1, label=f'Бенчмарк ({benchmark_ticker})')
ax1.set_title('Динамика стоимости портфеля')
ax1.set_ylabel('Стоимость ($)')
ax1.legend()
ax1.grid(True)
# График накопленной доходности
self.portfolio_history['Cumulative Returns'].plot(ax=ax2, label='Накопленная доходность')
ax2.set_ylabel('Доходность (%)')
ax2.axhline(y=0, color='k', linestyle='-', alpha=0.2)
ax2.grid(True)
plt.tight_layout()
plt.show()
# Вывод статистики
annual_return = (1 + self.portfolio_history['Returns']).prod() ** (252 / len(self.portfolio_history)) – 1
volatility = self.portfolio_history['Returns'].std() * np.sqrt(252)
sharpe = annual_return / volatility if volatility != 0 else 0
max_drawdown = (self.portfolio_history['Value'] / self.portfolio_history['Value'].cummax() – 1).min()
print(f"Годовая доходность: {annual_return:.2%}")
print(f"Волатильность: {volatility:.2%}")
print(f"Коэффициент Шарпа: {sharpe:.2f}")
print(f"Максимальная просадка: {max_drawdown:.2%}")
print(f"Конечная стоимость: ${self.portfolio_history['Value'].iloc[-1]:.2f}")
print(f"Общая доходность: {self.portfolio_history['Value'].iloc[-1]/self.initial_investment – 1:.2%}")
# Пример использования
tickers = ['SPY', 'QQQ', 'GLD', 'TLT', 'VNQ']
target_allocation = {
'SPY': 0.25, # S&P 500
'QQQ': 0.25, # Nasdaq 100
'GLD': 0.20, # Золото
'TLT': 0.20, # Долгосрочные казначейские облигации
'VNQ': 0.10 # Недвижимость
}
pm = PortfolioManager(tickers, target_allocation, initial_investment=10000)
pm.download_data(period="5y")
history, rebalance_dates, allocations = pm.simulate_portfolio(rebalance_frequency='quarterly')
pm.visualize_performance(benchmark_ticker='SPY')
Третий сценарий: создание системы скрининга акций для выявления потенциальных возможностей роста на основе дивергенции цены и объема:
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
# Функция для выявления дивергенций
def detect_price_volume_divergence(ticker, period="6mo", window=20):
# Загрузка данных
data = yf.download(ticker, period=period)
if len(data) < window * 2:
return None
# Расчет индикаторов
data['Price_ROC'] = data['Close'].pct_change(window)
data['Volume_ROC'] = data['Volume'].pct_change(window)
# Выявление дивергенций
data['Bullish_Divergence'] = ((data['Price_ROC'] < 0) & (data['Volume_ROC'] > 0)).astype(int)
data['Bearish_Divergence'] = ((data['Price_ROC'] > 0) & (data['Volume_ROC'] < 0)).astype(int)
# Фильтрация сильных сигналов
strong_bullish = data[data['Bullish_Divergence'] == 1].copy()
strong_bearish = data[data['Bearish_Divergence'] == 1].copy()
if not strong_bullish.empty or not strong_bearish.empty:
# Расчет силы дивергенции
if not strong_bullish.empty:
strong_bullish['Divergence_Strength'] = strong_bullish['Volume_ROC'] / abs(strong_bullish['Price_ROC'])
if not strong_bearish.empty:
strong_bearish['Divergence_Strength'] = strong_bearish['Volume_ROC'] / abs(strong_bearish['Price_ROC'])
# Последние сигналы
last_bullish = strong_bullish.iloc[-1] if not strong_bullish.empty else None
last_bearish = strong_bearish.iloc[-1] if not strong_bearish.empty else None
# Возвращаем результаты
return {
'ticker': ticker,
'current_price': data['Close'].iloc[-1],
'last_bullish_date': last_bullish.name if last_bullish is not None else None,
'last_bullish_strength': last_bullish['Divergence_Strength'] if last_bullish is not None else None,
'last_bearish_date': last_bearish.name if last_bearish is not None else None,
'last_bearish_strength': last_bearish['Divergence_Strength'] if last_bearish is not None else None,
'data': data
}
return None
# Функция для скрининга списка акций
def screen_stocks_for_divergences(tickers, period="6mo", window=20):
results = []
for ticker in tqdm(tickers, desc="Анализируем акции"):
try:
divergence = detect_price_volume_divergence(ticker, period, window)
if divergence:
results.append(divergence)
except Exception as e:
print(f"Ошибка при обработке {ticker}: {str(e)}")
return results
# Пример использования: скрининг компонентов S&P 500
def get_sp500_tickers():
# В реальном сценарии здесь был бы запрос к API или парсинг списка
# Для примера используем ограниченный набор тикеров
return ['AAPL', 'MSFT', 'AMZN', 'TSLA', 'GOOG', 'META', 'NVDA', 'BRK-B', 'UNH', 'JNJ']
tickers = get_sp500_tickers()
divergence_results = screen_stocks_for_divergences(tickers)
# Вывод результатов
if divergence_results:
# Сортировка по силе бычьей дивергенции
bullish_opportunities = [r for r in divergence_results if r['last_bullish_date'] is not None]
bullish_opportunities.sort(key=lambda x: x['last_bullish_strength'], reverse=True)
print("Топ-5 акций с бычьей дивергенцией цены и объема:")
for i, result in enumerate(bullish_opportunities[:5], 1):
print(f"{i}. {result['ticker']}: ${result['current_price']:.2f}, сила дивергенции: {result['last_bullish_strength']:.2f}")
# Визуализация лучшей возможности
if bullish_opportunities:
best = bullish_opportunities[0]
plt.figure(figsize=(14, 8))
# Создание подграфиков
ax1 = plt.subplot(211)
ax2 = plt.subplot(212, sharex=ax1)
# График цены
ax1.plot(best['data'].index, best['data']['Close'])
ax1.set_title(f"Бычья дивергенция цены и объема для {best['ticker']}")
ax1.set_ylabel("Цена")
ax1.grid(True)
# Отметка даты последней дивергенции
if best['last_bullish_date']:
ax1.axvline(x=best['last_bullish_date'], color='g', linestyle='--',
label=f"Дата бычьей дивергенции: {best['last_bullish_date'].date()}")
# График объема
ax2.bar(best['data'].index, best['data']['Volume'])
ax2.set_ylabel("Объем")
ax2.grid(True)
# Отметка даты последней дивергенции
if best['last_bullish_date']:
ax2.axvline(x=best['last_bullish_date'], color='g', linestyle='--')
plt.tight_layout()
plt.show()
else:
print("Дивергенций не обнаружено")
Эти примеры демонстрируют, как с помощью yfinance и стандартных библиотек Python можно создавать профессиональные торговые системы. Важные особенности при практической реализации:
- Всегда проверяйте полученные данные на полноту и корректность
- Учитывайте задержку данных при создании торговых стратегий
- Используйте механизмы кэширования для снижения нагрузки на сервер Yahoo
- Внедряйте обработку исключений для устойчивости к ошибкам загрузки данных
- Тестируйте стратегии на исторических данных перед применением на реальных счетах
- Комбинируйте технический и фундаментальный анализ для повышения точности сигналов
- Разделяйте системы анализа и исполнения торговых операций для безопасности
Освоив Python и yfinance, вы получили мощный инструмент для работы с финансовыми данными. Эта комбинация открывает дверь в мир алгоритмической торговли, автоматизированного анализа и принятия инвестиционных решений на основе данных. Доступность информации и вычислительн