update pay ui
This commit is contained in:
Binary file not shown.
500
app_vx.py
500
app_vx.py
@@ -5381,6 +5381,114 @@ def get_comment_replies(comment_id):
|
|||||||
}), 500
|
}), 500
|
||||||
|
|
||||||
|
|
||||||
|
# 工具函数:解析JSON字段
|
||||||
|
def parse_json_field(field_value):
|
||||||
|
"""解析JSON字段"""
|
||||||
|
if not field_value:
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
if isinstance(field_value, str):
|
||||||
|
if field_value.startswith('['):
|
||||||
|
return json.loads(field_value)
|
||||||
|
else:
|
||||||
|
return field_value.split(',')
|
||||||
|
else:
|
||||||
|
return field_value
|
||||||
|
except:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
# 工具函数:获取 future_events 表字段值,支持新旧字段回退
|
||||||
|
def get_future_event_field(row, new_field, old_field):
|
||||||
|
"""
|
||||||
|
获取 future_events 表字段值,支持新旧字段回退
|
||||||
|
如果新字段存在且不为空,使用新字段;否则使用旧字段
|
||||||
|
"""
|
||||||
|
new_value = getattr(row, new_field, None) if hasattr(row, new_field) else None
|
||||||
|
old_value = getattr(row, old_field, None) if hasattr(row, old_field) else None
|
||||||
|
|
||||||
|
# 如果新字段有值(不为空字符串),使用新字段
|
||||||
|
if new_value is not None and str(new_value).strip():
|
||||||
|
return new_value
|
||||||
|
return old_value
|
||||||
|
|
||||||
|
|
||||||
|
# 工具函数:解析新的 best_matches 数据结构(含研报引用信息)
|
||||||
|
def parse_best_matches(best_matches_value):
|
||||||
|
"""
|
||||||
|
解析新的 best_matches 数据结构(含研报引用信息)
|
||||||
|
|
||||||
|
新结构示例:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"stock_code": "300451.SZ",
|
||||||
|
"company_name": "创业慧康",
|
||||||
|
"original_description": "核心标的,医疗信息化...",
|
||||||
|
"best_report_title": "报告标题",
|
||||||
|
"best_report_author": "作者",
|
||||||
|
"best_report_sentences": "相关内容",
|
||||||
|
"best_report_match_score": "好",
|
||||||
|
"best_report_match_ratio": 0.9285714285714286,
|
||||||
|
"best_report_declare_date": "2023-04-25T00:00:00",
|
||||||
|
"total_reports": 9,
|
||||||
|
"high_score_reports": 6
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
返回统一格式的股票列表,兼容旧格式
|
||||||
|
"""
|
||||||
|
if not best_matches_value:
|
||||||
|
return []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 解析 JSON
|
||||||
|
if isinstance(best_matches_value, str):
|
||||||
|
data = json.loads(best_matches_value)
|
||||||
|
else:
|
||||||
|
data = best_matches_value
|
||||||
|
|
||||||
|
if not isinstance(data, list):
|
||||||
|
return []
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for item in data:
|
||||||
|
if isinstance(item, dict):
|
||||||
|
# 新结构:包含研报信息的字典
|
||||||
|
stock_info = {
|
||||||
|
'code': item.get('stock_code', ''),
|
||||||
|
'name': item.get('company_name', ''),
|
||||||
|
'description': item.get('original_description', ''),
|
||||||
|
'score': item.get('best_report_match_ratio', 0),
|
||||||
|
# 研报引用信息
|
||||||
|
'report': {
|
||||||
|
'title': item.get('best_report_title', ''),
|
||||||
|
'author': item.get('best_report_author', ''),
|
||||||
|
'sentences': item.get('best_report_sentences', ''),
|
||||||
|
'match_score': item.get('best_report_match_score', ''),
|
||||||
|
'match_ratio': item.get('best_report_match_ratio', 0),
|
||||||
|
'declare_date': item.get('best_report_declare_date', ''),
|
||||||
|
'total_reports': item.get('total_reports', 0),
|
||||||
|
'high_score_reports': item.get('high_score_reports', 0)
|
||||||
|
} if item.get('best_report_title') else None
|
||||||
|
}
|
||||||
|
result.append(stock_info)
|
||||||
|
elif isinstance(item, (list, tuple)) and len(item) >= 2:
|
||||||
|
# 旧结构:[code, name, description, score]
|
||||||
|
result.append({
|
||||||
|
'code': item[0],
|
||||||
|
'name': item[1],
|
||||||
|
'description': item[2] if len(item) > 2 else '',
|
||||||
|
'score': item[3] if len(item) > 3 else 0,
|
||||||
|
'report': None
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
print(f"parse_best_matches error: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
# 工具函数:处理转义字符,保留 Markdown 格式
|
# 工具函数:处理转义字符,保留 Markdown 格式
|
||||||
def unescape_markdown_text(text):
|
def unescape_markdown_text(text):
|
||||||
"""
|
"""
|
||||||
@@ -5470,6 +5578,7 @@ def api_calendar_events():
|
|||||||
offset = (page - 1) * per_page
|
offset = (page - 1) * per_page
|
||||||
|
|
||||||
# 构建基础查询 - 使用 future_events 表
|
# 构建基础查询 - 使用 future_events 表
|
||||||
|
# 添加新字段 second_modified_text, `second_modified_text.1`, best_matches 支持新旧回退
|
||||||
query = """
|
query = """
|
||||||
SELECT data_id, \
|
SELECT data_id, \
|
||||||
calendar_time, \
|
calendar_time, \
|
||||||
@@ -5481,7 +5590,10 @@ def api_calendar_events():
|
|||||||
fact, \
|
fact, \
|
||||||
related_stocks, \
|
related_stocks, \
|
||||||
concepts, \
|
concepts, \
|
||||||
inferred_tag
|
inferred_tag, \
|
||||||
|
second_modified_text, \
|
||||||
|
`second_modified_text.1` as second_modified_text_1, \
|
||||||
|
best_matches
|
||||||
FROM future_events
|
FROM future_events
|
||||||
WHERE 1 = 1 \
|
WHERE 1 = 1 \
|
||||||
"""
|
"""
|
||||||
@@ -5552,90 +5664,114 @@ def api_calendar_events():
|
|||||||
|
|
||||||
events_data = []
|
events_data = []
|
||||||
for event in events:
|
for event in events:
|
||||||
# 解析相关股票
|
# 使用新字段回退机制获取 former 和 forecast
|
||||||
|
# second_modified_text -> former
|
||||||
|
former_value = get_future_event_field(event, 'second_modified_text', 'former')
|
||||||
|
# second_modified_text.1 -> forecast
|
||||||
|
forecast_new = getattr(event, 'second_modified_text_1', None)
|
||||||
|
forecast_value = forecast_new if (forecast_new and str(forecast_new).strip()) else getattr(event, 'forecast', None)
|
||||||
|
|
||||||
|
# 解析相关股票 - 优先使用 best_matches,回退到 related_stocks
|
||||||
related_stocks_list = []
|
related_stocks_list = []
|
||||||
related_avg_chg = 0
|
related_avg_chg = 0
|
||||||
related_max_chg = 0
|
related_max_chg = 0
|
||||||
related_week_chg = 0
|
related_week_chg = 0
|
||||||
|
|
||||||
# 处理相关股票数据
|
# 优先使用 best_matches(新结构,含研报引用)
|
||||||
if event.related_stocks:
|
best_matches = getattr(event, 'best_matches', None)
|
||||||
|
if best_matches and str(best_matches).strip():
|
||||||
|
# 使用新的 parse_best_matches 函数解析
|
||||||
|
parsed_stocks = parse_best_matches(best_matches)
|
||||||
|
else:
|
||||||
|
# 回退到旧的 related_stocks 处理
|
||||||
|
parsed_stocks = []
|
||||||
|
if event.related_stocks:
|
||||||
|
try:
|
||||||
|
import ast
|
||||||
|
if isinstance(event.related_stocks, str):
|
||||||
|
try:
|
||||||
|
stock_data = json.loads(event.related_stocks)
|
||||||
|
except:
|
||||||
|
stock_data = ast.literal_eval(event.related_stocks)
|
||||||
|
else:
|
||||||
|
stock_data = event.related_stocks
|
||||||
|
|
||||||
|
if stock_data:
|
||||||
|
for stock_info in stock_data:
|
||||||
|
if isinstance(stock_info, list) and len(stock_info) >= 2:
|
||||||
|
parsed_stocks.append({
|
||||||
|
'code': stock_info[0],
|
||||||
|
'name': stock_info[1],
|
||||||
|
'description': stock_info[2] if len(stock_info) > 2 else '',
|
||||||
|
'score': stock_info[3] if len(stock_info) > 3 else 0,
|
||||||
|
'report': None
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error parsing related_stocks for event {event.data_id}: {e}")
|
||||||
|
|
||||||
|
# 处理解析后的股票数据,获取交易信息
|
||||||
|
if parsed_stocks:
|
||||||
try:
|
try:
|
||||||
import json
|
daily_changes = []
|
||||||
import ast
|
week_changes = []
|
||||||
|
|
||||||
# 使用与detail接口相同的解析逻辑
|
for stock_info in parsed_stocks:
|
||||||
if isinstance(event.related_stocks, str):
|
stock_code = stock_info.get('code', '')
|
||||||
try:
|
stock_name = stock_info.get('name', '')
|
||||||
stock_data = json.loads(event.related_stocks)
|
description = stock_info.get('description', '')
|
||||||
except:
|
score = stock_info.get('score', 0)
|
||||||
stock_data = ast.literal_eval(event.related_stocks)
|
report = stock_info.get('report', None)
|
||||||
else:
|
|
||||||
stock_data = event.related_stocks
|
|
||||||
|
|
||||||
if stock_data:
|
if stock_code:
|
||||||
daily_changes = []
|
# 规范化股票代码,移除后缀
|
||||||
week_changes = []
|
clean_code = stock_code.replace('.SZ', '').replace('.SH', '').replace('.BJ', '')
|
||||||
|
|
||||||
# 处理正确的数据格式 [股票代码, 股票名称, 描述, 分数]
|
# 使用模糊匹配查询真实的交易数据
|
||||||
for stock_info in stock_data:
|
trade_query = """
|
||||||
if isinstance(stock_info, list) and len(stock_info) >= 2:
|
SELECT F007N as close_price, F010N as change_pct, TRADEDATE
|
||||||
stock_code = stock_info[0] # 股票代码
|
FROM ea_trade
|
||||||
stock_name = stock_info[1] # 股票名称
|
WHERE SECCODE LIKE :stock_code_pattern
|
||||||
description = stock_info[2] if len(stock_info) > 2 else ''
|
ORDER BY TRADEDATE DESC LIMIT 7 \
|
||||||
score = stock_info[3] if len(stock_info) > 3 else 0
|
"""
|
||||||
else:
|
trade_result = db.session.execute(text(trade_query),
|
||||||
continue
|
{'stock_code_pattern': f'{clean_code}%'})
|
||||||
|
trade_data = trade_result.fetchall()
|
||||||
|
|
||||||
if stock_code:
|
daily_chg = 0
|
||||||
# 规范化股票代码,移除后缀
|
week_chg = 0
|
||||||
clean_code = stock_code.replace('.SZ', '').replace('.SH', '').replace('.BJ', '')
|
|
||||||
|
|
||||||
# 使用模糊匹配查询真实的交易数据
|
if trade_data:
|
||||||
trade_query = """
|
# 日涨跌幅(当日)
|
||||||
SELECT F007N as close_price, F010N as change_pct, TRADEDATE
|
daily_chg = float(trade_data[0].change_pct or 0)
|
||||||
FROM ea_trade
|
|
||||||
WHERE SECCODE LIKE :stock_code_pattern
|
|
||||||
ORDER BY TRADEDATE DESC LIMIT 7 \
|
|
||||||
"""
|
|
||||||
trade_result = db.session.execute(text(trade_query),
|
|
||||||
{'stock_code_pattern': f'{clean_code}%'})
|
|
||||||
trade_data = trade_result.fetchall()
|
|
||||||
|
|
||||||
daily_chg = 0
|
# 周涨跌幅(5个交易日)
|
||||||
week_chg = 0
|
if len(trade_data) >= 5:
|
||||||
|
current_price = float(trade_data[0].close_price or 0)
|
||||||
|
week_ago_price = float(trade_data[4].close_price or 0)
|
||||||
|
if week_ago_price > 0:
|
||||||
|
week_chg = ((current_price - week_ago_price) / week_ago_price) * 100
|
||||||
|
|
||||||
if trade_data:
|
# 收集涨跌幅数据
|
||||||
# 日涨跌幅(当日)
|
daily_changes.append(daily_chg)
|
||||||
daily_chg = float(trade_data[0].change_pct or 0)
|
week_changes.append(week_chg)
|
||||||
|
|
||||||
# 周涨跌幅(5个交易日)
|
related_stocks_list.append({
|
||||||
if len(trade_data) >= 5:
|
'code': stock_code,
|
||||||
current_price = float(trade_data[0].close_price or 0)
|
'name': stock_name,
|
||||||
week_ago_price = float(trade_data[4].close_price or 0)
|
'description': description,
|
||||||
if week_ago_price > 0:
|
'score': score,
|
||||||
week_chg = ((current_price - week_ago_price) / week_ago_price) * 100
|
'daily_chg': daily_chg,
|
||||||
|
'week_chg': week_chg,
|
||||||
|
'report': report # 添加研报引用信息
|
||||||
|
})
|
||||||
|
|
||||||
# 收集涨跌幅数据
|
# 计算平均收益率
|
||||||
daily_changes.append(daily_chg)
|
if daily_changes:
|
||||||
week_changes.append(week_chg)
|
related_avg_chg = round(sum(daily_changes) / len(daily_changes), 4)
|
||||||
|
related_max_chg = round(max(daily_changes), 4)
|
||||||
|
|
||||||
related_stocks_list.append({
|
if week_changes:
|
||||||
'code': stock_code,
|
related_week_chg = round(sum(week_changes) / len(week_changes), 4)
|
||||||
'name': stock_name,
|
|
||||||
'description': description,
|
|
||||||
'score': score,
|
|
||||||
'daily_chg': daily_chg,
|
|
||||||
'week_chg': week_chg
|
|
||||||
})
|
|
||||||
|
|
||||||
# 计算平均收益率
|
|
||||||
if daily_changes:
|
|
||||||
related_avg_chg = round(sum(daily_changes) / len(daily_changes), 4)
|
|
||||||
related_max_chg = round(max(daily_changes), 4)
|
|
||||||
|
|
||||||
if week_changes:
|
|
||||||
related_week_chg = round(sum(week_changes) / len(week_changes), 4)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error processing related stocks for event {event.data_id}: {e}")
|
print(f"Error processing related stocks for event {event.data_id}: {e}")
|
||||||
@@ -5660,8 +5796,9 @@ def api_calendar_events():
|
|||||||
highlight_match = 'concepts'
|
highlight_match = 'concepts'
|
||||||
|
|
||||||
# 将转义的换行符转换为真正的换行符,保留 Markdown 格式
|
# 将转义的换行符转换为真正的换行符,保留 Markdown 格式
|
||||||
cleaned_former = unescape_markdown_text(event.former)
|
# 使用新字段回退后的值(former_value, forecast_value)
|
||||||
cleaned_forecast = unescape_markdown_text(event.forecast)
|
cleaned_former = unescape_markdown_text(former_value)
|
||||||
|
cleaned_forecast = unescape_markdown_text(forecast_value)
|
||||||
cleaned_fact = unescape_markdown_text(event.fact)
|
cleaned_fact = unescape_markdown_text(event.fact)
|
||||||
|
|
||||||
event_dict = {
|
event_dict = {
|
||||||
@@ -5907,6 +6044,7 @@ def api_future_event_detail(item_id):
|
|||||||
"""未来事件详情接口 - 连接 future_events 表 (修正数据解析) - 仅限 Pro/Max 会员"""
|
"""未来事件详情接口 - 连接 future_events 表 (修正数据解析) - 仅限 Pro/Max 会员"""
|
||||||
try:
|
try:
|
||||||
# 从 future_events 表查询事件详情
|
# 从 future_events 表查询事件详情
|
||||||
|
# 添加新字段 second_modified_text, `second_modified_text.1`, best_matches 支持新旧回退
|
||||||
query = """
|
query = """
|
||||||
SELECT data_id, \
|
SELECT data_id, \
|
||||||
calendar_time, \
|
calendar_time, \
|
||||||
@@ -5917,7 +6055,10 @@ def api_future_event_detail(item_id):
|
|||||||
forecast, \
|
forecast, \
|
||||||
fact, \
|
fact, \
|
||||||
related_stocks, \
|
related_stocks, \
|
||||||
concepts
|
concepts, \
|
||||||
|
second_modified_text, \
|
||||||
|
`second_modified_text.1` as second_modified_text_1, \
|
||||||
|
best_matches
|
||||||
FROM future_events
|
FROM future_events
|
||||||
WHERE data_id = :item_id \
|
WHERE data_id = :item_id \
|
||||||
"""
|
"""
|
||||||
@@ -5932,6 +6073,13 @@ def api_future_event_detail(item_id):
|
|||||||
'data': None
|
'data': None
|
||||||
}), 404
|
}), 404
|
||||||
|
|
||||||
|
# 使用新字段回退机制获取 former 和 forecast
|
||||||
|
# second_modified_text -> former
|
||||||
|
former_value = get_future_event_field(event, 'second_modified_text', 'former')
|
||||||
|
# second_modified_text.1 -> forecast
|
||||||
|
forecast_new = getattr(event, 'second_modified_text_1', None)
|
||||||
|
forecast_value = forecast_new if (forecast_new and str(forecast_new).strip()) else getattr(event, 'forecast', None)
|
||||||
|
|
||||||
extracted_concepts = extract_concepts_from_concepts_field(event.concepts)
|
extracted_concepts = extract_concepts_from_concepts_field(event.concepts)
|
||||||
|
|
||||||
# 解析相关股票
|
# 解析相关股票
|
||||||
@@ -5975,136 +6123,150 @@ def api_future_event_detail(item_id):
|
|||||||
'环保': '公共产业板块', '综合': '公共产业板块'
|
'环保': '公共产业板块', '综合': '公共产业板块'
|
||||||
}
|
}
|
||||||
|
|
||||||
# 处理相关股票
|
# 处理相关股票 - 优先使用 best_matches,回退到 related_stocks
|
||||||
related_avg_chg = 0
|
related_avg_chg = 0
|
||||||
related_max_chg = 0
|
related_max_chg = 0
|
||||||
related_week_chg = 0
|
related_week_chg = 0
|
||||||
|
|
||||||
if event.related_stocks:
|
# 优先使用 best_matches(新结构,含研报引用)
|
||||||
|
best_matches = getattr(event, 'best_matches', None)
|
||||||
|
if best_matches and str(best_matches).strip():
|
||||||
|
# 使用新的 parse_best_matches 函数解析
|
||||||
|
parsed_stocks = parse_best_matches(best_matches)
|
||||||
|
else:
|
||||||
|
# 回退到旧的 related_stocks 处理
|
||||||
|
parsed_stocks = []
|
||||||
|
if event.related_stocks:
|
||||||
|
try:
|
||||||
|
import ast
|
||||||
|
if isinstance(event.related_stocks, str):
|
||||||
|
try:
|
||||||
|
stock_data = json.loads(event.related_stocks)
|
||||||
|
except:
|
||||||
|
stock_data = ast.literal_eval(event.related_stocks)
|
||||||
|
else:
|
||||||
|
stock_data = event.related_stocks
|
||||||
|
|
||||||
|
if stock_data:
|
||||||
|
for stock_info in stock_data:
|
||||||
|
if isinstance(stock_info, list) and len(stock_info) >= 2:
|
||||||
|
parsed_stocks.append({
|
||||||
|
'code': stock_info[0],
|
||||||
|
'name': stock_info[1],
|
||||||
|
'description': stock_info[2] if len(stock_info) > 2 else '',
|
||||||
|
'score': stock_info[3] if len(stock_info) > 3 else 0,
|
||||||
|
'report': None
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error parsing related_stocks for event {event.data_id}: {e}")
|
||||||
|
|
||||||
|
# 处理解析后的股票数据
|
||||||
|
if parsed_stocks:
|
||||||
try:
|
try:
|
||||||
import json
|
daily_changes = []
|
||||||
import ast
|
week_changes = []
|
||||||
|
|
||||||
# **修正:正确解析related_stocks数据结构**
|
for stock_info in parsed_stocks:
|
||||||
if isinstance(event.related_stocks, str):
|
stock_code = stock_info.get('code', '')
|
||||||
try:
|
stock_name = stock_info.get('name', '')
|
||||||
# 先尝试JSON解析
|
description = stock_info.get('description', '')
|
||||||
stock_data = json.loads(event.related_stocks)
|
score = stock_info.get('score', 0)
|
||||||
except:
|
report = stock_info.get('report', None)
|
||||||
# 如果JSON解析失败,尝试ast.literal_eval解析
|
|
||||||
stock_data = ast.literal_eval(event.related_stocks)
|
|
||||||
else:
|
|
||||||
stock_data = event.related_stocks
|
|
||||||
|
|
||||||
print(f"Parsed stock_data: {stock_data}") # 调试输出
|
if stock_code:
|
||||||
|
# 规范化股票代码,移除后缀
|
||||||
|
clean_code = stock_code.replace('.SZ', '').replace('.SH', '').replace('.BJ', '')
|
||||||
|
|
||||||
if stock_data:
|
print(f"Processing stock: {clean_code} - {stock_name}") # 调试输出
|
||||||
daily_changes = []
|
|
||||||
week_changes = []
|
|
||||||
|
|
||||||
# **修正:处理正确的数据格式 [股票代码, 股票名称, 描述, 分数]**
|
# 使用模糊匹配LIKE查询申万一级行业F004V
|
||||||
for stock_info in stock_data:
|
sector_query = """
|
||||||
if isinstance(stock_info, list) and len(stock_info) >= 2:
|
SELECT F004V as sw_primary_sector
|
||||||
stock_code = stock_info[0] # 第一个元素是股票代码
|
FROM ea_sector
|
||||||
stock_name = stock_info[1] # 第二个元素是股票名称
|
WHERE SECCODE LIKE :stock_code_pattern
|
||||||
description = stock_info[2] if len(stock_info) > 2 else ''
|
AND F002V = '申银万国行业分类' LIMIT 1 \
|
||||||
score = stock_info[3] if len(stock_info) > 3 else 0
|
"""
|
||||||
else:
|
sector_result = db.session.execute(text(sector_query),
|
||||||
continue # 跳过格式不正确的数据
|
{'stock_code_pattern': f'{clean_code}%'})
|
||||||
|
sector_row = sector_result.fetchone()
|
||||||
|
|
||||||
if stock_code:
|
# 根据申万一级行业(F004V)映射到主板块
|
||||||
# 规范化股票代码,移除后缀
|
sw_primary_sector = sector_row.sw_primary_sector if sector_row else None
|
||||||
clean_code = stock_code.replace('.SZ', '').replace('.SH', '').replace('.BJ', '')
|
primary_sector = sector_map.get(sw_primary_sector, '其他') if sw_primary_sector else '其他'
|
||||||
|
|
||||||
print(f"Processing stock: {clean_code} - {stock_name}") # 调试输出
|
print(
|
||||||
|
f"Stock: {clean_code}, SW Primary: {sw_primary_sector}, Primary Sector: {primary_sector}")
|
||||||
|
|
||||||
# 使用模糊匹配LIKE查询申万一级行业F004V
|
# 通过SQL查询获取真实的日涨跌幅和周涨跌幅
|
||||||
sector_query = """
|
trade_query = """
|
||||||
SELECT F004V as sw_primary_sector
|
SELECT F007N as close_price, F010N as change_pct, TRADEDATE
|
||||||
FROM ea_sector
|
FROM ea_trade
|
||||||
WHERE SECCODE LIKE :stock_code_pattern
|
WHERE SECCODE LIKE :stock_code_pattern
|
||||||
AND F002V = '申银万国行业分类' LIMIT 1 \
|
ORDER BY TRADEDATE DESC LIMIT 7 \
|
||||||
"""
|
"""
|
||||||
sector_result = db.session.execute(text(sector_query),
|
trade_result = db.session.execute(text(trade_query),
|
||||||
{'stock_code_pattern': f'{clean_code}%'})
|
{'stock_code_pattern': f'{clean_code}%'})
|
||||||
sector_row = sector_result.fetchone()
|
trade_data = trade_result.fetchall()
|
||||||
|
|
||||||
# 根据申万一级行业(F004V)映射到主板块
|
daily_chg = 0
|
||||||
sw_primary_sector = sector_row.sw_primary_sector if sector_row else None
|
week_chg = 0
|
||||||
primary_sector = sector_map.get(sw_primary_sector, '其他') if sw_primary_sector else '其他'
|
|
||||||
|
|
||||||
print(
|
if trade_data:
|
||||||
f"Stock: {clean_code}, SW Primary: {sw_primary_sector}, Primary Sector: {primary_sector}")
|
# 日涨跌幅(当日)
|
||||||
|
daily_chg = float(trade_data[0].change_pct or 0)
|
||||||
|
|
||||||
# 通过SQL查询获取真实的日涨跌幅和周涨跌幅
|
# 周涨跌幅(5个交易日)
|
||||||
trade_query = """
|
if len(trade_data) >= 5:
|
||||||
SELECT F007N as close_price, F010N as change_pct, TRADEDATE
|
current_price = float(trade_data[0].close_price or 0)
|
||||||
FROM ea_trade
|
week_ago_price = float(trade_data[4].close_price or 0)
|
||||||
WHERE SECCODE LIKE :stock_code_pattern
|
if week_ago_price > 0:
|
||||||
ORDER BY TRADEDATE DESC LIMIT 7 \
|
week_chg = ((current_price - week_ago_price) / week_ago_price) * 100
|
||||||
"""
|
|
||||||
trade_result = db.session.execute(text(trade_query),
|
|
||||||
{'stock_code_pattern': f'{clean_code}%'})
|
|
||||||
trade_data = trade_result.fetchall()
|
|
||||||
|
|
||||||
daily_chg = 0
|
print(
|
||||||
week_chg = 0
|
f"Trade data found: {len(trade_data) if trade_data else 0} records, daily_chg: {daily_chg}")
|
||||||
|
|
||||||
if trade_data:
|
# 统计各分类数量
|
||||||
# 日涨跌幅(当日)
|
sector_stats['全部股票'] += 1
|
||||||
daily_chg = float(trade_data[0].change_pct or 0)
|
sector_stats[primary_sector] += 1
|
||||||
|
|
||||||
# 周涨跌幅(5个交易日)
|
# 收集涨跌幅数据
|
||||||
if len(trade_data) >= 5:
|
daily_changes.append(daily_chg)
|
||||||
current_price = float(trade_data[0].close_price or 0)
|
week_changes.append(week_chg)
|
||||||
week_ago_price = float(trade_data[4].close_price or 0)
|
|
||||||
if week_ago_price > 0:
|
|
||||||
week_chg = ((current_price - week_ago_price) / week_ago_price) * 100
|
|
||||||
|
|
||||||
print(
|
related_stocks_list.append({
|
||||||
f"Trade data found: {len(trade_data) if trade_data else 0} records, daily_chg: {daily_chg}")
|
'code': stock_code, # 原始股票代码
|
||||||
|
'name': stock_name, # 股票名称
|
||||||
|
'description': description, # 关联描述
|
||||||
|
'score': score, # 关联分数
|
||||||
|
'sw_primary_sector': sw_primary_sector, # 申万一级行业(F004V)
|
||||||
|
'primary_sector': primary_sector, # 主板块分类
|
||||||
|
'daily_change': daily_chg, # 真实的日涨跌幅
|
||||||
|
'week_change': week_chg, # 真实的周涨跌幅
|
||||||
|
'report': report # 研报引用信息(新字段)
|
||||||
|
})
|
||||||
|
|
||||||
# 统计各分类数量
|
# 计算平均收益率
|
||||||
sector_stats['全部股票'] += 1
|
if daily_changes:
|
||||||
sector_stats[primary_sector] += 1
|
related_avg_chg = sum(daily_changes) / len(daily_changes)
|
||||||
|
related_max_chg = max(daily_changes)
|
||||||
|
|
||||||
# 收集涨跌幅数据
|
if week_changes:
|
||||||
daily_changes.append(daily_chg)
|
related_week_chg = sum(week_changes) / len(week_changes)
|
||||||
week_changes.append(week_chg)
|
|
||||||
|
|
||||||
related_stocks_list.append({
|
|
||||||
'code': stock_code, # 原始股票代码
|
|
||||||
'name': stock_name, # 股票名称
|
|
||||||
'description': description, # 关联描述
|
|
||||||
'score': score, # 关联分数
|
|
||||||
'sw_primary_sector': sw_primary_sector, # 申万一级行业(F004V)
|
|
||||||
'primary_sector': primary_sector, # 主板块分类
|
|
||||||
'daily_change': daily_chg, # 真实的日涨跌幅
|
|
||||||
'week_change': week_chg # 真实的周涨跌幅
|
|
||||||
})
|
|
||||||
|
|
||||||
# 计算平均收益率
|
|
||||||
if daily_changes:
|
|
||||||
related_avg_chg = sum(daily_changes) / len(daily_changes)
|
|
||||||
related_max_chg = max(daily_changes)
|
|
||||||
|
|
||||||
if week_changes:
|
|
||||||
related_week_chg = sum(week_changes) / len(week_changes)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error processing related stocks: {e}")
|
print(f"Error processing related stocks: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
# 构建返回数据
|
# 构建返回数据,使用新字段回退后的值
|
||||||
detail_data = {
|
detail_data = {
|
||||||
'id': event.data_id,
|
'id': event.data_id,
|
||||||
'title': event.title,
|
'title': event.title,
|
||||||
'type': event.type,
|
'type': event.type,
|
||||||
'star': event.star,
|
'star': event.star,
|
||||||
'calendar_time': event.calendar_time.isoformat() if event.calendar_time else None,
|
'calendar_time': event.calendar_time.isoformat() if event.calendar_time else None,
|
||||||
'former': event.former,
|
'former': former_value, # 使用回退后的值(优先 second_modified_text)
|
||||||
'forecast': event.forecast,
|
'forecast': forecast_value, # 使用回退后的值(优先 second_modified_text.1)
|
||||||
'fact': event.fact,
|
'fact': event.fact,
|
||||||
'concepts': event.concepts,
|
'concepts': event.concepts,
|
||||||
'extracted_concepts': extracted_concepts,
|
'extracted_concepts': extracted_concepts,
|
||||||
|
|||||||
Reference in New Issue
Block a user