This commit is contained in:
liao 2025-05-23 10:19:48 +08:00
parent 8f73099e18
commit 03450116ce
5 changed files with 130 additions and 35 deletions

View File

@ -241,7 +241,7 @@ def initialize_stock_price_schedule():
scheduler.add_job( scheduler.add_job(
func=update_stock_price, func=update_stock_price,
trigger='interval', trigger='interval',
minutes=5, minutes=60,
id='stock_price_update', id='stock_price_update',
name='实时股价数据采集', name='实时股价数据采集',
replace_existing=True replace_existing=True
@ -249,7 +249,7 @@ def initialize_stock_price_schedule():
# 启动调度器 # 启动调度器
scheduler.start() scheduler.start()
logger.info("实时股价数据采集定时任务已初始化,将在交易时间内每5分钟执行一次") logger.info("实时股价数据采集定时任务已初始化,将在交易时间内每60分钟执行一次")
return scheduler return scheduler
except Exception as e: except Exception as e:
@ -1452,6 +1452,22 @@ def comprehensive_analysis():
if 'db_session2' in locals() and db_session2 is not None: # 确保 db_session 已定义 if 'db_session2' in locals() and db_session2 is not None: # 确保 db_session 已定义
db_session2.close() # <--- 关闭会话 db_session2.close() # <--- 关闭会话
# 获取企业市值信息
market_value_results = {}
try:
from src.valuation_analysis.stock_price_collector import StockPriceCollector
price_collector = StockPriceCollector()
for stock_code in input_stock_codes:
price_data = price_collector.get_stock_price_data(stock_code)
if price_data and 'total_market_value' in price_data:
market_value_results[stock_code] = price_data['total_market_value']
else:
market_value_results[stock_code] = None
except Exception as e:
logger.error(f"获取企业市值信息失败: {str(e)}")
market_value_results = {}
db_session = next(get_db()) db_session = next(get_db())
# 筛选出传入列表中符合条件的股票 # 筛选出传入列表中符合条件的股票
for code, name in all_stocks: for code, name in all_stocks:
@ -1475,7 +1491,8 @@ def comprehensive_analysis():
"industry_space": industry_space, # 行业发展空间2:高速增长, 1:稳定经营, 0:不确定性大, -1:不利经营) "industry_space": industry_space, # 行业发展空间2:高速增长, 1:稳定经营, 0:不确定性大, -1:不利经营)
"financial_report_level": financial_report_level, # 经营质量2:优秀, 1:较好, 0:一般, -1:存在隐患,-2较大隐患 "financial_report_level": financial_report_level, # 经营质量2:优秀, 1:较好, 0:一般, -1:存在隐患,-2较大隐患
"pe_industry": pe_industry, # 个股在行业的PE水平-1:高于行业, 0:接近行业, 1:低于行业) "pe_industry": pe_industry, # 个股在行业的PE水平-1:高于行业, 0:接近行业, 1:低于行业)
"tracks": track_results.get(code, []) # 添加赛道信息 "tracks": track_results.get(code, []), # 添加赛道信息
"market_value": market_value_results.get(code) # 添加企业市值信息
}) })
logger.info(f"筛选出 {len(filtered_stocks)} 个符合条件的股票") logger.info(f"筛选出 {len(filtered_stocks)} 个符合条件的股票")

View File

@ -1477,6 +1477,13 @@ class FundamentalAnalyzer:
- 长期持有公司具备长期稳定的盈利能力行业地位稳固长期成长性好 - 长期持有公司具备长期稳定的盈利能力行业地位稳固长期成长性好
- 不建议投资存在明显风险因素基本面恶化估值过高行业前景不佳或者存在退市风险 - 不建议投资存在明显风险因素基本面恶化估值过高行业前景不佳或者存在退市风险
请注意
1. 请完全基于提供的分析结果中的最新数据进行分析不要使用任何历史数据或过时信息
2. 如果分析结果中包含2024年或2025年的数据请优先使用这些最新数据
3. 避免使用"2023年"等历史时间点的数据除非分析结果中明确提供了这些数据
4. 重点关注公司最新的业务发展财务表现和市场定位
5. 在分析行业环境时请使用最新的行业数据和竞争格局信息
请提供专业客观的分析突出关键信息避免冗长描述重点关注投资价值和风险在输出投资建议时请明确指出是短期持有中期持有长期持有还是不建议投资 请提供专业客观的分析突出关键信息避免冗长描述重点关注投资价值和风险在输出投资建议时请明确指出是短期持有中期持有长期持有还是不建议投资
各维度分析结果 各维度分析结果

View File

