QSSS_new / backend /data /data_service_memory.py
misonL's picture
特性:实现对话框、表单、输入框、标签、下拉菜单、分隔线、骨架屏、滑块、表格、文本区域的 UI 组件
c78ce9e
Raw
History Blame Contribute Delete
8.63 kB
# 数据服务类
import pandas as pd
import numpy as np
from typing import Dict, List, Any, Optional
import datetime
import logging
import io
from collections import OrderedDict # 导入 OrderedDict
class DataServiceMemory:
"""
数据服务类,负责获取和管理股票数据
"""
def __init__(self, config: Dict[str, Any] = None):
"""
初始化数据服务
Args:
config: 配置信息,包括数据源配置等
"""
self.config = config or {}
self.logger = logging.getLogger(__name__)
# 使用 OrderedDict 实现 LRU 缓存,存储数据
self.data_cache = OrderedDict()
self.stock_data = {}
self.factor_data = {}
self.backtest_results = {}
# 定义缓存最大大小
self.CACHE_MAX_SIZE = 100 # 缓存最大条目数,可根据实际需求调整
def get_stock_list(self) -> List[Dict[str, Any]]:
"""
获取股票列表,从API实时获取,不写入本地
Returns:
股票列表,包含股票代码、名称等信息
"""
# 实际项目中应从API实时获取
# 这里返回示例数据
return [
{"code": "000001.SZ", "name": "平安银行", "industry": "银行"},
{"code": "000002.SZ", "name": "万科A", "industry": "房地产"},
{"code": "000063.SZ", "name": "中兴通讯", "industry": "通信设备"},
{"code": "600036.SH", "name": "招商银行", "industry": "银行"},
{"code": "600519.SH", "name": "贵州茅台", "industry": "白酒"}
]
def get_daily_data(
self,
stock_codes: List[str],
start_date: str,
end_date: str) -> pd.DataFrame:
"""
获取日线数据,从API实时获取,并缓存
Args:
stock_codes: 股票代码列表
start_date: 开始日期,格式:YYYY-MM-DD
end_date: 结束日期,格式:YYYY-MM-DD
Returns:
日线数据DataFrame
"""
cache_key = f"{','.join(stock_codes)}_{start_date}_{end_date}"
# 检查内存缓存
if cache_key in self.data_cache:
self.logger.info(f"从缓存获取日线数据: {cache_key}")
# 将访问的键移动到 OrderedDict 的末尾,表示最近使用
self.data_cache.move_to_end(cache_key)
return self.data_cache[cache_key]
# 实际项目中应从API实时获取
# 这里生成示例数据
self.logger.info(f"从API获取日线数据: {stock_codes}, {start_date} - {end_date}")
# 生成日期范围
start = datetime.datetime.strptime(start_date, "%Y-%m-%d")
end = datetime.datetime.strptime(end_date, "%Y-%m-%d")
date_range = [
start +
datetime.timedelta(
days=x) for x in range(
(end -
start).days +
1)]
date_strings = [d.strftime("%Y-%m-%d") for d in date_range]
# 生成示例数据
data = []
for code in stock_codes:
base_price = np.random.randint(10, 100)
for date in date_strings:
price_change = np.random.normal(0, 1) * base_price * 0.01
open_price = base_price + price_change
close_price = open_price + np.random.normal(0, 1) * base_price * 0.005
high_price = max(open_price, close_price) + \
np.random.normal(0, 1) * base_price * 0.003
low_price = min(open_price, close_price) - \
np.random.normal(0, 1) * base_price * 0.003
volume = np.random.randint(1000000, 10000000)
data.append({
"code": code,
"date": date,
"open": open_price,
"high": high_price,
"low": low_price,
"close": close_price,
"volume": volume,
"amount": volume * close_price
})
base_price = close_price # 更新基准价格
# 创建DataFrame
df = pd.DataFrame(data)
# 存入内存缓存
self.data_cache[cache_key] = df
# 如果缓存超出最大大小,移除最旧的(即第一个)条目
if len(self.data_cache) > self.CACHE_MAX_SIZE:
oldest_key = next(iter(self.data_cache))
self.data_cache.popitem(last=False) # 移除最旧的条目
self.logger.info(f"缓存超出限制,移除最旧条目: {oldest_key}")
return df
def get_financial_data(
self,
stock_codes: List[str],
period: str = "latest") -> pd.DataFrame:
"""
获取财务数据,从API实时获取,并缓存
Args:
stock_codes: 股票代码列表
period: 财报期间,如 'latest', '20220331', '20211231' 等
Returns:
财务数据DataFrame
"""
cache_key = f"financial_{','.join(stock_codes)}_{period}"
# 检查内存缓存
if cache_key in self.data_cache:
self.logger.info(f"从缓存获取财务数据: {cache_key}")
# 将访问的键移动到 OrderedDict 的末尾,表示最近使用
self.data_cache.move_to_end(cache_key)
return self.data_cache[cache_key]
# 实际项目中应从API实时获取
# 这里生成示例数据
self.logger.info(f"从API获取财务数据: {stock_codes}, {period}")
# 生成示例数据
data = []
for code in stock_codes:
revenue = np.random.randint(1000000, 1000000000)
net_profit = revenue * np.random.uniform(0.05, 0.2)
total_assets = revenue * np.random.uniform(1, 5)
total_equity = total_assets * np.random.uniform(0.3, 0.7)
data.append({
"code": code,
"period": period,
"revenue": revenue,
"net_profit": net_profit,
"total_assets": total_assets,
"total_equity": total_equity,
"roe": net_profit / total_equity,
"roa": net_profit / total_assets,
"net_margin": net_profit / revenue,
"debt_ratio": (total_assets - total_equity) / total_assets
})
# 创建DataFrame
df = pd.DataFrame(data)
# 存入内存缓存
self.data_cache[cache_key] = df
# 如果缓存超出最大大小,移除最旧的(即第一个)条目
if len(self.data_cache) > self.CACHE_MAX_SIZE:
oldest_key = next(iter(self.data_cache))
self.data_cache.popitem(last=False) # 移除最旧的条目
self.logger.info(f"缓存超出限制,移除最旧条目: {oldest_key}")
return df
def save_backtest_result(self, strategy_id: str, result_data: Dict[str, Any]):
"""
保存回测结果
Args:
strategy_id: 策略ID
result_data: 回测结果数据
"""
self.backtest_results[strategy_id] = result_data
self.logger.info(f"回测结果已保存: {strategy_id}")
def get_backtest_result(self, strategy_id: str) -> Optional[Dict[str, Any]]:
"""
从缓存获取回测结果
Args:
strategy_id: 策略ID
Returns:
回测结果数据,如果不存在则返回None
"""
return self.backtest_results.get(strategy_id)
def clear_cache(self):
"""
清除内存缓存
"""
self.data_cache.clear()
self.logger.info("缓存已清除")
def export_data(self, data: pd.DataFrame, format: str = "csv") -> bytes:
"""
导出数据为字节流
Args:
data: 要导出的数据
format: 导出格式,支持 'csv', 'excel', 'json'
Returns:
字节数据
"""
buffer = io.BytesIO()
if format.lower() == "csv":
data.to_csv(buffer, index=False, encoding="utf-8")
elif format.lower() == "excel":
data.to_excel(buffer, index=False, engine="openpyxl")
elif format.lower() == "json":
buffer.write(data.to_json(orient="records").encode("utf-8"))
else:
raise ValueError(f"不支持的导出格式: {format}")
buffer.seek(0)
return buffer.getvalue()