|
|
|
@ -129,14 +129,40 @@ def _calc_trend_score(t60: float, t15: float, t5: float) -> Tuple[float, str, st
|
|
|
|
return round(raw, 1), direction, tag
|
|
|
|
return round(raw, 1), direction, tag
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_price_precision(price: float) -> int:
|
|
|
|
|
|
|
|
"""根据价格大小确定合适的小数位数"""
|
|
|
|
|
|
|
|
if price >= 10000:
|
|
|
|
|
|
|
|
return 0 # 如白银8250、股指5000+
|
|
|
|
|
|
|
|
elif price >= 1000:
|
|
|
|
|
|
|
|
return 1 # 如原油528、黄金685(实际2位)
|
|
|
|
|
|
|
|
elif price >= 100:
|
|
|
|
|
|
|
|
return 2 # 如大部分化工品
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
return 2 # 小数值的品种
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _round_by_price(value: float, price: float) -> float:
|
|
|
|
|
|
|
|
"""根据价格精度四舍五入"""
|
|
|
|
|
|
|
|
precision = _get_price_precision(price)
|
|
|
|
|
|
|
|
return round(value, precision)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _calc_pivot_points(high: float, low: float, close: float) -> dict:
|
|
|
|
def _calc_pivot_points(high: float, low: float, close: float) -> dict:
|
|
|
|
"""计算枢轴点和支撑/阻力位"""
|
|
|
|
"""计算枢轴点和支撑/阻力位(根据价格精度自动调整小数位)"""
|
|
|
|
pivot = (high + low + close) / 3
|
|
|
|
pivot = (high + low + close) / 3
|
|
|
|
r1 = 2 * pivot - low
|
|
|
|
r1 = 2 * pivot - low
|
|
|
|
s1 = 2 * pivot - high
|
|
|
|
s1 = 2 * pivot - high
|
|
|
|
r2 = pivot + (high - low)
|
|
|
|
r2 = pivot + (high - low)
|
|
|
|
s2 = pivot - (high - low)
|
|
|
|
s2 = pivot - (high - low)
|
|
|
|
return {"pivot": pivot, "r1": r1, "r2": r2, "s1": s1, "s2": s2}
|
|
|
|
# 根据价格精度四舍五入
|
|
|
|
|
|
|
|
p = _get_price_precision(close)
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
"pivot": round(pivot, p),
|
|
|
|
|
|
|
|
"r1": round(r1, p),
|
|
|
|
|
|
|
|
"r2": round(r2, p),
|
|
|
|
|
|
|
|
"s1": round(s1, p),
|
|
|
|
|
|
|
|
"s2": round(s2, p),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _normalize_scores(values: List[float], reverse: bool = False) -> List[float]:
|
|
|
|
def _normalize_scores(values: List[float], reverse: bool = False) -> List[float]:
|
|
|
|
@ -163,6 +189,63 @@ def _normalize_abs_scores(values: List[float]) -> List[float]:
|
|
|
|
return _normalize_scores(abs_values)
|
|
|
|
return _normalize_scores(abs_values)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _generate_trigger(score_data: dict, direction: str) -> str:
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
根据分析结果动态生成触发条件
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
|
|
score_data: 品种评分数据
|
|
|
|
|
|
|
|
direction: 方向 (long/short)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
触发条件文本
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
conditions = []
|
|
|
|
|
|
|
|
direction_tag = score_data.get("direction_tag", "震荡")
|
|
|
|
|
|
|
|
volume_ratio = score_data.get("volume_ratio", 1.0)
|
|
|
|
|
|
|
|
amplitude_pct = score_data.get("amplitude_pct", 0)
|
|
|
|
|
|
|
|
change_pct = score_data.get("change_pct", 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 根据方向标签生成基础条件
|
|
|
|
|
|
|
|
if direction == "long":
|
|
|
|
|
|
|
|
if direction_tag == "强多":
|
|
|
|
|
|
|
|
conditions.append("价格站稳支撑位上方")
|
|
|
|
|
|
|
|
elif direction_tag == "偏多":
|
|
|
|
|
|
|
|
conditions.append("回踩支撑企稳")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
conditions.append("突破枢轴点P位")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
if direction_tag == "强空":
|
|
|
|
|
|
|
|
conditions.append("价格跌破阻力位下方")
|
|
|
|
|
|
|
|
elif direction_tag == "偏空":
|
|
|
|
|
|
|
|
conditions.append("反弹阻力受阻")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
conditions.append("跌破枢轴点P位")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 根据量比添加量能条件
|
|
|
|
|
|
|
|
if volume_ratio > 1.5:
|
|
|
|
|
|
|
|
conditions.append("量能持续放大")
|
|
|
|
|
|
|
|
elif volume_ratio > 1.2:
|
|
|
|
|
|
|
|
conditions.append("5分钟K线放量确认")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
conditions.append("等待量能配合")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 根据振幅添加波动条件
|
|
|
|
|
|
|
|
if amplitude_pct > 2:
|
|
|
|
|
|
|
|
conditions.append("注意波动风险")
|
|
|
|
|
|
|
|
elif amplitude_pct > 1:
|
|
|
|
|
|
|
|
conditions.append("关注区间突破")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 根据涨跌幅添加趋势条件
|
|
|
|
|
|
|
|
if abs(change_pct) > 2:
|
|
|
|
|
|
|
|
if change_pct > 0:
|
|
|
|
|
|
|
|
conditions.append("强势延续确认")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
conditions.append("弱势延续确认")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return " + ".join(conditions[:3]) # 最多返回3个条件
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_plan(db: Session, review_date_str: str, week_day: str) -> dict:
|
|
|
|
def generate_plan(db: Session, review_date_str: str, week_day: str) -> dict:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
生成V2复盘与交易计划
|
|
|
|
生成V2复盘与交易计划
|
|
|
|
@ -350,21 +433,34 @@ def generate_plan(db: Session, review_date_str: str, week_day: str) -> dict:
|
|
|
|
green_items = [s for s in raw_scores if s["category"] == "green"]
|
|
|
|
green_items = [s for s in raw_scores if s["category"] == "green"]
|
|
|
|
|
|
|
|
|
|
|
|
for s in green_items:
|
|
|
|
for s in green_items:
|
|
|
|
direction = "long" if s["trend_score"] >= 50 else "short"
|
|
|
|
# 根据方向标签判断实际方向(强多/偏多→做多,强空/偏空→做空)
|
|
|
|
|
|
|
|
direction_tag = s.get("direction_tag", "震荡")
|
|
|
|
|
|
|
|
if direction_tag in ["强空", "偏空"]:
|
|
|
|
|
|
|
|
direction = "short"
|
|
|
|
|
|
|
|
elif direction_tag in ["强多", "偏多"]:
|
|
|
|
|
|
|
|
direction = "long"
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
# 震荡情况下根据涨跌幅判断
|
|
|
|
|
|
|
|
direction = "long" if s["change_pct"] > 0 else "short"
|
|
|
|
|
|
|
|
|
|
|
|
pivots = s["pivots"]
|
|
|
|
pivots = s["pivots"]
|
|
|
|
|
|
|
|
price = s["close_price"]
|
|
|
|
|
|
|
|
|
|
|
|
if direction == "long":
|
|
|
|
if direction == "long":
|
|
|
|
entry_low = round(pivots["s1"], 2)
|
|
|
|
entry_low = _round_by_price(pivots["s1"], price)
|
|
|
|
entry_high = round(pivots["pivot"], 2)
|
|
|
|
entry_high = _round_by_price(pivots["pivot"], price)
|
|
|
|
stop_loss = round(pivots["s2"], 2)
|
|
|
|
stop_loss = _round_by_price(pivots["s2"], price)
|
|
|
|
target1 = round(pivots["r1"], 2)
|
|
|
|
target1 = _round_by_price(pivots["r1"], price)
|
|
|
|
target2 = round(pivots["r2"], 2)
|
|
|
|
target2 = _round_by_price(pivots["r2"], price)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
entry_low = round(pivots["pivot"], 2)
|
|
|
|
entry_low = _round_by_price(pivots["pivot"], price)
|
|
|
|
entry_high = round(pivots["r1"], 2)
|
|
|
|
entry_high = _round_by_price(pivots["r1"], price)
|
|
|
|
stop_loss = round(pivots["r2"], 2)
|
|
|
|
stop_loss = _round_by_price(pivots["r2"], price)
|
|
|
|
target1 = round(pivots["s1"], 2)
|
|
|
|
target1 = _round_by_price(pivots["s1"], price)
|
|
|
|
target2 = round(pivots["s2"], 2)
|
|
|
|
target2 = _round_by_price(pivots["s2"], price)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 根据分析结果动态生成触发条件
|
|
|
|
|
|
|
|
trigger = _generate_trigger(s, direction)
|
|
|
|
|
|
|
|
|
|
|
|
plans.append({
|
|
|
|
plans.append({
|
|
|
|
"symbol": s["symbol"],
|
|
|
|
"symbol": s["symbol"],
|
|
|
|
@ -376,7 +472,7 @@ def generate_plan(db: Session, review_date_str: str, week_day: str) -> dict:
|
|
|
|
"stop_loss": stop_loss,
|
|
|
|
"stop_loss": stop_loss,
|
|
|
|
"target1": target1,
|
|
|
|
"target1": target1,
|
|
|
|
"target2": target2,
|
|
|
|
"target2": target2,
|
|
|
|
"trigger": "回踩支撑企稳 + 5m放量突破",
|
|
|
|
"trigger": trigger,
|
|
|
|
"amplitude_score": s["amplitude_score"],
|
|
|
|
"amplitude_score": s["amplitude_score"],
|
|
|
|
"volume_score": s["volume_score"],
|
|
|
|
"volume_score": s["volume_score"],
|
|
|
|
"trend_score": s["trend_score"],
|
|
|
|
"trend_score": s["trend_score"],
|
|
|
|
|