- Обновлен config.py с оптимизированными словарями секторов и индексов - Удалены устаревшие классы exchange.py и moex_class.py - Модернизирован moex_history.py с улучшенной логикой получения данных - Обновлен requirements.txt с современными зависимостями для финансовой платформы - Упрощен open_router.ipynb с фокусом на экономических темах
141 lines
5.6 KiB
Python
141 lines
5.6 KiB
Python
import pandas as pd
|
||
import aiohttp
|
||
import asyncio
|
||
from datetime import datetime, timedelta
|
||
import sys
|
||
import os
|
||
|
||
# Добавляем родительскую директорию в путь для импорта
|
||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||
from config import sector_indices
|
||
|
||
|
||
class MOEXHistoricalData:
|
||
"""Класс для получения исторических данных с Московской биржи"""
|
||
|
||
def __init__(self):
|
||
"""Инициализация класса для работы с историческими данными MOEX"""
|
||
self.base_url = "https://iss.moex.com/iss"
|
||
|
||
async def _make_request(self, url: str) -> dict:
|
||
"""
|
||
Выполняет асинхронный запрос к API MOEX
|
||
|
||
Args:
|
||
url: URL для запроса
|
||
|
||
Returns:
|
||
dict: Ответ от API в формате JSON
|
||
"""
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.get(url) as response:
|
||
if response.status == 200:
|
||
return await response.json()
|
||
else:
|
||
raise Exception(f"Ошибка при запросе к API MOEX: {response.status}")
|
||
|
||
async def get_official_sector_index(self, sector: str, start_date: str, end_date: str) -> pd.DataFrame:
|
||
"""
|
||
Получает исторические данные по официальному индексу сектора
|
||
|
||
Args:
|
||
sector: Название сектора
|
||
start_date: Начальная дата в формате 'YYYY-MM-DD'
|
||
end_date: Конечная дата в формате 'YYYY-MM-DD'
|
||
|
||
Returns:
|
||
pd.DataFrame: Исторические данные по индексу
|
||
"""
|
||
# Получаем код индекса для сектора
|
||
index_code = sector_indices.get(sector)
|
||
|
||
if not index_code:
|
||
raise ValueError(f"Неизвестный сектор: {sector}")
|
||
|
||
# Формируем URL для запроса
|
||
url = f"{self.base_url}/history/engines/stock/markets/index/securities/{index_code}/candles.json"
|
||
url += f"?from={start_date}&till={end_date}&interval=24"
|
||
|
||
# Выполняем запрос
|
||
response = await self._make_request(url)
|
||
|
||
# Преобразуем ответ в DataFrame
|
||
if 'candles' in response and 'data' in response['candles']:
|
||
df = pd.DataFrame(response['candles']['data'], columns=response['candles']['columns'])
|
||
|
||
# Переименовываем колонки для соответствия формату
|
||
df = df.rename(columns={
|
||
'begin': 'TRADEDATE',
|
||
'open': 'OPEN',
|
||
'high': 'HIGH',
|
||
'low': 'LOW',
|
||
'close': 'CLOSE',
|
||
'volume': 'VOLUME'
|
||
})
|
||
|
||
# Преобразуем дату в формат datetime
|
||
df['TRADEDATE'] = pd.to_datetime(df['TRADEDATE']).dt.date
|
||
|
||
return df
|
||
else:
|
||
return pd.DataFrame()
|
||
|
||
async def get_security_history(self, ticker: str, start_date: str, end_date: str) -> pd.DataFrame:
|
||
"""
|
||
Получает исторические данные по ценной бумаге
|
||
|
||
Args:
|
||
ticker: Тикер ценной бумаги
|
||
start_date: Начальная дата в формате 'YYYY-MM-DD'
|
||
end_date: Конечная дата в формате 'YYYY-MM-DD'
|
||
|
||
Returns:
|
||
pd.DataFrame: Исторические данные по ценной бумаге
|
||
"""
|
||
# Формируем URL для запроса
|
||
url = f"{self.base_url}/history/engines/stock/markets/shares/securities/{ticker}/candles.json"
|
||
url += f"?from={start_date}&till={end_date}&interval=24"
|
||
|
||
# Выполняем запрос
|
||
response = await self._make_request(url)
|
||
|
||
# Преобразуем ответ в DataFrame
|
||
if 'candles' in response and 'data' in response['candles']:
|
||
df = pd.DataFrame(response['candles']['data'], columns=response['candles']['columns'])
|
||
|
||
# Переименовываем колонки для соответствия формату
|
||
df = df.rename(columns={
|
||
'begin': 'TRADEDATE',
|
||
'open': 'OPEN',
|
||
'high': 'HIGH',
|
||
'low': 'LOW',
|
||
'close': 'CLOSE',
|
||
'volume': 'VOLUME'
|
||
})
|
||
|
||
# Преобразуем дату в формат datetime
|
||
df['TRADEDATE'] = pd.to_datetime(df['TRADEDATE']).dt.date
|
||
|
||
return df
|
||
else:
|
||
return pd.DataFrame()
|
||
|
||
|
||
# Пример использования
|
||
if __name__ == "__main__":
|
||
async def test():
|
||
moex = MOEXHistoricalData()
|
||
|
||
# Получаем данные по индексу нефти и газа за последний месяц
|
||
end_date = datetime.now()
|
||
start_date = end_date - timedelta(days=30)
|
||
|
||
df = await moex.get_official_sector_index(
|
||
'oil_gas',
|
||
start_date.strftime('%Y-%m-%d'),
|
||
end_date.strftime('%Y-%m-%d')
|
||
)
|
||
|
||
print(df.head())
|
||
|
||
asyncio.run(test()) |