diff --git a/api/trading.proto b/api/trading.proto index 33e555a..f2467cb 100644 --- a/api/trading.proto +++ b/api/trading.proto @@ -22,6 +22,11 @@ message ReqIndicatorSeries { message RspIndicatorSeries { repeated double matrix = 1; repeated int64 times = 2; + repeated IndicatorState states = 3; +} +message IndicatorState { + string state = 1; + repeated double value = 2; } message ReqStrategySeries { diff --git a/config/exchange.toml b/config/exchange.toml index e65fb93..662a8bd 100644 --- a/config/exchange.toml +++ b/config/exchange.toml @@ -18,9 +18,8 @@ receiveBuffer = 4096 marketSubscribeLimit = 16 consumeBatch = 1024 consumeLater = 2000 # 时间到达later或者数据累计到batch触发consume -httpProxy = "" # httpProxy = "http://192.168.1.5:7890" -# httpProxy = "http://10.255.183.209:7890" +httpProxy = "http://10.255.183.209:7890" # 模拟盘API交易地址如下: # REST:https://www.okx.com diff --git a/internal/trading/sig/indicator_series.go b/internal/trading/sig/indicator_series.go index 394fa9a..8d88c54 100644 --- a/internal/trading/sig/indicator_series.go +++ b/internal/trading/sig/indicator_series.go @@ -1,8 +1,10 @@ package sig import ( + "fmt" "sig-pub/pkg/indicator" "sig-pub/pkg/types/series" + "sig-pub/pkg/utils/collect" ) // WindowIndicatorSeries 封装 @@ -47,3 +49,27 @@ func (s *WindowIndicatorSeries) Series(offset, count int16) (matrix series.Float s.indicatorContext.AddOffset(-offset) return } + +func (s *WindowIndicatorSeries) State(k string, offset int16) (state float64) { + if collect.NotIn(k, s.indicator.Meta().State...) { + panic(fmt.Errorf("indicator %s not export state %s", s.indicator.Meta().Name, k)) + } + _ = s.Get(offset) // 计算指标 + state, ok := s.indicatorContext.State().Get(k, offset) + if !ok { + panic(fmt.Errorf("state %s offset %d not exists", k, offset)) + } + return +} + +func (s *WindowIndicatorSeries) StateSeries(k string, offset, count int16) (matrix series.Floats) { + if collect.NotIn(k, s.indicator.Meta().State...) { + panic(fmt.Errorf("indicator %s not export state %s", s.indicator.Meta().Name, k)) + } + _ = s.Series(offset, count) // 计算指标 + matrix, ok := s.indicatorContext.State().Series(k, offset, count) + if !ok { + panic(fmt.Errorf("state series %s error, offset %d, count %d", k, offset, count)) + } + return +} diff --git a/internal/trading/sig/indicator_state.go b/internal/trading/sig/indicator_state.go index ca72d36..f8559af 100644 --- a/internal/trading/sig/indicator_state.go +++ b/internal/trading/sig/indicator_state.go @@ -15,7 +15,7 @@ type IndicatorState struct { interval types.Interval intervalAdder types.IntervalAdder state map[string]*types.RingSeries[float64] - lastTs int64 + lastTs map[string]int64 } func NewIndicatorState(interval types.Interval) *IndicatorState { @@ -27,6 +27,7 @@ func NewIndicatorState(interval types.Interval) *IndicatorState { interval: interval, intervalAdder: intervalAdder, state: make(map[string]*types.RingSeries[float64]), + lastTs: make(map[string]int64), } } @@ -45,12 +46,13 @@ func (s *IndicatorState) ring(k string) *types.RingSeries[float64] { func (s *IndicatorState) Set(k string, v float64) { ts := s.indicatorContext.Get(0).Ts - if s.lastTs < ts { - if expectTs := s.intervalAdder(s.lastTs, 1); expectTs != ts && s.lastTs != 0 { - panic(fmt.Errorf("state 不连续: lastTs=%d, got=%d, expected=%d", s.lastTs, ts, expectTs)) + if s.lastTs[k] < ts { + // panic可替换为丢失指标用前一个值填充类似vmtsdb + if expectTs := s.intervalAdder(s.lastTs[k], 1); expectTs != ts && s.lastTs[k] != 0 { + panic(fmt.Errorf("state 不连续: lastTs=%d, got=%d, expected=%d", s.lastTs[k], ts, expectTs)) } s.ring(k).Push(v) - s.lastTs = ts + s.lastTs[k] = ts } } @@ -59,7 +61,7 @@ func (s *IndicatorState) Get(k string, offset int16) (v float64, ok bool) { target := s.intervalAdder(ts, -int64(offset)) ring := s.ring(k) for i := 0; i < ring.Length(); i++ { - if s.intervalAdder(s.lastTs, -int64(i)) == target { + if s.intervalAdder(s.lastTs[k], -int64(i)) == target { return ring.Get(i) } } @@ -71,7 +73,7 @@ func (s *IndicatorState) Series(k string, offset, count int16) (v series.Floats, target := s.intervalAdder(ts, -int64(offset)) ring := s.ring(k) for i := 0; i < ring.Length(); i++ { - if s.intervalAdder(s.lastTs, -int64(i)) == target { + if s.intervalAdder(s.lastTs[k], -int64(i)) == target { return ring.Series(i, int(count)) } } diff --git a/internal/trading/trading_grpc_server.go b/internal/trading/trading_grpc_server.go index 7ef4ae3..4ec0131 100644 --- a/internal/trading/trading_grpc_server.go +++ b/internal/trading/trading_grpc_server.go @@ -25,13 +25,19 @@ func (svr *TradingGrpcServer) Init() (err error) { func (svr *TradingGrpcServer) IndicatorSeries(ctx context.Context, req *pb.ReqIndicatorSeries) (rsp *pb.RspIndicatorSeries, err error) { // s, err := structpb.NewStruct(map[string]any{}) input := req.Input.AsMap() - matrix, times, err := svr.tradingService.IndicatorSeries(ctx, req.Indicator, req.Digit, types.Input(input), req.Series) + matrix, times, states, err := svr.tradingService.IndicatorSeries(ctx, req.Indicator, req.Digit, types.Input(input), req.Series) if err != nil { return } rsp = &pb.RspIndicatorSeries{} rsp.Matrix = matrix rsp.Times = times + for state, value := range states { + rsp.States = append(rsp.States, &pb.IndicatorState{ + State: state, + Value: value, + }) + } return } diff --git a/internal/trading/trading_service.go b/internal/trading/trading_service.go index e8f5855..9f1d5dd 100644 --- a/internal/trading/trading_service.go +++ b/internal/trading/trading_service.go @@ -199,7 +199,7 @@ func (svc *TradingService) fetchHistoryKlineSeries(ctx context.Context, sr *pb.S } // IndicatorSeries 获取指标实时或历史序列数据, 闭区间 -func (svc *TradingService) IndicatorSeries(ctx context.Context, indicatorName string, digit int32, input types.Input, sr *pb.SeriesRange) (matrix []float64, times []int64, err error) { +func (svc *TradingService) IndicatorSeries(ctx context.Context, indicatorName string, digit int32, input types.Input, sr *pb.SeriesRange) (matrix []float64, times []int64, states map[string][]float64, err error) { appros := indicator.ApproCandles indicator, ok := svc.indicatorReg.Indicator(indicatorName) if !ok { @@ -228,11 +228,12 @@ func (svc *TradingService) IndicatorSeries(ctx context.Context, indicatorName st srBefore := srRsp.Before sr.WindowExtra = uint32(max(0, candlePeriods-1)) + uint32(appros) - // 保留小数位数 - digit = lang.Ternary(digit > 0 && digit <= 10, digit, 6) + indicatorStates := indicator.Meta().State // 指标导出状态 + digit = lang.Ternary(digit > 0 && digit <= 10, digit, 6) // 保留小数位数 pow := math.Pow(10, float64(digit)) matrix = make([]float64, 0, 200) times = make([]int64, 0, 200) + states = make(map[string][]float64, len(indicatorStates)) err = svc.fetchHistoryKlineSeries(ctx, sr, func(k *types.Kline) (err error) { if lastTs, serial := kSeries.Update(k); !serial { err = fmt.Errorf("kline not series: %s(%s), interval=%s, lastTs=%d", sr.InstId, sr.Exchange, interval, lastTs) @@ -247,6 +248,11 @@ func (svc *TradingService) IndicatorSeries(ctx context.Context, indicatorName st vector := indicator.Calculate(indicatorContext) matrix = append(matrix, math.Round(vector*pow)/pow) times = append(times, indicatorContext.Get(0).Ts) + // 状态填充 + for _, state := range indicatorStates { + sv, _ := indicatorContext.State().Get(state, 0) + states[state] = append(states[state], sv) + } return }) if err != nil { diff --git a/pkg/indicator/atr.go b/pkg/indicator/atr.go index 7297f16..5d3b9dc 100644 --- a/pkg/indicator/atr.go +++ b/pkg/indicator/atr.go @@ -13,7 +13,7 @@ type ATR struct { // indicator interface func (c *ATR) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "atr", + Name: "ATR", Input: []types.InputArg{ {Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, }, diff --git a/pkg/indicator/ema.go b/pkg/indicator/ema.go index 181e16c..01acc08 100644 --- a/pkg/indicator/ema.go +++ b/pkg/indicator/ema.go @@ -10,7 +10,7 @@ type EMA struct { func (c *EMA) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "ema", + Name: "EMA", Input: []types.InputArg{ {Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, }, @@ -24,7 +24,7 @@ func (c *EMA) CandlePeriods(ctx IIndicatorContext) int16 { // Calculate 计算单根k线sma指标 func (c *EMA) Calculate(ctx IIndicatorContext) (vector float64) { window := ctx.Input().Int16("window") - prevEma, ok := ctx.State().Get("vector", 1) + prevEma, ok := ctx.State().Get("_vector", 1) if !ok { // 初始值用 sma 替代 prevEma = ctx.Series(1, window).Close().Avg() @@ -35,6 +35,6 @@ func (c *EMA) Calculate(ctx IIndicatorContext) (vector float64) { vector = multiplier*close + (1-multiplier)*prevEma // same: vector = ((close - prevEma) * multiplier) + prevEma - ctx.State().Set("vector", vector) + ctx.State().Set("_vector", vector) return } diff --git a/pkg/indicator/indicator.go b/pkg/indicator/indicator.go index c0725e5..40e85d0 100644 --- a/pkg/indicator/indicator.go +++ b/pkg/indicator/indicator.go @@ -14,6 +14,7 @@ type IndicatorMeta struct { Name string `json:"name"` // 指标名称 Desc string `json:"desc"` // 指标描述 Input []types.InputArg `json:"input"` // 输入参数 + State []string `json:"state"` // 向外暴露状态 } // IIndicator 指标基础计算接口 @@ -43,6 +44,9 @@ type IIndicatorSeries interface { CandlePeriods() int16 Get(offset int16) (vector float64) Series(offset, count int16) (matrix series.Floats) + // 获取指标计算过程中的状态值 + State(k string, offset int16) (state float64) + StateSeries(k string, offset, count int16) (matrix series.Floats) } type IIndicatorState interface { diff --git a/pkg/indicator/indicator_registry.go b/pkg/indicator/indicator_registry.go index 8de38f7..a1cc56d 100644 --- a/pkg/indicator/indicator_registry.go +++ b/pkg/indicator/indicator_registry.go @@ -18,23 +18,24 @@ func NewIndicatorRegistry() *IndicatorRegistry { func (r *IndicatorRegistry) Init() (err error) { // indicator regist - r.MustRegistIndicatorW(&RSI{}) - r.MustRegistIndicatorW(&SMA{}) - r.MustRegistIndicatorW(&ATR{}) - r.MustRegistIndicatorW(&EMA{}) - r.MustRegistIndicatorW(&MacdDIF{}) - r.MustRegistIndicatorW(&MacdDEA{}) - r.MustRegistIndicatorW(&Macd{}) - r.MustRegistIndicatorW(&OBV{}) - r.MustRegistIndicatorW(&WOBV{}) - r.MustRegistIndicatorW(&BollMB{}) - r.MustRegistIndicatorW(&BollUB{}) - r.MustRegistIndicatorW(&BollLB{}) + r.MustRegistIndicator(&RSI{}) + r.MustRegistIndicator(&SMA{}) + r.MustRegistIndicator(&ATR{}) + r.MustRegistIndicator(&EMA{}) + r.MustRegistIndicator(&MacdDIF{}) + r.MustRegistIndicator(&MacdDEA{}) + r.MustRegistIndicator(&Macd{}) + r.MustRegistIndicator(&OBV{}) + r.MustRegistIndicator(&WOBV{}) + r.MustRegistIndicator(&BollMB{}) + r.MustRegistIndicator(&BollUB{}) + r.MustRegistIndicator(&BollLB{}) + r.MustRegistIndicator(&SuperTrend{}) return } -// RegistIndicatorW -func (r *IndicatorRegistry) RegistIndicatorW(ind IIndicator) (err error) { +// RegistIndicator +func (r *IndicatorRegistry) RegistIndicator(ind IIndicator) (err error) { indName := ind.Meta().Name _, loaded := r.indicators.LoadOrStore(indName, ind) if loaded { @@ -44,8 +45,8 @@ func (r *IndicatorRegistry) RegistIndicatorW(ind IIndicator) (err error) { return } -func (r *IndicatorRegistry) MustRegistIndicatorW(ind IIndicator) { - if err := r.RegistIndicatorW(ind); err != nil { +func (r *IndicatorRegistry) MustRegistIndicator(ind IIndicator) { + if err := r.RegistIndicator(ind); err != nil { panic(err) } } diff --git a/pkg/indicator/macd.go b/pkg/indicator/macd.go index 8df476d..fe2b170 100644 --- a/pkg/indicator/macd.go +++ b/pkg/indicator/macd.go @@ -14,7 +14,7 @@ type Macd struct { func (c *Macd) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "macd", + Name: "Macd", Input: []types.InputArg{ {Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"}, {Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"}, @@ -25,14 +25,14 @@ func (c *Macd) Meta() IndicatorMeta { func (c *Macd) CandlePeriods(ctx IIndicatorContext) int16 { return max( - ctx.Indicator("macd_dif", ctx.Input()).CandlePeriods(), - ctx.Indicator("macd_dea", ctx.Input()).CandlePeriods(), + ctx.Indicator("MacdDIF", ctx.Input()).CandlePeriods(), + ctx.Indicator("MacdDEA", ctx.Input()).CandlePeriods(), ) } func (c *Macd) Calculate(ctx IIndicatorContext) (vector float64) { - macd_dea := ctx.Indicator("macd_dea", ctx.Input()).Get(0) - macd_dif := ctx.Indicator("macd_dif", ctx.Input()).Get(0) + macd_dea := ctx.Indicator("MacdDEA", ctx.Input()).Get(0) + macd_dif := ctx.Indicator("MacdDIF", ctx.Input()).Get(0) vector = (macd_dif - macd_dea) * 2 return } @@ -43,7 +43,7 @@ type MacdDIF struct { // indicator interface func (c *MacdDIF) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "macd_dif", + Name: "MacdDIF", Input: []types.InputArg{ {Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"}, {Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"}, @@ -53,8 +53,8 @@ func (c *MacdDIF) Meta() IndicatorMeta { func (c *MacdDIF) CandlePeriods(ctx IIndicatorContext) int16 { return max( - ctx.Indicator("ema", ctx.Input().Int16("fast")).CandlePeriods(), - ctx.Indicator("ema", ctx.Input().Int16("slow")).CandlePeriods(), + ctx.Indicator("EMA", ctx.Input().Int16("fast")).CandlePeriods(), + ctx.Indicator("EMA", ctx.Input().Int16("slow")).CandlePeriods(), ) } @@ -64,8 +64,8 @@ func (c *MacdDIF) Calculate(ctx IIndicatorContext) (vector float64) { slow := ctx.Input().Int16("slow") // 26 // macd计算从第max(fast, slow)期开始稳定 - fastEma := ctx.Indicator("ema", fast).Get(0) - slowEma := ctx.Indicator("ema", slow).Get(0) + fastEma := ctx.Indicator("EMA", fast).Get(0) + slowEma := ctx.Indicator("EMA", slow).Get(0) macd := fastEma - slowEma vector = macd return @@ -77,7 +77,7 @@ type MacdDEA struct { func (c *MacdDEA) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "macd_dea", + Name: "MacdDEA", Input: []types.InputArg{ {Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"}, {Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"}, @@ -87,23 +87,23 @@ func (c *MacdDEA) Meta() IndicatorMeta { } func (c *MacdDEA) CandlePeriods(ctx IIndicatorContext) int16 { - return ctx.Indicator("macd_dif", ctx.Input()).CandlePeriods() + ctx.Input().Int16("singal") + 1 + return ctx.Indicator("MacdDIF", ctx.Input()).CandlePeriods() + ctx.Input().Int16("singal") + 1 } func (c *MacdDEA) Calculate(ctx IIndicatorContext) (vector float64) { singal := ctx.Input().Int16("singal") // 9 - deaPrev, ok := ctx.State().Get("vector", 1) + deaPrev, ok := ctx.State().Get("_vector", 1) if !ok { // 初始值前9期的 MACD_DIF SMA - macdDifs := ctx.Indicator("macd_dif", ctx.Input()).Series(1, singal) + macdDifs := ctx.Indicator("MacdDIF", ctx.Input()).Series(1, singal) deaPrev = macdDifs.Avg() } - macd_dif := ctx.Indicator("macd_dif", ctx.Input()).Get(0) + macd_dif := ctx.Indicator("MacdDIF", ctx.Input()).Get(0) // 计算DEA beta := 2 / float64(singal+1) dea := beta*macd_dif + (1-beta)*deaPrev - ctx.State().Set("vector", dea) + ctx.State().Set("_vector", dea) vector = dea return diff --git a/pkg/indicator/obv.go b/pkg/indicator/obv.go index d9c5ff7..2fb3653 100644 --- a/pkg/indicator/obv.go +++ b/pkg/indicator/obv.go @@ -13,7 +13,7 @@ type OBV struct { func (c *OBV) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "obv", + Name: "OBV", Input: []types.InputArg{}, // todo 无参指标tsdb存储 } } @@ -23,7 +23,7 @@ func (c *OBV) CandlePeriods(ctx IIndicatorContext) int16 { } func (c *OBV) Calculate(ctx IIndicatorContext) (vector float64) { - obvPrev, ok := ctx.State().Get("obv", 1) + obvPrev, ok := ctx.State().Get("_vector", 1) if !ok { obvPrev = 0 } @@ -36,6 +36,6 @@ func (c *OBV) Calculate(ctx IIndicatorContext) (vector float64) { } else { vector = obvPrev } - ctx.State().Set("obv", vector) + ctx.State().Set("_vector", vector) return } diff --git a/pkg/indicator/rsi.go b/pkg/indicator/rsi.go index 5c33c7c..c811f71 100644 --- a/pkg/indicator/rsi.go +++ b/pkg/indicator/rsi.go @@ -14,7 +14,7 @@ type RSI struct { // indicator interface func (c *RSI) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "rsi", + Name: "RSI", Input: []types.InputArg{ {Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, }, diff --git a/pkg/indicator/sam.go b/pkg/indicator/sam.go index 083c139..a51248e 100644 --- a/pkg/indicator/sam.go +++ b/pkg/indicator/sam.go @@ -2,8 +2,6 @@ package indicator import ( "sig-pub/pkg/types" - - "github.com/markcheno/go-talib" ) // RSI stateless indicator @@ -14,7 +12,7 @@ type SMA struct { // indicator interface func (c *SMA) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "sma", + Name: "SMA", Input: []types.InputArg{ {Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, }, @@ -29,8 +27,8 @@ func (c *SMA) CandlePeriods(ctx IIndicatorContext) int16 { func (c *SMA) Calculate(ctx IIndicatorContext) (vector float64) { window := ctx.Input().Int16("window") closeSeries := ctx.Series(0, window).Close() - sma := talib.Sma(closeSeries, int(window)) - _ = sma[len(sma)-1] + // sma := talib.Sma(closeSeries, int(window)) + // _ = sma[len(sma)-1] vector = closeSeries.Avg() return } diff --git a/pkg/indicator/super_trend.go b/pkg/indicator/super_trend.go new file mode 100644 index 0000000..02ff500 --- /dev/null +++ b/pkg/indicator/super_trend.go @@ -0,0 +1,72 @@ +package indicator + +import "sig-pub/pkg/types" + +// SuperTrend 超级趋势 +type SuperTrend struct { +} + +func (c SuperTrend) Meta() IndicatorMeta { + return IndicatorMeta{ + Name: "SuperTrend", + Input: []types.InputArg{ + {Name: "window", Type: types.InputTypeUInt, Desc: "ATR周期(7/14)"}, + {Name: "mul", Type: types.InputTypeUInt, Desc: "乘数(建议2-4)"}, + }, + State: []string{"direction"}, + } +} + +func (c SuperTrend) CandlePeriods(ctx IIndicatorContext) int16 { + return ctx.Indicator("ATR", ctx.Input().Int16("window")).CandlePeriods() +} + +func (c SuperTrend) Calculate(ctx IIndicatorContext) (vector float64) { + window := ctx.Input().Int16("window") + mul := ctx.Input().Float("mul") + + atr := ctx.Indicator("ATR", window).Get(0) + hl2 := ctx.Get(0).HL2() + closeP := ctx.Get(0).CloseF64() + + upper := hl2 + mul*atr // 潛在上漲時的阻力位 + lower := hl2 - mul*atr // 潛在下跌時的支撐位 + + prevTrend, ok := ctx.State().Get("_trend", 1) + prevDirection, _ := ctx.State().Get("direction", 1) // 方向: 1.up, -1.down + + // 1.初始化 + if !ok { + if closeP > upper { + prevTrend = lower + prevDirection = 1 + } else { + prevTrend = upper + prevDirection = -1 + } + ctx.State().Set("_trend", prevTrend) + ctx.State().Set("direction", prevDirection) + return prevTrend + } + + // 2.迭代计算 + trend, direction := prevTrend, prevDirection + if prevDirection == 1 { + // uptrend + trend = max(lower, prevTrend) + if closeP < prevTrend { + trend = upper // 取上轨作为新红线 + direction = -1 // 转下跌趋势 + } + } else { + // downtrend + trend = min(upper, prevTrend) + if closeP > prevTrend { + trend = lower // 取下轨作为新绿线 + direction = 1 // 转上升趋势 + } + } + ctx.State().Set("_trend", trend) + ctx.State().Set("direction", direction) + return trend +} diff --git a/pkg/indicator/wobv.go b/pkg/indicator/wobv.go index 91652c4..5403c22 100644 --- a/pkg/indicator/wobv.go +++ b/pkg/indicator/wobv.go @@ -12,7 +12,7 @@ type WOBV struct { func (c *WOBV) Meta() IndicatorMeta { return IndicatorMeta{ - Name: "wobv", + Name: "WOBV", Input: []types.InputArg{}, // todo 无参指标tsdb存储 } } @@ -22,7 +22,7 @@ func (c *WOBV) CandlePeriods(ctx IIndicatorContext) int16 { } func (c *WOBV) Calculate(ctx IIndicatorContext) (vector float64) { - wobvPrev, ok := ctx.State().Get("wobv", 1) + wobvPrev, ok := ctx.State().Get("_vector", 1) if !ok { wobvPrev = 0 } @@ -30,7 +30,7 @@ func (c *WOBV) Calculate(ctx IIndicatorContext) (vector float64) { k := ctx.Get(0) wf := (k.CloseF64() - k.OpenF64()) / (k.HighF64() - k.LowF64()) wobv := wobvPrev + wf*k.VolF64() - ctx.State().Set("wobv", wobv) + ctx.State().Set("_vector", wobv) vector = wobv return diff --git a/pkg/strategy/gold_x.go b/pkg/strategy/gold_x.go index bb06b70..793caf8 100644 --- a/pkg/strategy/gold_x.go +++ b/pkg/strategy/gold_x.go @@ -32,25 +32,23 @@ func (s *GoldX) Init(input types.Input) (err error) { func (s *GoldX) CandlePeriods(ctx ISingleSigStrategyContext) int16 { return max( - ctx.Indicator("macd", ctx.Input()).CandlePeriods(), - ctx.Indicator("macd_dif", ctx.Input()).CandlePeriods(), - ctx.Indicator("macd_dea", ctx.Input()).CandlePeriods(), + ctx.Indicator("Macd", ctx.Input()).CandlePeriods(), + ctx.Indicator("MacdDIF", ctx.Input()).CandlePeriods(), + ctx.Indicator("MacdDEA", ctx.Input()).CandlePeriods(), ) } func (s *GoldX) Update(ctx ISingleSigStrategyContext) (side types.Side) { - macdHist := ctx.Indicator("macd", ctx.Input()).Get(0) // macd柱状图 - macdDea := ctx.Indicator("macd_dea", ctx.Input()).Series(0, 2) // macd_dea信号线 - macdDif := ctx.Indicator("macd_dif", ctx.Input()).Series(0, 2) // macd_dif线 + macdHist := ctx.Indicator("Macd", ctx.Input()).Get(0) // macd柱状图 + macdDea := ctx.Indicator("MacdDEA", ctx.Input()).Series(0, 2) // macd_dea信号线 + macdDif := ctx.Indicator("MacdDIF", ctx.Input()).Series(0, 2) // macd_dif线 // todo 包装方法 crossover/crossunder // 1.MACD DIF线接近或上穿零轴(表示整体多头市场) crossover := macdDif[0] > macdDea[0] && macdDif[1] < macdDea[1] // 上穿 crossunder := macdDif[0] < macdDea[0] && macdDif[1] > macdDea[1] // 下穿 - ts := ctx.Get(0).Ts - _ = ts + if crossover { - _ = macdHist // 2.附加确认条件: 柱状图从负值转为正值 if macdHist > 0 { // todo 3.成交量放大(结合 OBV 等指标验证资金流入)。 diff --git a/pkg/strategy/super_trend.go b/pkg/strategy/super_trend_bos_waves.go similarity index 100% rename from pkg/strategy/super_trend.go rename to pkg/strategy/super_trend_bos_waves.go diff --git a/pkg/strategy/super_trend_rsi.go b/pkg/strategy/super_trend_rsi.go new file mode 100644 index 0000000..e885252 --- /dev/null +++ b/pkg/strategy/super_trend_rsi.go @@ -0,0 +1,50 @@ +package strategy + +import "sig-pub/pkg/types" + +// SuperTrendRSI 结合super trend和rsi指标策略 +type SuperTrendRSI struct { +} + +func (s *SuperTrendRSI) New() ISigStrategy { + return &SuperTrendRSI{} +} + +func (s *SuperTrendRSI) Meta() StrategyMeta { + return StrategyMeta{ + Name: "SuperTrendRSI", + Desc: "金叉策略", + Input: []types.InputArg{ + {Name: "trendWindow", Type: types.InputTypeUInt, Desc: "SuperTrend ATR周期"}, + {Name: "trendMultipiler", Type: types.InputTypeUInt, Desc: "SuperTrend multipiler"}, + {Name: "rsiWindow", Type: types.InputTypeUInt, Desc: "rsi周期"}, + }, + } +} + +// Init 校验参数, 并根据参数初始化策略 +func (s *SuperTrendRSI) Init(input types.Input) (err error) { + return +} + +func (s *SuperTrendRSI) CandlePeriods(ctx ISingleSigStrategyContext) int16 { + return max( + ctx.Indicator("SuperTrend", types.Input{ + "window": ctx.Input().Int16("trendPeriod"), + "mul": ctx.Input().Int16("trendMultipiler"), + }).CandlePeriods(), + ctx.Indicator("RSI", types.Input{"window": ctx.Input().Int16("rsiWindow")}).CandlePeriods(), + ) +} + +func (s *SuperTrendRSI) Update(ctx ISingleSigStrategyContext) (side types.Side) { + superTrend := ctx.Indicator("SuperTrend", types.Input{ + "window": ctx.Input().Int16("trendPeriod"), + "mul": ctx.Input().Int16("trendMultipiler"), + }) + rsi := ctx.Indicator("RSI", types.Input{"window": ctx.Input().Int16("rsiWindow")}) + + _, _ = superTrend, rsi + + return +}