fix: 修复复盘计划失败问题

refactor3.0
Lxy 1 week ago
parent 0ee6a3dab7
commit f663435843

@ -7,9 +7,6 @@ from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base from sqlalchemy.orm import sessionmaker, declarative_base
from datetime import datetime from datetime import datetime
from app.mysql_database import MySQLSessionLocal
from app.storage_manager import get_storage_manager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# 数据目录 # 数据目录
@ -31,38 +28,14 @@ AnalysisBase = declarative_base()
def get_analysis_db(): def get_analysis_db():
"""获取期货智析数据库会话。 """获取期货智析数据库会话。
根据 MySQL 可用性动态选择后端 分析数据量较小复盘计划评分等始终使用 SQLite 以保证稳定性
- MySQL 可用时返回 MySQL Session AnalysisBase 绑定的是 analysis_engine (SQLite)ORM 模型均基于此定义
- MySQL 不可用时返回 SQLite Session兜底
""" """
storage = get_storage_manager() db = AnalysisSessionLocal()
try:
if MySQLSessionLocal is not None and storage.check_mysql(): yield db
db = None finally:
try: db.close()
db = MySQLSessionLocal()
yield db
except Exception as e:
logger.warning(f"创建 MySQL analysis session 失败,降级到 SQLite: {e}")
if db is not None:
try:
db.close()
except Exception:
pass
db = AnalysisSessionLocal()
yield db
finally:
if db is not None:
try:
db.close()
except Exception:
pass
else:
db = AnalysisSessionLocal()
try:
yield db
finally:
db.close()
def init_analysis_db(): def init_analysis_db():

