139 lines
4.4 KiB
Python
139 lines
4.4 KiB
Python
"""前置策略匹配核心逻辑
|
|
|
|
本模块仅根据人工选择的大盘周期、阶段、趋势强弱,
|
|
查询匹配绑定表并输出可用账户与策略。
|
|
不做任何 K 线识别、箱体判断、点位计算或突破校验。
|
|
"""
|
|
|
|
from sqlalchemy.orm import Session, joinedload
|
|
|
|
from app.models import MarketRegime, RegimeMatch
|
|
from app.schemas import MatchRequest, MatchResult, MatchAccountOut, MatchStrategyOut
|
|
|
|
|
|
def run_match(db: Session, req: MatchRequest) -> MatchResult:
|
|
"""执行前置匹配"""
|
|
regime = db.query(MarketRegime).filter(MarketRegime.id == req.market_regime_id).first()
|
|
if not regime:
|
|
return MatchResult(
|
|
market_cycle=req.market_cycle,
|
|
regime_name="未知",
|
|
trade_type="",
|
|
allow_direction="",
|
|
trend_strength=req.trend_strength,
|
|
status="disabled",
|
|
message="大盘阶段不存在",
|
|
)
|
|
|
|
base = dict(
|
|
market_cycle=req.market_cycle,
|
|
regime_name=regime.name,
|
|
trade_type=regime.trade_type,
|
|
allow_direction=regime.allow_direction,
|
|
trend_strength=req.trend_strength,
|
|
)
|
|
|
|
# 震荡 → 全部禁用
|
|
if req.trend_strength == "震荡":
|
|
return MatchResult(
|
|
**base,
|
|
status="watch",
|
|
message="趋势强弱为「震荡」,全部策略禁用,建议观望",
|
|
)
|
|
|
|
# 宽幅震荡阶段 → 观望
|
|
if regime.trade_type == "观望" or regime.allow_direction == "禁止":
|
|
return MatchResult(
|
|
**base,
|
|
status="watch",
|
|
message=f"大盘阶段「{regime.name}」为观望阶段,禁止交易",
|
|
)
|
|
|
|
# 查询匹配绑定
|
|
matches = (
|
|
db.query(RegimeMatch)
|
|
.options(
|
|
joinedload(RegimeMatch.account),
|
|
joinedload(RegimeMatch.strategy),
|
|
)
|
|
.filter(
|
|
RegimeMatch.market_regime_id == req.market_regime_id,
|
|
RegimeMatch.market_cycle == req.market_cycle,
|
|
RegimeMatch.trend_strength == req.trend_strength,
|
|
)
|
|
.all()
|
|
)
|
|
|
|
if not matches:
|
|
return MatchResult(
|
|
**base,
|
|
status="disabled",
|
|
message="未找到匹配的账户/策略绑定,请在配置中心添加匹配规则",
|
|
)
|
|
|
|
# 过滤:仅保留已启用账户
|
|
accounts_out = []
|
|
strategies_out = []
|
|
seen_acc = set()
|
|
seen_strat = set()
|
|
|
|
for m in matches:
|
|
if not m.account or m.account.enable != 1:
|
|
continue
|
|
|
|
# 趋势强弱过滤(双重保险)
|
|
strat = m.strategy
|
|
if not strat:
|
|
continue
|
|
if not _strength_compatible(req.trend_strength, strat.fit_trend_strength):
|
|
continue
|
|
|
|
direction = m.force_direction or regime.allow_direction
|
|
|
|
if m.account_id not in seen_acc:
|
|
seen_acc.add(m.account_id)
|
|
accounts_out.append(MatchAccountOut(
|
|
id=m.account.id,
|
|
account_name=m.account.account_name,
|
|
total_capital=m.account.total_capital,
|
|
trade_cycle=m.account.trade_cycle,
|
|
risk_ratio=m.account.risk_ratio,
|
|
force_direction=direction,
|
|
))
|
|
|
|
if m.strategy_id not in seen_strat:
|
|
seen_strat.add(m.strategy_id)
|
|
strategies_out.append(MatchStrategyOut(
|
|
id=strat.id,
|
|
strategy_name=strat.strategy_name,
|
|
fit_cycle=strat.fit_cycle,
|
|
strategy_rule=strat.strategy_rule,
|
|
force_direction=direction,
|
|
))
|
|
|
|
if not accounts_out:
|
|
return MatchResult(
|
|
**base,
|
|
status="disabled",
|
|
message="无可用账户(可能全部被禁用或不匹配当前趋势强弱)",
|
|
)
|
|
|
|
return MatchResult(
|
|
**base,
|
|
status="ok",
|
|
message="匹配成功,以下为前置策略匹配结果(箱体/点位/突破条件需人工确认)",
|
|
accounts=accounts_out,
|
|
strategies=strategies_out,
|
|
)
|
|
|
|
|
|
def _strength_compatible(selected: str, fit: str) -> bool:
|
|
"""判断趋势强弱是否与策略适配"""
|
|
if fit == "全部":
|
|
return True
|
|
if selected == "强" and fit == "强":
|
|
return True
|
|
if selected == "弱" and fit == "弱":
|
|
return True
|
|
return False
|