Обновление зависимостей и игнорируемых файлов
- Добавлен yfinance в requirements.txt - Расширен .gitignore для исключения служебных файлов Python - Исправлен импорт в currency.py для корректной работы с модулями
This commit is contained in:
parent
74d4e14476
commit
61b6f03e26
6
.gitignore
vendored
6
.gitignore
vendored
@ -1 +1,7 @@
|
|||||||
venv/
|
venv/
|
||||||
|
pycache/
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
__pycache__/
|
||||||
|
__pycache__
|
||||||
11
4.2.0
Normal file
11
4.2.0
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Requirement already satisfied: nbformat in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (5.10.4)
|
||||||
|
Requirement already satisfied: fastjsonschema>=2.15 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from nbformat) (2.21.1)
|
||||||
|
Requirement already satisfied: jsonschema>=2.6 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from nbformat) (4.23.0)
|
||||||
|
Requirement already satisfied: jupyter-core!=5.0.*,>=4.12 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from nbformat) (5.7.2)
|
||||||
|
Requirement already satisfied: traitlets>=5.1 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from nbformat) (5.14.3)
|
||||||
|
Requirement already satisfied: attrs>=22.2.0 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from jsonschema>=2.6->nbformat) (24.3.0)
|
||||||
|
Requirement already satisfied: jsonschema-specifications>=2023.03.6 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from jsonschema>=2.6->nbformat) (2024.10.1)
|
||||||
|
Requirement already satisfied: referencing>=0.28.4 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from jsonschema>=2.6->nbformat) (0.35.1)
|
||||||
|
Requirement already satisfied: rpds-py>=0.7.1 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from jsonschema>=2.6->nbformat) (0.22.3)
|
||||||
|
Requirement already satisfied: platformdirs>=2.5 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from jupyter-core!=5.0.*,>=4.12->nbformat) (4.3.6)
|
||||||
|
Requirement already satisfied: pywin32>=300 in d:\pythonpython\globalsy\globalsy_streamlit\venv\lib\site-packages (from jupyter-core!=5.0.*,>=4.12->nbformat) (308)
|
||||||
@ -134,3 +134,5 @@ class ForexDataHandler:
|
|||||||
raise ValueError(f"Неизвестный индекс: {index}")
|
raise ValueError(f"Неизвестный индекс: {index}")
|
||||||
|
|
||||||
return self.get_market_data(self.russian_indices[index])
|
return self.get_market_data(self.russian_indices[index])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
70
classes/moex_class.py
Normal file
70
classes/moex_class.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import requests
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
class RussianMarketData:
|
||||||
|
def __init__(self):
|
||||||
|
self.moex_base_url = "https://iss.moex.com/iss"
|
||||||
|
|
||||||
|
# Словарь с индексами
|
||||||
|
self.indices = {
|
||||||
|
'oil_gas': 'MOEXOG', # Нефть и газ
|
||||||
|
'finance': 'MOEXFN', # Финансы
|
||||||
|
'telecom': 'MOEXTL', # Телекоммуникации
|
||||||
|
'metals': 'MOEXMM', # Металлы и добыча
|
||||||
|
'consumer': 'MOEXCN', # Потребительский сектор
|
||||||
|
'transport': 'MOEXTN' # Транспорт
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_moex_index_history(self, index_code='MOEXOG', start_date=None, end_date=None):
|
||||||
|
"""
|
||||||
|
Получение исторических данных индекса MOEX.
|
||||||
|
"""
|
||||||
|
if start_date is None:
|
||||||
|
start_date = (datetime.now() - timedelta(days=365)).strftime('%Y-%m-%d')
|
||||||
|
if end_date is None:
|
||||||
|
end_date = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
all_data = []
|
||||||
|
start = 0
|
||||||
|
while True:
|
||||||
|
url = f"{self.moex_base_url}/history/engines/stock/markets/index/securities/{index_code}.json"
|
||||||
|
params = {
|
||||||
|
'from': start_date,
|
||||||
|
'till': end_date,
|
||||||
|
'start': start
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.get(url, params=params)
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
# Проверка наличия данных
|
||||||
|
if 'history' not in data or len(data['history']['data']) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Добавление данных в общий список
|
||||||
|
all_data.extend(data['history']['data'])
|
||||||
|
start += 100 # Увеличиваем смещение на 100 для следующего запроса
|
||||||
|
|
||||||
|
# Преобразование данных в DataFrame
|
||||||
|
columns = data['history']['columns']
|
||||||
|
df = pd.DataFrame(all_data, columns=columns)
|
||||||
|
|
||||||
|
# Обработка данных
|
||||||
|
df['TRADEDATE'] = pd.to_datetime(df['TRADEDATE'])
|
||||||
|
df = df.set_index('TRADEDATE')
|
||||||
|
|
||||||
|
return df[['CLOSE', 'VOLUME']]
|
||||||
|
|
||||||
|
def get_historical_data(self, sector: str, start_date=None, end_date=None):
|
||||||
|
"""
|
||||||
|
Получает исторические данные для указанного сектора.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sector: ключ сектора из словаря indices
|
||||||
|
"""
|
||||||
|
if sector not in self.indices:
|
||||||
|
raise ValueError(f"Неизвестный сектор: {sector}")
|
||||||
|
|
||||||
|
index_code = self.indices[sector]
|
||||||
|
return self.get_moex_index_history(index_code, start_date, end_date)
|
||||||
228
classes/moex_history.py
Normal file
228
classes/moex_history.py
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import requests
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import List, Dict, Optional
|
||||||
|
import asyncio
|
||||||
|
import aiohttp
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
class MOEXHistoricalData:
|
||||||
|
def __init__(self):
|
||||||
|
self.base_url = "https://iss.moex.com/iss"
|
||||||
|
|
||||||
|
# Словарь соответствия секторов и их индексов на MOEX
|
||||||
|
self.sector_indices = {
|
||||||
|
'metals_mining': 'MOEXMM', # Индекс Металлов и добычи
|
||||||
|
'oil_gas': 'MOEXOG', # Индекс Нефти и газа
|
||||||
|
'chemicals': 'MOEXCH', # Индекс Химии и нефтехимии
|
||||||
|
'electric_utilities': 'MOEXEU', # Индекс Электроэнергетики
|
||||||
|
'telecom': 'MOEXTL', # Индекс Телекоммуникаций
|
||||||
|
'finance': 'MOEXFN', # Индекс Финансов
|
||||||
|
'consumer': 'MOEXCN', # Индекс Потребительского сектора
|
||||||
|
'transport': 'MOEXTN' # Индекс Транспорта
|
||||||
|
}
|
||||||
|
|
||||||
|
async def get_security_history(
|
||||||
|
self,
|
||||||
|
ticker: str,
|
||||||
|
start_date: str,
|
||||||
|
end_date: str,
|
||||||
|
engine: str = "stock",
|
||||||
|
market: str = "shares",
|
||||||
|
board: str = "TQBR"
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Получение исторических данных по отдельному тикеру
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ticker: Тикер акции
|
||||||
|
start_date: Начальная дата в формате YYYY-MM-DD
|
||||||
|
end_date: Конечная дата в формате YYYY-MM-DD
|
||||||
|
engine: Торговый движок (по умолчанию stock)
|
||||||
|
market: Рынок (по умолчанию shares)
|
||||||
|
board: Режим торгов (по умолчанию TQBR)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DataFrame с историческими данными
|
||||||
|
"""
|
||||||
|
url = f"{self.base_url}/history/engines/{engine}/markets/{market}/boards/{board}/securities/{ticker}.json"
|
||||||
|
|
||||||
|
all_data = []
|
||||||
|
start = 0
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
while True:
|
||||||
|
params = {
|
||||||
|
"from": start_date,
|
||||||
|
"till": end_date,
|
||||||
|
"start": start,
|
||||||
|
"limit": 100
|
||||||
|
}
|
||||||
|
|
||||||
|
async with session.get(url, params=params) as response:
|
||||||
|
data = await response.json()
|
||||||
|
|
||||||
|
# Получаем данные истории
|
||||||
|
history_data = data['history']
|
||||||
|
|
||||||
|
if not history_data['data']:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Добавляем данные в общий список
|
||||||
|
all_data.extend(history_data['data'])
|
||||||
|
start += 100
|
||||||
|
|
||||||
|
if len(history_data['data']) < 100:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Создаем DataFrame
|
||||||
|
df = pd.DataFrame(all_data, columns=history_data['columns'])
|
||||||
|
|
||||||
|
# Конвертируем даты и числовые значения
|
||||||
|
df['TRADEDATE'] = pd.to_datetime(df['TRADEDATE'])
|
||||||
|
numeric_columns = ['OPEN', 'HIGH', 'LOW', 'CLOSE', 'VALUE', 'VOLUME']
|
||||||
|
df[numeric_columns] = df[numeric_columns].apply(pd.to_numeric)
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
async def get_sector_history(
|
||||||
|
self,
|
||||||
|
sector_tickers: List[str],
|
||||||
|
start_date: str,
|
||||||
|
end_date: str,
|
||||||
|
engine: str = "stock",
|
||||||
|
market: str = "shares",
|
||||||
|
board: str = "TQBR"
|
||||||
|
) -> Dict[str, pd.DataFrame]:
|
||||||
|
"""
|
||||||
|
Получение исторических данных по всем тикерам сектора
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sector_tickers: Список тикеров сектора
|
||||||
|
start_date: Начальная дата в формате YYYY-MM-DD
|
||||||
|
end_date: Конечная дата в формате YYYY-MM-DD
|
||||||
|
engine: Торговый движок (по умолчанию stock)
|
||||||
|
market: Рынок (по умолчанию shares)
|
||||||
|
board: Режим торгов (по умолчанию TQBR)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Словарь {тикер: DataFrame с историческими данными}
|
||||||
|
"""
|
||||||
|
tasks = []
|
||||||
|
for ticker in sector_tickers:
|
||||||
|
task = self.get_security_history(
|
||||||
|
ticker=ticker,
|
||||||
|
start_date=start_date,
|
||||||
|
end_date=end_date,
|
||||||
|
engine=engine,
|
||||||
|
market=market,
|
||||||
|
board=board
|
||||||
|
)
|
||||||
|
tasks.append(task)
|
||||||
|
|
||||||
|
results = await asyncio.gather(*tasks)
|
||||||
|
return dict(zip(sector_tickers, results))
|
||||||
|
|
||||||
|
async def get_official_sector_index(
|
||||||
|
self,
|
||||||
|
sector: str,
|
||||||
|
start_date: str,
|
||||||
|
end_date: str
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Получение официального отраслевого индекса с MOEX
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sector: Название сектора (ключ из словаря sector_indices)
|
||||||
|
start_date: Начальная дата в формате YYYY-MM-DD
|
||||||
|
end_date: Конечная дата в формате YYYY-MM-DD
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DataFrame с данными индекса
|
||||||
|
"""
|
||||||
|
if sector not in self.sector_indices:
|
||||||
|
raise ValueError(f"Неизвестный сектор: {sector}. Доступные секторы: {list(self.sector_indices.keys())}")
|
||||||
|
|
||||||
|
index_ticker = self.sector_indices[sector]
|
||||||
|
url = f"{self.base_url}/history/engines/stock/markets/index/securities/{index_ticker}.json"
|
||||||
|
|
||||||
|
all_data = []
|
||||||
|
start = 0
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
while True:
|
||||||
|
params = {
|
||||||
|
"from": start_date,
|
||||||
|
"till": end_date,
|
||||||
|
"start": start,
|
||||||
|
"limit": 100
|
||||||
|
}
|
||||||
|
|
||||||
|
async with session.get(url, params=params) as response:
|
||||||
|
data = await response.json()
|
||||||
|
|
||||||
|
history_data = data['history']
|
||||||
|
|
||||||
|
if not history_data['data']:
|
||||||
|
break
|
||||||
|
|
||||||
|
all_data.extend(history_data['data'])
|
||||||
|
start += 100
|
||||||
|
|
||||||
|
if len(history_data['data']) < 100:
|
||||||
|
break
|
||||||
|
|
||||||
|
df = pd.DataFrame(all_data, columns=history_data['columns'])
|
||||||
|
|
||||||
|
# Конвертируем даты и числовые значения
|
||||||
|
df['TRADEDATE'] = pd.to_datetime(df['TRADEDATE'])
|
||||||
|
numeric_columns = ['OPEN', 'HIGH', 'LOW', 'CLOSE', 'VALUE', 'VOLUME']
|
||||||
|
df[numeric_columns] = df[numeric_columns].apply(pd.to_numeric)
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def calculate_sector_index(
|
||||||
|
self,
|
||||||
|
sector_data: Dict[str, pd.DataFrame],
|
||||||
|
weights: Optional[Dict[str, float]] = None
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Расчет индекса сектора на основе исторических данных входящих в него компаний
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sector_data: Словарь с историческими данными по тикерам {тикер: DataFrame}
|
||||||
|
weights: Словарь с весами компаний {тикер: вес}. Если None, веса будут равными
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DataFrame с рассчитанным индексом сектора
|
||||||
|
"""
|
||||||
|
# Если веса не указаны, используем равные веса
|
||||||
|
if weights is None:
|
||||||
|
weights = {ticker: 1/len(sector_data) for ticker in sector_data.keys()}
|
||||||
|
|
||||||
|
# Создаем DataFrame с датами и ценами закрытия для каждого тикера
|
||||||
|
prices_df = pd.DataFrame()
|
||||||
|
|
||||||
|
for ticker, df in sector_data.items():
|
||||||
|
prices_df[ticker] = df.set_index('TRADEDATE')['CLOSE']
|
||||||
|
|
||||||
|
# Рассчитываем относительное изменение цен
|
||||||
|
returns_df = prices_df.pct_change()
|
||||||
|
|
||||||
|
# Рассчитываем взвешенную доходность индекса
|
||||||
|
weighted_returns = pd.DataFrame()
|
||||||
|
for ticker in returns_df.columns:
|
||||||
|
weighted_returns[ticker] = returns_df[ticker] * weights[ticker]
|
||||||
|
|
||||||
|
index_returns = weighted_returns.sum(axis=1)
|
||||||
|
|
||||||
|
# Рассчитываем значения индекса
|
||||||
|
index_values = (1 + index_returns).cumprod() * 1000 # Начальное значение 1000
|
||||||
|
|
||||||
|
# Создаем итоговый DataFrame
|
||||||
|
result_df = pd.DataFrame({
|
||||||
|
'INDEX_VALUE': index_values,
|
||||||
|
'INDEX_RETURN': index_returns
|
||||||
|
})
|
||||||
|
|
||||||
|
return result_df
|
||||||
255
config.py
Normal file
255
config.py
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
sector_indices = {
|
||||||
|
'metals_mining': 'MOEXMM', # Индекс Металлов и добычи
|
||||||
|
'oil_gas': 'MOEXOG', # Индекс Нефти и газа
|
||||||
|
'chemicals': 'MOEXCH', # Индекс Химии и нефтехимии
|
||||||
|
'electric_utilities': 'MOEXEU', # Индекс Электроэнергетики
|
||||||
|
'telecom': 'MOEXTL', # Индекс Телекоммуникаций
|
||||||
|
'finance': 'MOEXFN', # Индекс Финансов
|
||||||
|
'consumer': 'MOEXCN', # Индекс Потребительского сектора
|
||||||
|
'transport': 'MOEXTN' # Индекс Транспорта
|
||||||
|
}
|
||||||
|
|
||||||
|
sector_tickers = {'metals_mining': ['ALRS',
|
||||||
|
'AMEZ',
|
||||||
|
'BELO',
|
||||||
|
'BLNG',
|
||||||
|
'CHEP',
|
||||||
|
'CHMF',
|
||||||
|
'CHMK',
|
||||||
|
'CHZN',
|
||||||
|
'ENPG',
|
||||||
|
'GMKN',
|
||||||
|
'KBTK',
|
||||||
|
'KOGK',
|
||||||
|
'LNZL',
|
||||||
|
'LNZLP',
|
||||||
|
'MAGN',
|
||||||
|
'MGOK',
|
||||||
|
'MTLR',
|
||||||
|
'MTLRP',
|
||||||
|
'NLMK',
|
||||||
|
'PGIL',
|
||||||
|
'PLZL',
|
||||||
|
'PMTL',
|
||||||
|
'POGR',
|
||||||
|
'POLY',
|
||||||
|
'RASP',
|
||||||
|
'RUAL',
|
||||||
|
'RUALR',
|
||||||
|
'SELG',
|
||||||
|
'SELGP',
|
||||||
|
'TRMK',
|
||||||
|
'UGLD',
|
||||||
|
'UNKL',
|
||||||
|
'VSMO',
|
||||||
|
'VSMZ'],
|
||||||
|
'oil_gas': ['BANE',
|
||||||
|
'BANEP',
|
||||||
|
'GAZP',
|
||||||
|
'JNOSP',
|
||||||
|
'KRKNP',
|
||||||
|
'LKOH',
|
||||||
|
'MFGS',
|
||||||
|
'MFGSP',
|
||||||
|
'NOTK',
|
||||||
|
'NVTK',
|
||||||
|
'RITK',
|
||||||
|
'RNFT',
|
||||||
|
'RNHSP',
|
||||||
|
'ROSN',
|
||||||
|
'SIBN',
|
||||||
|
'SNGS',
|
||||||
|
'SNGSP',
|
||||||
|
'TATN',
|
||||||
|
'TATNP',
|
||||||
|
'TNBP',
|
||||||
|
'TNBPP',
|
||||||
|
'TRMK',
|
||||||
|
'TRNFP'],
|
||||||
|
'chemicals': ['AKRN',
|
||||||
|
'AZKM',
|
||||||
|
'DGBZ',
|
||||||
|
'DGBZP',
|
||||||
|
'KAZT',
|
||||||
|
'KZOS',
|
||||||
|
'KZOSP',
|
||||||
|
'MGNZ',
|
||||||
|
'NKNC',
|
||||||
|
'NKNCP',
|
||||||
|
'OMSH',
|
||||||
|
'PHOR',
|
||||||
|
'SILV',
|
||||||
|
'URKA',
|
||||||
|
'YASH'],
|
||||||
|
'electric_utilities': ['ARSB',
|
||||||
|
'BEGY',
|
||||||
|
'DVEC',
|
||||||
|
'EESR',
|
||||||
|
'EESRP',
|
||||||
|
'ELFV',
|
||||||
|
'ENRU',
|
||||||
|
'EONR',
|
||||||
|
'FEES',
|
||||||
|
'HYDR',
|
||||||
|
'IRAO',
|
||||||
|
'IRGZ',
|
||||||
|
'KISB',
|
||||||
|
'KRNG',
|
||||||
|
'KRSG',
|
||||||
|
'LSNG',
|
||||||
|
'LSNGP',
|
||||||
|
'MGSV',
|
||||||
|
'MRKC',
|
||||||
|
'MRKH',
|
||||||
|
'MRKK',
|
||||||
|
'MRKP',
|
||||||
|
'MRKS',
|
||||||
|
'MRKU',
|
||||||
|
'MRKV',
|
||||||
|
'MRKY',
|
||||||
|
'MRKZ',
|
||||||
|
'MSNG',
|
||||||
|
'MSRS',
|
||||||
|
'MSSB',
|
||||||
|
'MSSV',
|
||||||
|
'OGK1',
|
||||||
|
'OGK2',
|
||||||
|
'OGK4',
|
||||||
|
'OGK6',
|
||||||
|
'OGKA',
|
||||||
|
'OGKB',
|
||||||
|
'OGKC',
|
||||||
|
'OGKD',
|
||||||
|
'OGKE',
|
||||||
|
'OGKF',
|
||||||
|
'RSTI',
|
||||||
|
'RSTIP',
|
||||||
|
'SAGO',
|
||||||
|
'SARE',
|
||||||
|
'SVER',
|
||||||
|
'TGKA',
|
||||||
|
'TGKB',
|
||||||
|
'TGKD',
|
||||||
|
'TGKE',
|
||||||
|
'TGKF',
|
||||||
|
'TGKH',
|
||||||
|
'TGKI',
|
||||||
|
'TGKJ',
|
||||||
|
'TGKN',
|
||||||
|
'TNSE',
|
||||||
|
'UPRO',
|
||||||
|
'VRAO',
|
||||||
|
'VTGK',
|
||||||
|
'YKEN'],
|
||||||
|
'telecom': ['AFKC',
|
||||||
|
'AFKS',
|
||||||
|
'BISV',
|
||||||
|
'BISVP',
|
||||||
|
'CMST',
|
||||||
|
'CNTL',
|
||||||
|
'CNTLP',
|
||||||
|
'CTLK',
|
||||||
|
'DLSV',
|
||||||
|
'DLSVP',
|
||||||
|
'MFON',
|
||||||
|
'MGTS',
|
||||||
|
'MGTSP',
|
||||||
|
'MTSI',
|
||||||
|
'MTSS',
|
||||||
|
'RTKM',
|
||||||
|
'RTKMP',
|
||||||
|
'SPTL',
|
||||||
|
'SPTLP',
|
||||||
|
'STKM',
|
||||||
|
'STKMP',
|
||||||
|
'TTLK',
|
||||||
|
'URSI',
|
||||||
|
'URSIP',
|
||||||
|
'UTEL',
|
||||||
|
'VTEL',
|
||||||
|
'VTELP'],
|
||||||
|
'finance': ['AFKS',
|
||||||
|
'BSPB',
|
||||||
|
'BSPBP',
|
||||||
|
'CBOM',
|
||||||
|
'EPLN',
|
||||||
|
'FTRE',
|
||||||
|
'LEAS',
|
||||||
|
'MBNK',
|
||||||
|
'MMBM',
|
||||||
|
'MOEX',
|
||||||
|
'PSBR',
|
||||||
|
'QIWI',
|
||||||
|
'RENI',
|
||||||
|
'ROSB',
|
||||||
|
'SBER',
|
||||||
|
'SBERP',
|
||||||
|
'SFIN',
|
||||||
|
'SPBE',
|
||||||
|
'T',
|
||||||
|
'TAVR',
|
||||||
|
'TCSG',
|
||||||
|
'TRHN',
|
||||||
|
'URSAP',
|
||||||
|
'VTBR',
|
||||||
|
'VTBS',
|
||||||
|
'VZRZ',
|
||||||
|
'VZRZP',
|
||||||
|
'YRSL',
|
||||||
|
'ZAYM'],
|
||||||
|
'consumer': ['ABIO',
|
||||||
|
'AGRO',
|
||||||
|
'APTK',
|
||||||
|
'AQUA',
|
||||||
|
'AVAZ',
|
||||||
|
'AVAZP',
|
||||||
|
'BELU',
|
||||||
|
'DELI',
|
||||||
|
'DIXY',
|
||||||
|
'DSKY',
|
||||||
|
'EUTR',
|
||||||
|
'FIVE',
|
||||||
|
'FIXP',
|
||||||
|
'GCHE',
|
||||||
|
'GEMC',
|
||||||
|
'GRAZ',
|
||||||
|
'HNFG',
|
||||||
|
'ISKJ',
|
||||||
|
'KLNA',
|
||||||
|
'LENT',
|
||||||
|
'LIFE',
|
||||||
|
'LNTA',
|
||||||
|
'MDMG',
|
||||||
|
'MGNT',
|
||||||
|
'MVID',
|
||||||
|
'OBUV',
|
||||||
|
'OKEY',
|
||||||
|
'ORUP',
|
||||||
|
'OTCP',
|
||||||
|
'PHST',
|
||||||
|
'PKBA',
|
||||||
|
'PKBAP',
|
||||||
|
'PRMD',
|
||||||
|
'PRTK',
|
||||||
|
'ROST',
|
||||||
|
'RSEA',
|
||||||
|
'SCOH',
|
||||||
|
'SCON',
|
||||||
|
'SVAV',
|
||||||
|
'SYNG',
|
||||||
|
'VFRM',
|
||||||
|
'VRPH',
|
||||||
|
'VSEH',
|
||||||
|
'WBDF',
|
||||||
|
'WUSH',
|
||||||
|
'YNDX'],
|
||||||
|
'transport': ['AFLT',
|
||||||
|
'FESH',
|
||||||
|
'FLOT',
|
||||||
|
'GLTR',
|
||||||
|
'GTRK',
|
||||||
|
'NKHP',
|
||||||
|
'NMTP',
|
||||||
|
'TAER',
|
||||||
|
'TRCN',
|
||||||
|
'UTAR']}
|
||||||
@ -1,5 +1,11 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Добавляем путь к родительской директории
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from exchange import ForexDataHandler
|
from classes.exchange import ForexDataHandler
|
||||||
|
|
||||||
# Создаем или подключаемся к базе данных
|
# Создаем или подключаемся к базе данных
|
||||||
conn = sqlite3.connect('currency_rates.db')
|
conn = sqlite3.connect('currency_rates.db')
|
||||||
|
|||||||
101
get/tick_history.py
Normal file
101
get/tick_history.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import sqlite3
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import asyncio
|
||||||
|
# Добавляем путь к родительской директории
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||||
|
from classes.moex_history import MOEXHistoricalData
|
||||||
|
from config import sector_tickers
|
||||||
|
|
||||||
|
|
||||||
|
class DataLoader:
|
||||||
|
def __init__(self, db_path: str):
|
||||||
|
"""
|
||||||
|
Инициализация загрузчика данных.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
db_path: Путь к файлу базы данных SQLite
|
||||||
|
"""
|
||||||
|
self.db_path = db_path
|
||||||
|
self.moex_data_handler = MOEXHistoricalData()
|
||||||
|
|
||||||
|
def _get_connection(self):
|
||||||
|
"""
|
||||||
|
Создает и возвращает соединение с базой данных.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
sqlite3.Connection: Объект соединения с базой данных
|
||||||
|
"""
|
||||||
|
return sqlite3.connect(self.db_path)
|
||||||
|
|
||||||
|
async def load_sector_data(self, sector: str):
|
||||||
|
"""
|
||||||
|
Получение и сохранение исторических данных по сектору.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sector: Название сектора
|
||||||
|
"""
|
||||||
|
end_date = datetime.now()
|
||||||
|
start_date = end_date - timedelta(days=730) # За последние 2 года
|
||||||
|
|
||||||
|
# Получаем данные по официальному секторному индексу
|
||||||
|
sector_df = await self.moex_data_handler.get_official_sector_index(
|
||||||
|
sector,
|
||||||
|
start_date.strftime('%Y-%m-%d'),
|
||||||
|
end_date.strftime('%Y-%m-%d')
|
||||||
|
)
|
||||||
|
|
||||||
|
# Сохраняем данные в таблицу
|
||||||
|
with self._get_connection() as conn:
|
||||||
|
sector_df.to_sql(sector, conn, if_exists='replace', index=False)
|
||||||
|
print(f"Данные для сектора '{sector}' сохранены в таблице '{sector}'.")
|
||||||
|
|
||||||
|
async def load_ticker_data(self, tickers: list):
|
||||||
|
"""
|
||||||
|
Получение и сохранение исторических данных по тикерам.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tickers: Список тикеров
|
||||||
|
"""
|
||||||
|
end_date = datetime.now()
|
||||||
|
start_date = end_date - timedelta(days=730) # За последние 2 года
|
||||||
|
|
||||||
|
tasks = []
|
||||||
|
for ticker in tickers:
|
||||||
|
task = self.moex_data_handler.get_security_history(
|
||||||
|
ticker,
|
||||||
|
start_date.strftime('%Y-%m-%d'),
|
||||||
|
end_date.strftime('%Y-%m-%d')
|
||||||
|
)
|
||||||
|
tasks.append(task)
|
||||||
|
|
||||||
|
results = await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
with self._get_connection() as conn:
|
||||||
|
for ticker, df in zip(tickers, results):
|
||||||
|
df.to_sql(ticker, conn, if_exists='replace', index=False)
|
||||||
|
print(f"Данные для тикера '{ticker}' сохранены в таблице '{ticker}'.")
|
||||||
|
|
||||||
|
async def load_data(self, sector: str, tickers: list):
|
||||||
|
"""
|
||||||
|
Загрузка данных по сектору и тикерам.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sector: Название сектора
|
||||||
|
tickers: Список тикеров
|
||||||
|
"""
|
||||||
|
await asyncio.gather(
|
||||||
|
self.load_sector_data(sector),
|
||||||
|
self.load_ticker_data(tickers)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Пример использования
|
||||||
|
if __name__ == "__main__":
|
||||||
|
db_path = 'moex_data.db' # Путь к файлу базы данных SQLite
|
||||||
|
data_loader = DataLoader(db_path)
|
||||||
|
|
||||||
|
|
||||||
|
for sector in sector_tickers.keys():
|
||||||
|
asyncio.run(data_loader.load_data(sector, sector_tickers[sector]))
|
||||||
29
get_news_and_analyze.py
Normal file
29
get_news_and_analyze.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
client = OpenAI(
|
||||||
|
base_url="https://openrouter.ai/api/v1",
|
||||||
|
api_key="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",
|
||||||
|
)
|
||||||
|
|
||||||
|
completion = client.chat.completions.create(
|
||||||
|
extra_body={},
|
||||||
|
model="google/gemini-2.0-pro-exp-02-05:free",
|
||||||
|
messages=[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "What is in this image?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": {
|
||||||
|
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
print(completion.choices[0].message.content)
|
||||||
1668
open_router.ipynb
Normal file
1668
open_router.ipynb
Normal file
File diff suppressed because one or more lines are too long
@ -15,4 +15,5 @@ seaborn
|
|||||||
statsmodels
|
statsmodels
|
||||||
xgboost
|
xgboost
|
||||||
lightgbm
|
lightgbm
|
||||||
groq
|
groq
|
||||||
|
yfinance
|
||||||
262
sector_tickers.json
Normal file
262
sector_tickers.json
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
{
|
||||||
|
"metals_mining": [
|
||||||
|
"ALRS",
|
||||||
|
"AMEZ",
|
||||||
|
"BELO",
|
||||||
|
"BLNG",
|
||||||
|
"CHEP",
|
||||||
|
"CHMF",
|
||||||
|
"CHMK",
|
||||||
|
"CHZN",
|
||||||
|
"ENPG",
|
||||||
|
"GMKN",
|
||||||
|
"KBTK",
|
||||||
|
"KOGK",
|
||||||
|
"LNZL",
|
||||||
|
"LNZLP",
|
||||||
|
"MAGN",
|
||||||
|
"MGOK",
|
||||||
|
"MTLR",
|
||||||
|
"MTLRP",
|
||||||
|
"NLMK",
|
||||||
|
"PGIL",
|
||||||
|
"PLZL",
|
||||||
|
"PMTL",
|
||||||
|
"POGR",
|
||||||
|
"POLY",
|
||||||
|
"RASP",
|
||||||
|
"RUAL",
|
||||||
|
"RUALR",
|
||||||
|
"SELG",
|
||||||
|
"SELGP",
|
||||||
|
"TRMK",
|
||||||
|
"UGLD",
|
||||||
|
"UNKL",
|
||||||
|
"VSMO",
|
||||||
|
"VSMZ"
|
||||||
|
],
|
||||||
|
"oil_gas": [
|
||||||
|
"BANE",
|
||||||
|
"BANEP",
|
||||||
|
"GAZP",
|
||||||
|
"JNOSP",
|
||||||
|
"KRKNP",
|
||||||
|
"LKOH",
|
||||||
|
"MFGS",
|
||||||
|
"MFGSP",
|
||||||
|
"NOTK",
|
||||||
|
"NVTK",
|
||||||
|
"RITK",
|
||||||
|
"RNFT",
|
||||||
|
"RNHSP",
|
||||||
|
"ROSN",
|
||||||
|
"SIBN",
|
||||||
|
"SNGS",
|
||||||
|
"SNGSP",
|
||||||
|
"TATN",
|
||||||
|
"TATNP",
|
||||||
|
"TNBP",
|
||||||
|
"TNBPP",
|
||||||
|
"TRMK",
|
||||||
|
"TRNFP"
|
||||||
|
],
|
||||||
|
"chemicals": [
|
||||||
|
"AKRN",
|
||||||
|
"AZKM",
|
||||||
|
"DGBZ",
|
||||||
|
"DGBZP",
|
||||||
|
"KAZT",
|
||||||
|
"KZOS",
|
||||||
|
"KZOSP",
|
||||||
|
"MGNZ",
|
||||||
|
"NKNC",
|
||||||
|
"NKNCP",
|
||||||
|
"OMSH",
|
||||||
|
"PHOR",
|
||||||
|
"SILV",
|
||||||
|
"URKA",
|
||||||
|
"YASH"
|
||||||
|
],
|
||||||
|
"electric_utilities": [
|
||||||
|
"ARSB",
|
||||||
|
"BEGY",
|
||||||
|
"DVEC",
|
||||||
|
"EESR",
|
||||||
|
"EESRP",
|
||||||
|
"ELFV",
|
||||||
|
"ENRU",
|
||||||
|
"EONR",
|
||||||
|
"FEES",
|
||||||
|
"HYDR",
|
||||||
|
"IRAO",
|
||||||
|
"IRGZ",
|
||||||
|
"KISB",
|
||||||
|
"KRNG",
|
||||||
|
"KRSG",
|
||||||
|
"LSNG",
|
||||||
|
"LSNGP",
|
||||||
|
"MGSV",
|
||||||
|
"MRKC",
|
||||||
|
"MRKH",
|
||||||
|
"MRKK",
|
||||||
|
"MRKP",
|
||||||
|
"MRKS",
|
||||||
|
"MRKU",
|
||||||
|
"MRKV",
|
||||||
|
"MRKY",
|
||||||
|
"MRKZ",
|
||||||
|
"MSNG",
|
||||||
|
"MSRS",
|
||||||
|
"MSSB",
|
||||||
|
"MSSV",
|
||||||
|
"OGK1",
|
||||||
|
"OGK2",
|
||||||
|
"OGK4",
|
||||||
|
"OGK6",
|
||||||
|
"OGKA",
|
||||||
|
"OGKB",
|
||||||
|
"OGKC",
|
||||||
|
"OGKD",
|
||||||
|
"OGKE",
|
||||||
|
"OGKF",
|
||||||
|
"RSTI",
|
||||||
|
"RSTIP",
|
||||||
|
"SAGO",
|
||||||
|
"SARE",
|
||||||
|
"SVER",
|
||||||
|
"TGKA",
|
||||||
|
"TGKB",
|
||||||
|
"TGKD",
|
||||||
|
"TGKE",
|
||||||
|
"TGKF",
|
||||||
|
"TGKH",
|
||||||
|
"TGKI",
|
||||||
|
"TGKJ",
|
||||||
|
"TGKN",
|
||||||
|
"TNSE",
|
||||||
|
"UPRO",
|
||||||
|
"VRAO",
|
||||||
|
"VTGK",
|
||||||
|
"YKEN"
|
||||||
|
],
|
||||||
|
"telecom": [
|
||||||
|
"AFKC",
|
||||||
|
"AFKS",
|
||||||
|
"BISV",
|
||||||
|
"BISVP",
|
||||||
|
"CMST",
|
||||||
|
"CNTL",
|
||||||
|
"CNTLP",
|
||||||
|
"CTLK",
|
||||||
|
"DLSV",
|
||||||
|
"DLSVP",
|
||||||
|
"MFON",
|
||||||
|
"MGTS",
|
||||||
|
"MGTSP",
|
||||||
|
"MTSI",
|
||||||
|
"MTSS",
|
||||||
|
"RTKM",
|
||||||
|
"RTKMP",
|
||||||
|
"SPTL",
|
||||||
|
"SPTLP",
|
||||||
|
"STKM",
|
||||||
|
"STKMP",
|
||||||
|
"TTLK",
|
||||||
|
"URSI",
|
||||||
|
"URSIP",
|
||||||
|
"UTEL",
|
||||||
|
"VTEL",
|
||||||
|
"VTELP"
|
||||||
|
],
|
||||||
|
"finance": [
|
||||||
|
"AFKS",
|
||||||
|
"BSPB",
|
||||||
|
"BSPBP",
|
||||||
|
"CBOM",
|
||||||
|
"EPLN",
|
||||||
|
"FTRE",
|
||||||
|
"LEAS",
|
||||||
|
"MBNK",
|
||||||
|
"MMBM",
|
||||||
|
"MOEX",
|
||||||
|
"PSBR",
|
||||||
|
"QIWI",
|
||||||
|
"RENI",
|
||||||
|
"ROSB",
|
||||||
|
"SBER",
|
||||||
|
"SBERP",
|
||||||
|
"SFIN",
|
||||||
|
"SPBE",
|
||||||
|
"T",
|
||||||
|
"TAVR",
|
||||||
|
"TCSG",
|
||||||
|
"TRHN",
|
||||||
|
"URSAP",
|
||||||
|
"VTBR",
|
||||||
|
"VTBS",
|
||||||
|
"VZRZ",
|
||||||
|
"VZRZP",
|
||||||
|
"YRSL",
|
||||||
|
"ZAYM"
|
||||||
|
],
|
||||||
|
"consumer": [
|
||||||
|
"ABIO",
|
||||||
|
"AGRO",
|
||||||
|
"APTK",
|
||||||
|
"AQUA",
|
||||||
|
"AVAZ",
|
||||||
|
"AVAZP",
|
||||||
|
"BELU",
|
||||||
|
"DELI",
|
||||||
|
"DIXY",
|
||||||
|
"DSKY",
|
||||||
|
"EUTR",
|
||||||
|
"FIVE",
|
||||||
|
"FIXP",
|
||||||
|
"GCHE",
|
||||||
|
"GEMC",
|
||||||
|
"GRAZ",
|
||||||
|
"HNFG",
|
||||||
|
"ISKJ",
|
||||||
|
"KLNA",
|
||||||
|
"LENT",
|
||||||
|
"LIFE",
|
||||||
|
"LNTA",
|
||||||
|
"MDMG",
|
||||||
|
"MGNT",
|
||||||
|
"MVID",
|
||||||
|
"OBUV",
|
||||||
|
"OKEY",
|
||||||
|
"ORUP",
|
||||||
|
"OTCP",
|
||||||
|
"PHST",
|
||||||
|
"PKBA",
|
||||||
|
"PKBAP",
|
||||||
|
"PRMD",
|
||||||
|
"PRTK",
|
||||||
|
"ROST",
|
||||||
|
"RSEA",
|
||||||
|
"SCOH",
|
||||||
|
"SCON",
|
||||||
|
"SVAV",
|
||||||
|
"SYNG",
|
||||||
|
"VFRM",
|
||||||
|
"VRPH",
|
||||||
|
"VSEH",
|
||||||
|
"WBDF",
|
||||||
|
"WUSH",
|
||||||
|
"YNDX"
|
||||||
|
],
|
||||||
|
"transport": [
|
||||||
|
"AFLT",
|
||||||
|
"FESH",
|
||||||
|
"FLOT",
|
||||||
|
"GLTR",
|
||||||
|
"GTRK",
|
||||||
|
"NKHP",
|
||||||
|
"NMTP",
|
||||||
|
"TAER",
|
||||||
|
"TRCN",
|
||||||
|
"UTAR"
|
||||||
|
]
|
||||||
|
}
|
||||||
2269
test.ipynb
Normal file
2269
test.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user