@ -626,121 +626,126 @@ def save_plan_to_db(db: Session, plan_data: dict) -> int:
review_date_str = plan_data["review_date"] review_date_str = plan_data["review_date"]
week_day = plan_data["week_day"] week_day = plan_data["week_day"]
# 清理旧数据 try:
existing = db.query(ReviewPlanV2).filter_by(review_date=review_date_str).first() # 清理旧数据
if existing: existing = db.query(ReviewPlanV2).filter_by(review_date=review_date_str).first()
review_plan_id = existing.id if existing:
# 清理关联数据 review_plan_id = existing.id
db.query(SymbolScoreV2).filter_by(review_date_id=review_plan_id).delete() # 清理关联数据
db.query(TradingPlanV2).filter_by(review_date_id=review_plan_id).delete() db.query(SymbolScoreV2).filter_by(review_date_id=review_plan_id).delete()
db.query(SectorHeat).filter_by(review_date_id=review_plan_id).delete() db.query(TradingPlanV2).filter_by(review_date_id=review_plan_id).delete()
# 更新元数据 db.query(SectorHeat).filter_by(review_date_id=review_plan_id).delete()
existing.week_day = week_day # 更新元数据
existing.data_basis = plan_data.get("data_basis") existing.week_day = week_day
existing.core_conclusion = plan_data.get("core_conclusion") existing.data_basis = plan_data.get("data_basis")
existing.bull_count = plan_data.get("bull_count") existing.core_conclusion = plan_data.get("core_conclusion")
existing.bear_count = plan_data.get("bear_count") existing.bull_count = plan_data.get("bull_count")
existing.neutral_count = plan_data.get("neutral_count") existing.bear_count = plan_data.get("bear_count")
existing.opportunity_count = plan_data.get("opportunity_count") existing.neutral_count = plan_data.get("neutral_count")
existing.risk_warnings = plan_data.get("risk_warnings") existing.opportunity_count = plan_data.get("opportunity_count")
existing.actual_data_date = plan_data.get("actual_data_date") existing.risk_warnings = plan_data.get("risk_warnings")
existing.data_date_matches = 1 if plan_data.get("data_date_matches") else 0 existing.actual_data_date = plan_data.get("actual_data_date")
else: existing.data_date_matches = 1 if plan_data.get("data_date_matches") else 0
review_plan = ReviewPlanV2( else:
review_date=review_date_str, review_plan = ReviewPlanV2(
week_day=week_day, review_date=review_date_str,
data_basis=plan_data.get("data_basis"), week_day=week_day,
core_conclusion=plan_data.get("core_conclusion"), data_basis=plan_data.get("data_basis"),
bull_count=plan_data.get("bull_count"), core_conclusion=plan_data.get("core_conclusion"),
bear_count=plan_data.get("bear_count"), bull_count=plan_data.get("bull_count"),
neutral_count=plan_data.get("neutral_count"), bear_count=plan_data.get("bear_count"),
opportunity_count=plan_data.get("opportunity_count"), neutral_count=plan_data.get("neutral_count"),
risk_warnings=plan_data.get("risk_warnings"), opportunity_count=plan_data.get("opportunity_count"),
actual_data_date=plan_data.get("actual_data_date"), risk_warnings=plan_data.get("risk_warnings"),
data_date_matches=1 if plan_data.get("data_date_matches") else 0, actual_data_date=plan_data.get("actual_data_date"),
) data_date_matches=1 if plan_data.get("data_date_matches") else 0,
db.add(review_plan) )
db.flush() db.add(review_plan)
review_plan_id = review_plan.id db.flush()
review_plan_id = review_plan.id
# 保存评分数据
for s in plan_data.get("scores", []): # 保存评分数据
pivots = s.get("pivots", {}) for s in plan_data.get("scores", []):
score_record = SymbolScoreV2( pivots = s.get("pivots", {})
review_date_id=review_plan_id, score_record = SymbolScoreV2(
symbol=s["symbol"], review_date_id=review_plan_id,
name=s["name"], symbol=s["symbol"],
close_price=s.get("close_price"), name=s["name"],
prev_close=s.get("prev_close"), close_price=s.get("close_price"),
high_price=s.get("high_price"), prev_close=s.get("prev_close"),
low_price=s.get("low_price"), high_price=s.get("high_price"),
volume=s.get("volume"), low_price=s.get("low_price"),
avg_volume_5=s.get("avg_volume_5"), volume=s.get("volume"),
amplitude_score=s.get("amplitude_score"), avg_volume_5=s.get("avg_volume_5"),
volume_score=s.get("volume_score"), amplitude_score=s.get("amplitude_score"),
change_score=s.get("change_score"), volume_score=s.get("volume_score"),
trend_score=s.get("trend_score"), change_score=s.get("change_score"),
activity_score=s.get("activity_score"), trend_score=s.get("trend_score"),
composite_score=s.get("composite_score"), activity_score=s.get("activity_score"),
amplitude_pct=s.get("amplitude_pct"), composite_score=s.get("composite_score"),
change_pct=s.get("change_pct"), amplitude_pct=s.get("amplitude_pct"),
volume_ratio=s.get("volume_ratio"), change_pct=s.get("change_pct"),
trend_60m=s.get("trend_60m"), volume_ratio=s.get("volume_ratio"),
trend_15m=s.get("trend_15m"), trend_60m=s.get("trend_60m"),
trend_5m=s.get("trend_5m"), trend_15m=s.get("trend_15m"),
direction=s.get("direction"), trend_5m=s.get("trend_5m"),
direction_tag=s.get("direction_tag"), direction=s.get("direction"),
category=s.get("category"), direction_tag=s.get("direction_tag"),
pivot=pivots.get("pivot"), category=s.get("category"),
r1=pivots.get("r1"), pivot=pivots.get("pivot"),
r2=pivots.get("r2"), r1=pivots.get("r1"),
s1=pivots.get("s1"), r2=pivots.get("r2"),
s2=pivots.get("s2"), s1=pivots.get("s1"),
rank=s.get("rank"), s2=pivots.get("s2"),
data_date=s.get("data_date"), rank=s.get("rank"),
) data_date=s.get("data_date"),
db.add(score_record) )
db.add(score_record)
# 保存交易计划
for p in plan_data.get("plans", []): # 保存交易计划
plan_record = TradingPlanV2( for p in plan_data.get("plans", []):
review_date_id=review_plan_id, plan_record = TradingPlanV2(
symbol=p["symbol"], review_date_id=review_plan_id,
name=p["name"], symbol=p["symbol"],
direction=p["direction"], name=p["name"],
composite_score=p.get("composite_score"), direction=p["direction"],
entry_low=p.get("entry_low"), composite_score=p.get("composite_score"),
entry_high=p.get("entry_high"), entry_low=p.get("entry_low"),
stop_loss=p.get("stop_loss"), entry_high=p.get("entry_high"),
target1=p.get("target1"), stop_loss=p.get("stop_loss"),
target2=p.get("target2"), target1=p.get("target1"),
trigger=p.get("trigger"), target2=p.get("target2"),
amplitude_score=p.get("amplitude_score"), trigger=p.get("trigger"),
volume_score=p.get("volume_score"), amplitude_score=p.get("amplitude_score"),
trend_score=p.get("trend_score"), volume_score=p.get("volume_score"),
activity_score=p.get("activity_score"), trend_score=p.get("trend_score"),
category=p.get("category"), activity_score=p.get("activity_score"),
) category=p.get("category"),
db.add(plan_record) )
db.add(plan_record)
# 保存板块热度
for sec in plan_data.get("sectors", []): # 保存板块热度
sector_record = SectorHeat( for sec in plan_data.get("sectors", []):
review_date_id=review_plan_id, sector_record = SectorHeat(
sector_name=sec["sector_name"], review_date_id=review_plan_id,
avg_score=sec.get("avg_score"), sector_name=sec["sector_name"],
avg_trend=sec.get("avg_trend"), avg_score=sec.get("avg_score"),
direction=sec.get("direction"), avg_trend=sec.get("avg_trend"),
heat_level=sec.get("heat_level"), direction=sec.get("direction"),
leader_symbol=sec.get("leader_symbol"), heat_level=sec.get("heat_level"),
leader_score=sec.get("leader_score"), leader_symbol=sec.get("leader_symbol"),
members=sec.get("members"), leader_score=sec.get("leader_score"),
) members=sec.get("members"),
db.add(sector_record) )
db.add(sector_record)
db.commit()
logger.info(f"交易计划已保存: {review_date_str}, ID={review_plan_id}") db.commit()
return review_plan_id logger.info(f"交易计划已保存: {review_date_str}, ID={review_plan_id}")
return review_plan_id
except Exception as e:
db.rollback()
logger.exception(f"保存交易计划失败: {e}")
raise
def get_plan_data(db: Session, review_plan_id: int) -> Optional[dict]: def get_plan_data(db: Session, review_plan_id: int) -> Optional[dict]:

Binary file not shown.
Loading…
Cancel
Save