package indicator import ( "encoding/json" "fmt" "git.apinb.com/bsm-sdk/core/utils" "git.apinb.com/quant/gostock/internal/impl" "git.apinb.com/quant/gostock/internal/models" talib "github.com/markcheno/go-talib" ) var ( offset = 1 // 偏移量 ) type StockArgConf struct { BestByDrawdown string `json:"best_by_drawdown"` BestByProfit string `json:"best_by_profit"` BestByReturn string `json:"best_by_return"` BestBySharpe string `json:"best_by_sharpe"` BestByWinRate string `json:"best_by_win_rate"` } type RsiResult struct { Score int Oversold int Prve float64 Last float64 Desc string } func GetArgConfig(code string) (*models.StockArgs, *StockArgConf, error) { var args models.StockArgs err := impl.DBService.Where("ts_code = ?", code).First(&args).Error if err != nil { return nil, nil, err } var conf StockArgConf err = json.Unmarshal([]byte(args.Config), &conf) if err != nil { return nil, nil, err } return &args, &conf, nil } func RunRsi(code string) *RsiResult { args, conf, err := GetArgConfig(code) if err != nil { return &RsiResult{Score: -1, Desc: "RSI参数错误!"} } if args.RsiOversold == 0 { return &RsiResult{Score: -1, Desc: "RSI Oversold=0,参数错误!"} } if conf.BestByProfit != "rsi" { return &RsiResult{Score: -1, Desc: "BestByProfit不是RSI"} } var close []float64 impl.DBService.Model(models.StockDaily{}).Where("ts_code = ?", code).Order("trade_date desc").Limit(args.RsiPeriod*4).Pluck("close", &close) if len(close) < args.RsiPeriod { return &RsiResult{Score: -1, Desc: "数据不足"} } newCloses := ReverseSlice(close) args.RsiOversold = args.RsiOversold + offset rsiResult := talib.Rsi(newCloses, args.RsiPeriod) prveRsi := utils.FloatRound(rsiResult[len(rsiResult)-2], 2) lastRsi := utils.FloatRound(rsiResult[len(rsiResult)-1], 2) r := &RsiResult{Oversold: args.RsiOversold, Prve: prveRsi, Last: lastRsi} prveRsiInt := int(prveRsi) lastRsiInt := int(lastRsi) if lastRsiInt == 0 { r.Score = -1 r.Desc = "RSI lastRsiInt=0,计算错误!" return r } // 跌破RSI下轨 if lastRsiInt > args.RsiOversold { if CheckLowest(close, lastRsiInt, 14) { r.Score = 1 r.Desc = fmt.Sprintf("RSI=%d 跌破下轨,14日最低", lastRsiInt) return r } if CheckLowest(close, lastRsiInt, 20) { r.Score = 1 r.Desc = fmt.Sprintf("RSI=%d 跌破下轨,20日最低", lastRsiInt) return r } r.Score = -1 r.Desc = fmt.Sprintf("RSI=%d 高于Oversold%d", lastRsiInt, args.RsiOversold) return r } // RSI跌破下轨后呈上涨趋势 if lastRsiInt < prveRsiInt { r.Score = -1 r.Desc = fmt.Sprintf("Rsi=%d prveRsi=%d,突破下轨,持续下跌", lastRsiInt, prveRsiInt) return r } else if lastRsiInt == prveRsiInt { r.Score = 1 r.Desc = fmt.Sprintf("Rsi=%d prveRsi=%d,突破下轨,与前一交易日无太大波动", lastRsiInt, prveRsiInt) return r } r.Score = 1 r.Desc = fmt.Sprintf("Rsi=%d prveRsi=%d,突破下轨后呈上涨趋势", lastRsiInt, prveRsiInt) return r }