first commit

This commit is contained in:
dekun
2026-05-28 21:43:23 +08:00
commit 1d5c97904f
33 changed files with 5250 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
"""前置策略匹配核心逻辑
本模块仅根据人工选择的大盘周期、阶段、趋势强弱,
查询匹配绑定表并输出可用账户与策略。
不做任何 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