@ -11,7 +11,7 @@ XUEQIU_HEADERS = {
'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept-Encoding': 'gzip, deflate, br, zstd',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Client-Version': 'v2.44.75', 'Client-Version': 'v2.44.75',
'Cookie': 'cookiesu=811743062689927; device_id=33fa3c7fca4a65f8f4354e10ed6b7470; HMACCOUNT=8B64A2E3C307C8C0; s=c611ttmqlj; xq_is_login=1; u=8493411634; bid=4065a77ca57a69c83405d6e591ab5449_m8r2nhs8; Hm_lvt_1db88642e346389874251b5a1eded6e3=1746410725; xq_a_token=660fb18cf1d15162da76deedc46b649370124dca; xqat=660fb18cf1d15162da76deedc46b649370124dca; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOjg0OTM0MTE2MzQsImlzcyI6InVjIiwiZXhwIjoxNzQ5ODYxNjY5LCJjdG0iOjE3NDcyNjk2Njk0NDgsImNpZCI6ImQ5ZDBuNEFadXAifQ.jc_E9qvguLwBDASn1Z-KjGtU89pNJRwJq_hIaiR3r2re7-_xiXH8qhuhC3Se8rlfKGZ8sHsb3rSND_vnF7yMp90QQHdK_brSmlgd6_ltHmJfWSFNJvMk7F3s0yPjcpeMqeUTPFnZwKmoWwZVKEwdVBN8f25z6e9M2JjtSTZ2huADH_FdEn1rb9IU-H35z_MLWW1M7vB5xc2rh57yFIBnQoxu9OLfeETpeIpASP1UBeZXoQZ_v1gIWiFYItwuudIz0tPYzB-o2duRe31G0S_hNvEGl3HH4M5FjTyaPAq2PRuiZCyRF-25gHXBZnLcxyavZ1VAURfHng_377_IJNSXsw; xq_r_token=8a5dec9c93caf88d0e1f98f1d23ea1bb60eb6225; is_overseas=0; Hm_lpvt_1db88642e346389874251b5a1eded6e3=1747356850; ssxmod_itna=eqGxBDnGKYuxcD4kDRgxYq7ueYKS8DBP01Dp2xQyP08D60DB40QuHhqDyGGdVmpmghQehYtDDsqze4GzDiLPGhDBWAFdYCdqt4NKWooqCWKCwdUme9Ill25QAClcymm=0Iil4OAe8oGLDY=DCTKK420iDYAEDBYD74G+DDeDiO3Dj4GmDGY=aeDFIQutVCRKdxDwDB=DmqG23ObDm4DfDDLorBD4Il2YDDtDAkaGNPDADA3doDDlYD84edb4DYpogQ0FdgahphuXIeDMixGXzAlzx9CnoiWtV/LfNf2aHPGuDG=OcC0Hh2bmRT3f8hGxYBY5QeOhx+BxorKq0DW7HRYqexx=CD=WKK7oQ7YBGxPG4KiKy7hAQd5dpOodYYrcqsMkbZMshieygdyhxogYO2deGd46DAQ5MA5VBxiT5/h4WB++l=Eet4D; ssxmod_itna2=eqGxBDnGKYuxcD4kDRgxYq7ueYKS8DBP01Dp2xQyP08D60DB40QuHhqDyGGdVmpmghQehY4Dfie4pCoTp35CT5NsKziGGtvkoYD', 'Cookie': 'cookiesu=811743062689927; device_id=33fa3c7fca4a65f8f4354e10ed6b7470; HMACCOUNT=8B64A2E3C307C8C0; s=c611ttmqlj; xq_is_login=1; u=8493411634; bid=4065a77ca57a69c83405d6e591ab5449_m8r2nhs8; Hm_lvt_1db88642e346389874251b5a1eded6e3=1746410725; xq_a_token=660fb18cf1d15162da76deedc46b649370124dca; xqat=660fb18cf1d15162da76deedc46b649370124dca; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOjg0OTM0MTE2MzQsImlzcyI6InVjIiwiZXhwIjoxNzQ5ODYxNjY5LCJjdG0iOjE3NDcyNjk2Njk0NDgsImNpZCI6ImQ5ZDBuNEFadXAifQ.jc_E9qvguLwBDASn1Z-KjGtU89pNJRwJq_hIaiR3r2re7-_xiXH8qhuhC3Se8rlfKGZ8sHsb3rSND_vnF7yMp90QQHdK_brSmlgd6_ltHmJfWSFNJvMk7F3s0yPjcpeMqeUTPFnZwKmoWwZVKEwdVBN8f25z6e9M2JjtSTZ2huADH_FdEn1rb9IU-H35z_MLWW1M7vB5xc2rh57yFIBnQoxu9OLfeETpeIpASP1UBeZXoQZ_v1gIWiFYItwuudIz0tPYzB-o2duRe31G0S_hNvEGl3HH4M5FjTyaPAq2PRuiZCyRF-25gHXBZnLcxyavZ1VAURfHng_377_IJNSXsw; xq_r_token=8a5dec9c93caf88d0e1f98f1d23ea1bb60eb6225; snbim_minify=true; is_overseas=0; Hm_lpvt_1db88642e346389874251b5a1eded6e3=1747905410; ssxmod_itna=eqGxBDnGKYuxcD4kDRgxYq7ueYKS8DBP01Dp2xQyP08D60DB40QuHhqDyGGTrlGiGbtOh01qDsqze4GzDiLPGhDBWAFdYCdqtsqfmmxXxyB+doh6odserKO5sg=EiqfqztqpiexCPGnD0=O77N4xYAEDBYD74G+DDeDiO3Dj4GmDGYd=eDFzjRQyl2edxDwDB=DmqG23grDm4DfDDL5xRD4zC2YDDtDAMWz5PDADA3ooDDlYGO44Lr4DYp52nXWdOaspxTXzeDMixGXzYlCgaCRo0TQy9LAN32TNPGuDG=H6e0ahrbicn0AP4KGGwQ0imPKY+5meOQDqixGYwQGGiGGetGe3qqjeKYw10G4ixqim2mpbK+h1iaIPeQAieNS1X5pXZP4rQ04Iv4zmQWvplG40P4Gw4CqRjwzlwGjPwlD3iho+qKlD4hi3YD; ssxmod_itna2=eqGxBDnGKYuxcD4kDRgxYq7ueYKS8DBP01Dp2xQyP08D60DB40QuHhqDyGGTrlGiGbtOh0P4DWhYebouIdHtBItz/DboqtwisfWD',
'Referer': 'https://weibo.com/u/7735765253', 'Referer': 'https://weibo.com/u/7735765253',
'Sec-Ch-Ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"', 'Sec-Ch-Ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
'Sec-Ch-Ua-Mobile': '?0', 'Sec-Ch-Ua-Mobile': '?0',

View File

@ -11,6 +11,7 @@ from pymongo import MongoClient
import logging import logging
from typing import Dict, List, Optional, Union, Tuple from typing import Dict, List, Optional, Union, Tuple
import json import json
import requests
from .config import DB_URL, MONGO_CONFIG, LOG_FILE from .config import DB_URL, MONGO_CONFIG, LOG_FILE
from .stock_price_collector import StockPriceCollector from .stock_price_collector import StockPriceCollector
@ -394,6 +395,69 @@ class FinancialAnalyzer:
'message': f'查询失败: {str(e)}' 'message': f'查询失败: {str(e)}'
} }
def get_momentum_indicators(self, stock_code: str, industry_codes: List[str]) -> Dict:
"""
获取动量指标数据
Args:
stock_code: 目标股票代码
industry_codes: 行业股票代码列表
Returns:
动量指标数据字典
"""
try:
url = "http://192.168.18.42:5000/api/dify/getStockMomentumIndex"
payload = {
"code_list": industry_codes,
"target_code": stock_code
}
response = requests.post(url, json=payload)
if response.status_code != 200:
return {
'success': False,
'message': f'获取动量指标失败: HTTP {response.status_code}'
}
data = response.json()
# 计算OBV和NATR的rank_score
obv_rank_score = round((1 - data['obv_rank'] / len(industry_codes)) * 10, 3)
natr_rank_score = round((1 - data['natr_rank'] / len(industry_codes)) * 10, 3)
return {
'success': True,
'indicators': [
{
'key': 'obv',
'desc': '能量',
'value': round(data['OBV'], 3),
'rank_score': obv_rank_score
},
{
'key': 'form',
'desc': f'技术形态-{data["form"]}',
'value': round(data['form_probability'], 3),
'rank_score': round(data['form_probability'] * 10, 3) # 将概率转换为0-10的分数
},
{
'key': 'natr',
'desc': '阶段位置',
'value': round(data['NATR'], 3),
'rank_score': natr_rank_score
}
],
'avg_score': round((obv_rank_score + natr_rank_score + round(data['form_probability'] * 10, 3)) / 3, 3)
}
except Exception as e:
logger.error(f"获取动量指标失败: {str(e)}")
return {
'success': False,
'message': f'获取动量指标失败: {str(e)}'
}
def analyze_financial_data(self, stock_code: str) -> Dict: def analyze_financial_data(self, stock_code: str) -> Dict:
""" """
分析财务数据 分析财务数据
@ -413,6 +477,12 @@ class FinancialAnalyzer:
industry_analyzer = IndustryAnalyzer() industry_analyzer = IndustryAnalyzer()
concepts = industry_analyzer.get_stock_concepts(stock_code) concepts = industry_analyzer.get_stock_concepts(stock_code)
# 获取同行业股票列表
industry_stocks = self.get_industry_stocks(stock_code)
# 获取动量指标数据
momentum_result = self.get_momentum_indicators(stock_code, industry_stocks)
# 获取基础财务指标 # 获取基础财务指标
base_result = self.extract_financial_indicators(stock_code) base_result = self.extract_financial_indicators(stock_code)
if not base_result.get('success'): if not base_result.get('success'):
@ -578,6 +648,7 @@ class FinancialAnalyzer:
'growth': growth_data, 'growth': growth_data,
'value_rating': process_indicators(value_rating_indicators), 'value_rating': process_indicators(value_rating_indicators),
'liquidity': process_indicators(liquidity_indicators), 'liquidity': process_indicators(liquidity_indicators),
'momentum': momentum_result.get('indicators', []), # 添加动量指标数据
'concepts': concepts, # 添加概念板块数据 'concepts': concepts, # 添加概念板块数据
'price_data': price_data # 添加实时股价数据 'price_data': price_data # 添加实时股价数据
} }