update
This commit is contained in:
parent
fcb9e8d659
commit
96e8eddea5
@ -175,7 +175,7 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
# 股票智能体配置
|
# 股票智能体配置
|
||||||
stock_symbols_us: str = "" # 美股代码,逗号分隔
|
stock_symbols_us: str = "" # 美股代码,逗号分隔
|
||||||
# 港股代码:科技+新能源+芯片+AI+金融+汽车+医药+消费+能源
|
# 港股代码:科技+新能源+芯片+AI+金融+汽车+医药+消费+能源(统一格式:去掉前导零)
|
||||||
# 科技:腾讯控股/阿里巴巴/美团/小米集团/京东集团/网易/百度/快手/知乎/B站
|
# 科技:腾讯控股/阿里巴巴/美团/小米集团/京东集团/网易/百度/快手/知乎/B站
|
||||||
# 新能源:比亚迪/理想汽车/小鹏汽车/赣锋锂业/龙源电力/信义能源
|
# 新能源:比亚迪/理想汽车/小鹏汽车/赣锋锂业/龙源电力/信义能源
|
||||||
# 芯片:中芯国际/华虹半导体/上海复旦
|
# 芯片:中芯国际/华虹半导体/上海复旦
|
||||||
@ -185,7 +185,7 @@ class Settings(BaseSettings):
|
|||||||
# 医药:药明康德/药明生物/百济神州/信达生物/石药集团
|
# 医药:药明康德/药明生物/百济神州/信达生物/石药集团
|
||||||
# 消费:名创优品/泡泡玛特/安踏体育
|
# 消费:名创优品/泡泡玛特/安踏体育
|
||||||
# 能源:中海油/中石油/中国神华
|
# 能源:中海油/中石油/中国神华
|
||||||
stock_symbols_hk: str = "00700.HK,09988.HK,03690.HK,01810.HK,09618.HK,09999.HK,09888.HK,01024.HK,02390.HK,09626.HK,01211.HK,02015.HK,09868.HK,01772.HK,00916.HK,03868.HK,00981.HK,01347.HK,01385.HK,00020.HK,06682.HK,02121.HK,01357.HK,09959.HK,06608.HK,00005.HK,00939.HK,01398.HK,01288.HK,03988.HK,01299.HK,02318.HK,02628.HK,03908.HK,06030.HK,09866.HK,02333.HK,00175.HK,02359.HK,02269.HK,06160.HK,01801.HK,01093.HK,09896.HK,09992.HK,02020.HK,00883.HK,00857.HK,01088.HK"
|
stock_symbols_hk: str = "700.HK,9988.HK,3690.HK,1810.HK,9618.HK,9999.HK,9888.HK,1024.HK,2390.HK,9626.HK,1211.HK,2015.HK,9868.HK,1772.HK,916.HK,3868.HK,981.HK,1347.HK,1385.HK,20.HK,6682.HK,2121.HK,1357.HK,9959.HK,6608.HK,5.HK,939.HK,1398.HK,1288.HK,3988.HK,1299.HK,2318.HK,2628.HK,3908.HK,6030.HK,9866.HK,2333.HK,175.HK,2359.HK,2269.HK,6160.HK,1801.HK,1093.HK,9896.HK,9992.HK,2020.HK,883.HK,857.HK,1088.HK"
|
||||||
stock_analysis_interval: int = 300 # 分析间隔(秒,默认5分钟)
|
stock_analysis_interval: int = 300 # 分析间隔(秒,默认5分钟)
|
||||||
stock_llm_threshold: float = 0.70 # 触发 LLM 分析的置信度阈值
|
stock_llm_threshold: float = 0.70 # 触发 LLM 分析的置信度阈值
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,33 @@ class FundamentalService:
|
|||||||
|
|
||||||
logger.info("基本面数据服务初始化成功")
|
logger.info("基本面数据服务初始化成功")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _normalize_hk_symbol(symbol: str) -> str:
|
||||||
|
"""
|
||||||
|
标准化港股代码格式为 yfinance 要求的格式
|
||||||
|
- 4位及以下:左侧补零到4位,如 700.HK → 0700.HK, 5.HK → 0005.HK
|
||||||
|
- 5位及以上:去掉前导零,如 09618.HK → 9618.HK
|
||||||
|
"""
|
||||||
|
if not symbol.endswith('.HK'):
|
||||||
|
return symbol
|
||||||
|
|
||||||
|
# 分离代码和后缀
|
||||||
|
code_part = symbol[:-3] # 去掉 .HK
|
||||||
|
suffix = '.HK'
|
||||||
|
|
||||||
|
# 如果是纯数字代码
|
||||||
|
if code_part.isdigit():
|
||||||
|
# 4位及以下:补零到4位
|
||||||
|
if len(code_part) <= 4:
|
||||||
|
normalized_code = code_part.zfill(4)
|
||||||
|
# 5位及以上:去掉前导零
|
||||||
|
else:
|
||||||
|
normalized_code = code_part.lstrip('0') or '0'
|
||||||
|
else:
|
||||||
|
normalized_code = code_part
|
||||||
|
|
||||||
|
return normalized_code + suffix
|
||||||
|
|
||||||
def get_fundamental_data(self, symbol: str) -> Optional[Dict[str, Any]]:
|
def get_fundamental_data(self, symbol: str) -> Optional[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取股票的基本面数据
|
获取股票的基本面数据
|
||||||
@ -44,7 +71,10 @@ class FundamentalService:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ticker = yf.Ticker(symbol)
|
# 标准化港股代码格式
|
||||||
|
normalized_symbol = self._normalize_hk_symbol(symbol)
|
||||||
|
|
||||||
|
ticker = yf.Ticker(normalized_symbol)
|
||||||
|
|
||||||
# 获取股票信息
|
# 获取股票信息
|
||||||
info = ticker.info
|
info = ticker.info
|
||||||
|
|||||||
@ -9,24 +9,54 @@ from app.utils.logger import logger
|
|||||||
|
|
||||||
|
|
||||||
class USStockService:
|
class USStockService:
|
||||||
"""美股数据服务类"""
|
"""美股数据服务类(支持美股和港股)"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""初始化美股数据服务"""
|
"""初始化美股数据服务"""
|
||||||
self.cache = {} # 简单的内存缓存
|
self.cache = {} # 简单的内存缓存
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _normalize_hk_symbol(symbol: str) -> str:
|
||||||
|
"""
|
||||||
|
标准化港股代码格式为 yfinance 要求的格式
|
||||||
|
- 4位及以下:左侧补零到4位,如 700.HK → 0700.HK, 5.HK → 0005.HK
|
||||||
|
- 5位及以上:去掉前导零,如 09618.HK → 9618.HK
|
||||||
|
"""
|
||||||
|
if not symbol.endswith('.HK'):
|
||||||
|
return symbol
|
||||||
|
|
||||||
|
# 分离代码和后缀
|
||||||
|
code_part = symbol[:-3] # 去掉 .HK
|
||||||
|
suffix = '.HK'
|
||||||
|
|
||||||
|
# 如果是纯数字代码
|
||||||
|
if code_part.isdigit():
|
||||||
|
# 4位及以下:补零到4位
|
||||||
|
if len(code_part) <= 4:
|
||||||
|
normalized_code = code_part.zfill(4)
|
||||||
|
# 5位及以上:去掉前导零
|
||||||
|
else:
|
||||||
|
normalized_code = code_part.lstrip('0') or '0'
|
||||||
|
else:
|
||||||
|
normalized_code = code_part
|
||||||
|
|
||||||
|
return normalized_code + suffix
|
||||||
|
|
||||||
def get_stock_info(self, symbol: str) -> Optional[Dict[str, Any]]:
|
def get_stock_info(self, symbol: str) -> Optional[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
获取美股基本信息
|
获取美股基本信息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
symbol: 股票代码(如 AAPL, TSLA)
|
symbol: 股票代码(如 AAPL, TSLA 或 0700.HK)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
股票基本信息字典
|
股票基本信息字典
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
stock = yf.Ticker(symbol)
|
# 标准化港股代码格式
|
||||||
|
normalized_symbol = self._normalize_hk_symbol(symbol)
|
||||||
|
|
||||||
|
stock = yf.Ticker(normalized_symbol)
|
||||||
info = stock.info
|
info = stock.info
|
||||||
|
|
||||||
if not info or 'symbol' not in info:
|
if not info or 'symbol' not in info:
|
||||||
@ -85,7 +115,10 @@ class USStockService:
|
|||||||
包含OHLCV数据的DataFrame
|
包含OHLCV数据的DataFrame
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
stock = yf.Ticker(symbol)
|
# 标准化港股代码格式
|
||||||
|
normalized_symbol = self._normalize_hk_symbol(symbol)
|
||||||
|
|
||||||
|
stock = yf.Ticker(normalized_symbol)
|
||||||
hist = stock.history(period=period, interval=interval)
|
hist = stock.history(period=period, interval=interval)
|
||||||
|
|
||||||
if hist.empty:
|
if hist.empty:
|
||||||
@ -110,7 +143,10 @@ class USStockService:
|
|||||||
财务数据字典
|
财务数据字典
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
stock = yf.Ticker(symbol)
|
# 标准化港股代码格式
|
||||||
|
normalized_symbol = self._normalize_hk_symbol(symbol)
|
||||||
|
|
||||||
|
stock = yf.Ticker(normalized_symbol)
|
||||||
|
|
||||||
# 获取财务报表
|
# 获取财务报表
|
||||||
financials = stock.financials
|
financials = stock.financials
|
||||||
|
|||||||
@ -25,18 +25,47 @@ class YFinanceService:
|
|||||||
logger.error("yfinance 未安装,请运行: pip install yfinance")
|
logger.error("yfinance 未安装,请运行: pip install yfinance")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def _normalize_hk_symbol(self, symbol: str) -> str:
|
||||||
|
"""
|
||||||
|
标准化港股代码格式为 yfinance 要求的格式
|
||||||
|
- 4位及以下:左侧补零到4位,如 700.HK → 0700.HK, 5.HK → 0005.HK
|
||||||
|
- 5位及以上:去掉前导零,如 09618.HK → 9618.HK
|
||||||
|
"""
|
||||||
|
if not symbol.endswith('.HK'):
|
||||||
|
return symbol
|
||||||
|
|
||||||
|
# 分离代码和后缀
|
||||||
|
code_part = symbol[:-3] # 去掉 .HK
|
||||||
|
suffix = '.HK'
|
||||||
|
|
||||||
|
# 如果是纯数字代码
|
||||||
|
if code_part.isdigit():
|
||||||
|
# 4位及以下:补零到4位
|
||||||
|
if len(code_part) <= 4:
|
||||||
|
normalized_code = code_part.zfill(4)
|
||||||
|
# 5位及以上:去掉前导零
|
||||||
|
else:
|
||||||
|
normalized_code = code_part.lstrip('0') or '0'
|
||||||
|
else:
|
||||||
|
normalized_code = code_part
|
||||||
|
|
||||||
|
return normalized_code + suffix
|
||||||
|
|
||||||
def get_ticker(self, symbol: str) -> Optional[Dict]:
|
def get_ticker(self, symbol: str) -> Optional[Dict]:
|
||||||
"""
|
"""
|
||||||
获取股票实时行情
|
获取股票实时行情
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
symbol: 股票代码,如 'AAPL'
|
symbol: 股票代码,如 'AAPL' 或 '0700.HK'
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
行情数据字典
|
行情数据字典
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
ticker = self.yf.Ticker(symbol)
|
# 标准化港股代码格式
|
||||||
|
normalized_symbol = self._normalize_hk_symbol(symbol)
|
||||||
|
|
||||||
|
ticker = self.yf.Ticker(normalized_symbol)
|
||||||
|
|
||||||
# 使用 history 方法获取数据(更可靠,避免 429 错误)
|
# 使用 history 方法获取数据(更可靠,避免 429 错误)
|
||||||
hist = ticker.history(period="2d", interval="1h")
|
hist = ticker.history(period="2d", interval="1h")
|
||||||
@ -112,7 +141,9 @@ class YFinanceService:
|
|||||||
period: str
|
period: str
|
||||||
) -> Optional[pd.DataFrame]:
|
) -> Optional[pd.DataFrame]:
|
||||||
"""获取带缓存的数据"""
|
"""获取带缓存的数据"""
|
||||||
cache_key = f"{symbol}_{interval}_{period}"
|
# 标准化港股代码格式
|
||||||
|
normalized_symbol = self._normalize_hk_symbol(symbol)
|
||||||
|
cache_key = f"{normalized_symbol}_{interval}_{period}"
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
|
|
||||||
# 检查缓存
|
# 检查缓存
|
||||||
@ -124,7 +155,7 @@ class YFinanceService:
|
|||||||
|
|
||||||
# 获取新数据
|
# 获取新数据
|
||||||
try:
|
try:
|
||||||
ticker = self.yf.Ticker(symbol)
|
ticker = self.yf.Ticker(normalized_symbol)
|
||||||
df = ticker.history(period=period, interval=interval)
|
df = ticker.history(period=period, interval=interval)
|
||||||
|
|
||||||
if df.empty:
|
if df.empty:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user