// Package strategy 提供内置回测策略(MVC Service 层)。 // 用户可在 backtest.Strategy 接口基础上扩展自定义轮动/网格等策略。 package strategy import ( "context" "fmt" "sort" "stock-analysis/internal/backtest" ) // LowPriceParams 低价轮动策略参数。 type LowPriceParams struct { TopN int // 持仓数量 Rebalance int // 调仓周期(交易日) MinPrice float64 // 价格下限(过滤异常低价/退市风险债) MaxPrice float64 // 价格上限(低价策略通常低于 130) } // DefaultLowPriceParams 返回推荐默认参数。 func DefaultLowPriceParams() LowPriceParams { return LowPriceParams{TopN: 10, Rebalance: 21, MinPrice: 80, MaxPrice: 130} } // LowPrice 低价轮动策略:每 Rebalance 个交易日,选择全市场价格最低的 TopN // 只转债等权持有。基于可转债"下有保底"特性,低价格通常意味着较低的下行风险, // 是经典的可转债轮动框架(演示用,可替换为双低/溢价等因子)。 type LowPrice struct { params LowPriceParams day int // 已执行的交易日计数 } // NewLowPrice 创建低价轮动策略。 func NewLowPrice(p LowPriceParams) *LowPrice { return &LowPrice{params: p} } // Name 返回策略名称。 func (s *LowPrice) Name() string { return fmt.Sprintf("低价轮动(top%d,每%d交易日)", s.params.TopN, s.params.Rebalance) } // OnBar 实现 backtest.Strategy:交易日递增,到调仓日时选股返回目标持仓。 func (s *LowPrice) OnBar(ctx context.Context, date string, universe []backtest.Quote, hist *backtest.History) ([]backtest.Target, error) { s.day++ if s.day > 1 && (s.day-1)%s.params.Rebalance != 0 { return nil, nil // 非调仓日 } candidates := make([]backtest.Quote, 0, len(universe)) for _, q := range universe { if q.Price >= s.params.MinPrice && q.Price <= s.params.MaxPrice { candidates = append(candidates, q) } } sort.Slice(candidates, func(i, j int) bool { return candidates[i].Price < candidates[j].Price }) if len(candidates) > s.params.TopN { candidates = candidates[:s.params.TopN] } if len(candidates) == 0 { return nil, nil // 无合格标的,保持现状 } weight := 1.0 / float64(len(candidates)) targets := make([]backtest.Target, 0, len(candidates)) for _, q := range candidates { targets = append(targets, backtest.Target{Code: q.Code, Weight: weight}) } return targets, nil }