package indicator import ( "fmt" "sig-pub/api/pb" "sig-pub/pkg/types" ) // RSI stateless indicator // 相对强弱指数 (RSI) rsi define: https://www.investopedia.com/terms/r/rsi.asp type RSI struct { } // indicator interface func (c *RSI) Meta() IndicatorMeta { return IndicatorMeta{ Name: "RSI", Input: []types.InputArg{ {Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, }, } } func (c *RSI) CandlePeriods(ctx IIndicatorContext) int16 { return ctx.Input().Int16("window") } // Calculate 计算单根k线rsi指标 func (c *RSI) Calculate(ctx IIndicatorContext) (vector float64) { window := ctx.Input().Int16("window") // 读k线, 计算 klineSeries := ctx.Series(0, int16(window)) closeSeries := klineSeries.Close() closeDiff := closeSeries.Diff() avgGain := closeDiff.PositiveValuesOrZero().Abs().Sum() / float64(window) avgLoss := closeDiff.NegativeValuesOrZero().Abs().Sum() / float64(window) rs := avgGain / avgLoss rsi := 100 - (100 / (1 + rs)) return rsi } func (c *RSI) QueryRange(exchange pb.ExchangeType, instId string, interval types.Interval, rsi int) (query string, err error) { var r types.MeticMatrix _ = r intervalAdder, ok := types.SupportedIntervals[interval] if !ok { err = fmt.Errorf("unsupport interval %s", interval) return } minutes := intervalAdder(0, int64(rsi)) / 1000 / 60 query = fmt.Sprintf(` 100 - 100 / (1 + ( avg_over_time(clamp_min(delta(%s{kind="close", interval="%s", exchange="%s"}), 0)[%dm]) / avg_over_time(abs(clamp_max(delta(%s{kind="close", interval="%s", exchange="%s"}), 0))[%dm]) )) `, instId, interval, exchange, minutes, instId, interval, exchange, minutes) return }