Browse Source

indicator super_trend

main
strange 9 months ago
parent
commit
fbc52f9ede
  1. 5
      api/trading.proto
  2. 3
      config/exchange.toml
  3. 26
      internal/trading/sig/indicator_series.go
  4. 16
      internal/trading/sig/indicator_state.go
  5. 8
      internal/trading/trading_grpc_server.go
  6. 12
      internal/trading/trading_service.go
  7. 2
      pkg/indicator/atr.go
  8. 6
      pkg/indicator/ema.go
  9. 4
      pkg/indicator/indicator.go
  10. 33
      pkg/indicator/indicator_registry.go
  11. 32
      pkg/indicator/macd.go
  12. 6
      pkg/indicator/obv.go
  13. 2
      pkg/indicator/rsi.go
  14. 8
      pkg/indicator/sam.go
  15. 72
      pkg/indicator/super_trend.go
  16. 6
      pkg/indicator/wobv.go
  17. 16
      pkg/strategy/gold_x.go
  18. 0
      pkg/strategy/super_trend_bos_waves.go
  19. 50
      pkg/strategy/super_trend_rsi.go

5
api/trading.proto

@ -22,6 +22,11 @@ message ReqIndicatorSeries {
message RspIndicatorSeries { message RspIndicatorSeries {
repeated double matrix = 1; repeated double matrix = 1;
repeated int64 times = 2; repeated int64 times = 2;
repeated IndicatorState states = 3;
}
message IndicatorState {
string state = 1;
repeated double value = 2;
} }
message ReqStrategySeries { message ReqStrategySeries {

3
config/exchange.toml

@ -18,9 +18,8 @@ receiveBuffer = 4096
marketSubscribeLimit = 16 marketSubscribeLimit = 16
consumeBatch = 1024 consumeBatch = 1024
consumeLater = 2000 # 时间到达later或者数据累计到batch触发consume consumeLater = 2000 # 时间到达later或者数据累计到batch触发consume
httpProxy = ""
# httpProxy = "http://192.168.1.5:7890" # httpProxy = "http://192.168.1.5:7890"
# httpProxy = "http://10.255.183.209:7890" httpProxy = "http://10.255.183.209:7890"
# 模拟盘API交易地址如下: # 模拟盘API交易地址如下:
# REST:https://www.okx.com # REST:https://www.okx.com

26
internal/trading/sig/indicator_series.go

@ -1,8 +1,10 @@
package sig package sig
import ( import (
"fmt"
"sig-pub/pkg/indicator" "sig-pub/pkg/indicator"
"sig-pub/pkg/types/series" "sig-pub/pkg/types/series"
"sig-pub/pkg/utils/collect"
) )
// WindowIndicatorSeries 封装 // WindowIndicatorSeries 封装
@ -47,3 +49,27 @@ func (s *WindowIndicatorSeries) Series(offset, count int16) (matrix series.Float
s.indicatorContext.AddOffset(-offset) s.indicatorContext.AddOffset(-offset)
return 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
}

16
internal/trading/sig/indicator_state.go

@ -15,7 +15,7 @@ type IndicatorState struct {
interval types.Interval interval types.Interval
intervalAdder types.IntervalAdder intervalAdder types.IntervalAdder
state map[string]*types.RingSeries[float64] state map[string]*types.RingSeries[float64]
lastTs int64 lastTs map[string]int64
} }
func NewIndicatorState(interval types.Interval) *IndicatorState { func NewIndicatorState(interval types.Interval) *IndicatorState {
@ -27,6 +27,7 @@ func NewIndicatorState(interval types.Interval) *IndicatorState {
interval: interval, interval: interval,
intervalAdder: intervalAdder, intervalAdder: intervalAdder,
state: make(map[string]*types.RingSeries[float64]), 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) { func (s *IndicatorState) Set(k string, v float64) {
ts := s.indicatorContext.Get(0).Ts ts := s.indicatorContext.Get(0).Ts
if s.lastTs < ts { if s.lastTs[k] < ts {
if expectTs := s.intervalAdder(s.lastTs, 1); expectTs != ts && s.lastTs != 0 { // panic可替换为丢失指标用前一个值填充类似vmtsdb
panic(fmt.Errorf("state 不连续: lastTs=%d, got=%d, expected=%d", s.lastTs, ts, expectTs)) 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.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)) target := s.intervalAdder(ts, -int64(offset))
ring := s.ring(k) ring := s.ring(k)
for i := 0; i < ring.Length(); i++ { 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) 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)) target := s.intervalAdder(ts, -int64(offset))
ring := s.ring(k) ring := s.ring(k)
for i := 0; i < ring.Length(); i++ { 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)) return ring.Series(i, int(count))
} }
} }

8
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) { func (svr *TradingGrpcServer) IndicatorSeries(ctx context.Context, req *pb.ReqIndicatorSeries) (rsp *pb.RspIndicatorSeries, err error) {
// s, err := structpb.NewStruct(map[string]any{}) // s, err := structpb.NewStruct(map[string]any{})
input := req.Input.AsMap() 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 { if err != nil {
return return
} }
rsp = &pb.RspIndicatorSeries{} rsp = &pb.RspIndicatorSeries{}
rsp.Matrix = matrix rsp.Matrix = matrix
rsp.Times = times rsp.Times = times
for state, value := range states {
rsp.States = append(rsp.States, &pb.IndicatorState{
State: state,
Value: value,
})
}
return return
} }

12
internal/trading/trading_service.go

@ -199,7 +199,7 @@ func (svc *TradingService) fetchHistoryKlineSeries(ctx context.Context, sr *pb.S
} }
// IndicatorSeries 获取指标实时或历史序列数据, 闭区间 // 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 appros := indicator.ApproCandles
indicator, ok := svc.indicatorReg.Indicator(indicatorName) indicator, ok := svc.indicatorReg.Indicator(indicatorName)
if !ok { if !ok {
@ -228,11 +228,12 @@ func (svc *TradingService) IndicatorSeries(ctx context.Context, indicatorName st
srBefore := srRsp.Before srBefore := srRsp.Before
sr.WindowExtra = uint32(max(0, candlePeriods-1)) + uint32(appros) sr.WindowExtra = uint32(max(0, candlePeriods-1)) + uint32(appros)
// 保留小数位数 indicatorStates := indicator.Meta().State // 指标导出状态
digit = lang.Ternary(digit > 0 && digit <= 10, digit, 6) digit = lang.Ternary(digit > 0 && digit <= 10, digit, 6) // 保留小数位数
pow := math.Pow(10, float64(digit)) pow := math.Pow(10, float64(digit))
matrix = make([]float64, 0, 200) matrix = make([]float64, 0, 200)
times = make([]int64, 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) { err = svc.fetchHistoryKlineSeries(ctx, sr, func(k *types.Kline) (err error) {
if lastTs, serial := kSeries.Update(k); !serial { 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) 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) vector := indicator.Calculate(indicatorContext)
matrix = append(matrix, math.Round(vector*pow)/pow) matrix = append(matrix, math.Round(vector*pow)/pow)
times = append(times, indicatorContext.Get(0).Ts) times = append(times, indicatorContext.Get(0).Ts)
// 状态填充
for _, state := range indicatorStates {
sv, _ := indicatorContext.State().Get(state, 0)
states[state] = append(states[state], sv)
}
return return
}) })
if err != nil { if err != nil {

2
pkg/indicator/atr.go

@ -13,7 +13,7 @@ type ATR struct {
// indicator interface // indicator interface
func (c *ATR) Meta() IndicatorMeta { func (c *ATR) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "atr", Name: "ATR",
Input: []types.InputArg{ Input: []types.InputArg{
{Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, {Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"},
}, },

6
pkg/indicator/ema.go

@ -10,7 +10,7 @@ type EMA struct {
func (c *EMA) Meta() IndicatorMeta { func (c *EMA) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "ema", Name: "EMA",
Input: []types.InputArg{ Input: []types.InputArg{
{Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, {Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"},
}, },
@ -24,7 +24,7 @@ func (c *EMA) CandlePeriods(ctx IIndicatorContext) int16 {
// Calculate 计算单根k线sma指标 // Calculate 计算单根k线sma指标
func (c *EMA) Calculate(ctx IIndicatorContext) (vector float64) { func (c *EMA) Calculate(ctx IIndicatorContext) (vector float64) {
window := ctx.Input().Int16("window") window := ctx.Input().Int16("window")
prevEma, ok := ctx.State().Get("vector", 1) prevEma, ok := ctx.State().Get("_vector", 1)
if !ok { if !ok {
// 初始值用 sma 替代 // 初始值用 sma 替代
prevEma = ctx.Series(1, window).Close().Avg() 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 vector = multiplier*close + (1-multiplier)*prevEma
// same: vector = ((close - prevEma) * multiplier) + prevEma // same: vector = ((close - prevEma) * multiplier) + prevEma
ctx.State().Set("vector", vector) ctx.State().Set("_vector", vector)
return return
} }

4
pkg/indicator/indicator.go

@ -14,6 +14,7 @@ type IndicatorMeta struct {
Name string `json:"name"` // 指标名称 Name string `json:"name"` // 指标名称
Desc string `json:"desc"` // 指标描述 Desc string `json:"desc"` // 指标描述
Input []types.InputArg `json:"input"` // 输入参数 Input []types.InputArg `json:"input"` // 输入参数
State []string `json:"state"` // 向外暴露状态
} }
// IIndicator 指标基础计算接口 // IIndicator 指标基础计算接口
@ -43,6 +44,9 @@ type IIndicatorSeries interface {
CandlePeriods() int16 CandlePeriods() int16
Get(offset int16) (vector float64) Get(offset int16) (vector float64)
Series(offset, count int16) (matrix series.Floats) 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 { type IIndicatorState interface {

33
pkg/indicator/indicator_registry.go

@ -18,23 +18,24 @@ func NewIndicatorRegistry() *IndicatorRegistry {
func (r *IndicatorRegistry) Init() (err error) { func (r *IndicatorRegistry) Init() (err error) {
// indicator regist // indicator regist
r.MustRegistIndicatorW(&RSI{}) r.MustRegistIndicator(&RSI{})
r.MustRegistIndicatorW(&SMA{}) r.MustRegistIndicator(&SMA{})
r.MustRegistIndicatorW(&ATR{}) r.MustRegistIndicator(&ATR{})
r.MustRegistIndicatorW(&EMA{}) r.MustRegistIndicator(&EMA{})
r.MustRegistIndicatorW(&MacdDIF{}) r.MustRegistIndicator(&MacdDIF{})
r.MustRegistIndicatorW(&MacdDEA{}) r.MustRegistIndicator(&MacdDEA{})
r.MustRegistIndicatorW(&Macd{}) r.MustRegistIndicator(&Macd{})
r.MustRegistIndicatorW(&OBV{}) r.MustRegistIndicator(&OBV{})
r.MustRegistIndicatorW(&WOBV{}) r.MustRegistIndicator(&WOBV{})
r.MustRegistIndicatorW(&BollMB{}) r.MustRegistIndicator(&BollMB{})
r.MustRegistIndicatorW(&BollUB{}) r.MustRegistIndicator(&BollUB{})
r.MustRegistIndicatorW(&BollLB{}) r.MustRegistIndicator(&BollLB{})
r.MustRegistIndicator(&SuperTrend{})
return return
} }
// RegistIndicatorW // RegistIndicator
func (r *IndicatorRegistry) RegistIndicatorW(ind IIndicator) (err error) { func (r *IndicatorRegistry) RegistIndicator(ind IIndicator) (err error) {
indName := ind.Meta().Name indName := ind.Meta().Name
_, loaded := r.indicators.LoadOrStore(indName, ind) _, loaded := r.indicators.LoadOrStore(indName, ind)
if loaded { if loaded {
@ -44,8 +45,8 @@ func (r *IndicatorRegistry) RegistIndicatorW(ind IIndicator) (err error) {
return return
} }
func (r *IndicatorRegistry) MustRegistIndicatorW(ind IIndicator) { func (r *IndicatorRegistry) MustRegistIndicator(ind IIndicator) {
if err := r.RegistIndicatorW(ind); err != nil { if err := r.RegistIndicator(ind); err != nil {
panic(err) panic(err)
} }
} }

32
pkg/indicator/macd.go

@ -14,7 +14,7 @@ type Macd struct {
func (c *Macd) Meta() IndicatorMeta { func (c *Macd) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "macd", Name: "Macd",
Input: []types.InputArg{ Input: []types.InputArg{
{Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"}, {Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"},
{Name: "slow", 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 { func (c *Macd) CandlePeriods(ctx IIndicatorContext) int16 {
return max( return max(
ctx.Indicator("macd_dif", ctx.Input()).CandlePeriods(), ctx.Indicator("MacdDIF", ctx.Input()).CandlePeriods(),
ctx.Indicator("macd_dea", ctx.Input()).CandlePeriods(), ctx.Indicator("MacdDEA", ctx.Input()).CandlePeriods(),
) )
} }
func (c *Macd) Calculate(ctx IIndicatorContext) (vector float64) { func (c *Macd) Calculate(ctx IIndicatorContext) (vector float64) {
macd_dea := ctx.Indicator("macd_dea", ctx.Input()).Get(0) macd_dea := ctx.Indicator("MacdDEA", ctx.Input()).Get(0)
macd_dif := ctx.Indicator("macd_dif", ctx.Input()).Get(0) macd_dif := ctx.Indicator("MacdDIF", ctx.Input()).Get(0)
vector = (macd_dif - macd_dea) * 2 vector = (macd_dif - macd_dea) * 2
return return
} }
@ -43,7 +43,7 @@ type MacdDIF struct {
// indicator interface // indicator interface
func (c *MacdDIF) Meta() IndicatorMeta { func (c *MacdDIF) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "macd_dif", Name: "MacdDIF",
Input: []types.InputArg{ Input: []types.InputArg{
{Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"}, {Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"},
{Name: "slow", 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 { func (c *MacdDIF) CandlePeriods(ctx IIndicatorContext) int16 {
return max( return max(
ctx.Indicator("ema", ctx.Input().Int16("fast")).CandlePeriods(), ctx.Indicator("EMA", ctx.Input().Int16("fast")).CandlePeriods(),
ctx.Indicator("ema", ctx.Input().Int16("slow")).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 slow := ctx.Input().Int16("slow") // 26
// macd计算从第max(fast, slow)期开始稳定 // macd计算从第max(fast, slow)期开始稳定
fastEma := ctx.Indicator("ema", fast).Get(0) fastEma := ctx.Indicator("EMA", fast).Get(0)
slowEma := ctx.Indicator("ema", slow).Get(0) slowEma := ctx.Indicator("EMA", slow).Get(0)
macd := fastEma - slowEma macd := fastEma - slowEma
vector = macd vector = macd
return return
@ -77,7 +77,7 @@ type MacdDEA struct {
func (c *MacdDEA) Meta() IndicatorMeta { func (c *MacdDEA) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "macd_dea", Name: "MacdDEA",
Input: []types.InputArg{ Input: []types.InputArg{
{Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"}, {Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"},
{Name: "slow", 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 { 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) { func (c *MacdDEA) Calculate(ctx IIndicatorContext) (vector float64) {
singal := ctx.Input().Int16("singal") // 9 singal := ctx.Input().Int16("singal") // 9
deaPrev, ok := ctx.State().Get("vector", 1) deaPrev, ok := ctx.State().Get("_vector", 1)
if !ok { if !ok {
// 初始值前9期的 MACD_DIF SMA // 初始值前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() deaPrev = macdDifs.Avg()
} }
macd_dif := ctx.Indicator("macd_dif", ctx.Input()).Get(0) macd_dif := ctx.Indicator("MacdDIF", ctx.Input()).Get(0)
// 计算DEA // 计算DEA
beta := 2 / float64(singal+1) beta := 2 / float64(singal+1)
dea := beta*macd_dif + (1-beta)*deaPrev dea := beta*macd_dif + (1-beta)*deaPrev
ctx.State().Set("vector", dea) ctx.State().Set("_vector", dea)
vector = dea vector = dea
return return

6
pkg/indicator/obv.go

@ -13,7 +13,7 @@ type OBV struct {
func (c *OBV) Meta() IndicatorMeta { func (c *OBV) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "obv", Name: "OBV",
Input: []types.InputArg{}, // todo 无参指标tsdb存储 Input: []types.InputArg{}, // todo 无参指标tsdb存储
} }
} }
@ -23,7 +23,7 @@ func (c *OBV) CandlePeriods(ctx IIndicatorContext) int16 {
} }
func (c *OBV) Calculate(ctx IIndicatorContext) (vector float64) { func (c *OBV) Calculate(ctx IIndicatorContext) (vector float64) {
obvPrev, ok := ctx.State().Get("obv", 1) obvPrev, ok := ctx.State().Get("_vector", 1)
if !ok { if !ok {
obvPrev = 0 obvPrev = 0
} }
@ -36,6 +36,6 @@ func (c *OBV) Calculate(ctx IIndicatorContext) (vector float64) {
} else { } else {
vector = obvPrev vector = obvPrev
} }
ctx.State().Set("obv", vector) ctx.State().Set("_vector", vector)
return return
} }

2
pkg/indicator/rsi.go

@ -14,7 +14,7 @@ type RSI struct {
// indicator interface // indicator interface
func (c *RSI) Meta() IndicatorMeta { func (c *RSI) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "rsi", Name: "RSI",
Input: []types.InputArg{ Input: []types.InputArg{
{Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, {Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"},
}, },

8
pkg/indicator/sam.go

@ -2,8 +2,6 @@ package indicator
import ( import (
"sig-pub/pkg/types" "sig-pub/pkg/types"
"github.com/markcheno/go-talib"
) )
// RSI stateless indicator // RSI stateless indicator
@ -14,7 +12,7 @@ type SMA struct {
// indicator interface // indicator interface
func (c *SMA) Meta() IndicatorMeta { func (c *SMA) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "sma", Name: "SMA",
Input: []types.InputArg{ Input: []types.InputArg{
{Name: "window", Type: types.InputTypeUInt, Desc: "窗口大小"}, {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) { func (c *SMA) Calculate(ctx IIndicatorContext) (vector float64) {
window := ctx.Input().Int16("window") window := ctx.Input().Int16("window")
closeSeries := ctx.Series(0, window).Close() closeSeries := ctx.Series(0, window).Close()
sma := talib.Sma(closeSeries, int(window)) // sma := talib.Sma(closeSeries, int(window))
_ = sma[len(sma)-1] // _ = sma[len(sma)-1]
vector = closeSeries.Avg() vector = closeSeries.Avg()
return return
} }

72
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
}

6
pkg/indicator/wobv.go

@ -12,7 +12,7 @@ type WOBV struct {
func (c *WOBV) Meta() IndicatorMeta { func (c *WOBV) Meta() IndicatorMeta {
return IndicatorMeta{ return IndicatorMeta{
Name: "wobv", Name: "WOBV",
Input: []types.InputArg{}, // todo 无参指标tsdb存储 Input: []types.InputArg{}, // todo 无参指标tsdb存储
} }
} }
@ -22,7 +22,7 @@ func (c *WOBV) CandlePeriods(ctx IIndicatorContext) int16 {
} }
func (c *WOBV) Calculate(ctx IIndicatorContext) (vector float64) { func (c *WOBV) Calculate(ctx IIndicatorContext) (vector float64) {
wobvPrev, ok := ctx.State().Get("wobv", 1) wobvPrev, ok := ctx.State().Get("_vector", 1)
if !ok { if !ok {
wobvPrev = 0 wobvPrev = 0
} }
@ -30,7 +30,7 @@ func (c *WOBV) Calculate(ctx IIndicatorContext) (vector float64) {
k := ctx.Get(0) k := ctx.Get(0)
wf := (k.CloseF64() - k.OpenF64()) / (k.HighF64() - k.LowF64()) wf := (k.CloseF64() - k.OpenF64()) / (k.HighF64() - k.LowF64())
wobv := wobvPrev + wf*k.VolF64() wobv := wobvPrev + wf*k.VolF64()
ctx.State().Set("wobv", wobv) ctx.State().Set("_vector", wobv)
vector = wobv vector = wobv
return return

16
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 { func (s *GoldX) CandlePeriods(ctx ISingleSigStrategyContext) int16 {
return max( return max(
ctx.Indicator("macd", ctx.Input()).CandlePeriods(), ctx.Indicator("Macd", ctx.Input()).CandlePeriods(),
ctx.Indicator("macd_dif", ctx.Input()).CandlePeriods(), ctx.Indicator("MacdDIF", ctx.Input()).CandlePeriods(),
ctx.Indicator("macd_dea", ctx.Input()).CandlePeriods(), ctx.Indicator("MacdDEA", ctx.Input()).CandlePeriods(),
) )
} }
func (s *GoldX) Update(ctx ISingleSigStrategyContext) (side types.Side) { func (s *GoldX) Update(ctx ISingleSigStrategyContext) (side types.Side) {
macdHist := ctx.Indicator("macd", ctx.Input()).Get(0) // macd柱状图 macdHist := ctx.Indicator("Macd", ctx.Input()).Get(0) // macd柱状图
macdDea := ctx.Indicator("macd_dea", ctx.Input()).Series(0, 2) // macd_dea信号线 macdDea := ctx.Indicator("MacdDEA", ctx.Input()).Series(0, 2) // macd_dea信号线
macdDif := ctx.Indicator("macd_dif", ctx.Input()).Series(0, 2) // macd_dif线 macdDif := ctx.Indicator("MacdDIF", ctx.Input()).Series(0, 2) // macd_dif线
// todo 包装方法 crossover/crossunder // todo 包装方法 crossover/crossunder
// 1.MACD DIF线接近或上穿零轴(表示整体多头市场) // 1.MACD DIF线接近或上穿零轴(表示整体多头市场)
crossover := macdDif[0] > macdDea[0] && macdDif[1] < macdDea[1] // 上穿 crossover := macdDif[0] > macdDea[0] && macdDif[1] < macdDea[1] // 上穿
crossunder := 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 { if crossover {
_ = macdHist
// 2.附加确认条件: 柱状图从负值转为正值 // 2.附加确认条件: 柱状图从负值转为正值
if macdHist > 0 { if macdHist > 0 {
// todo 3.成交量放大(结合 OBV 等指标验证资金流入)。 // todo 3.成交量放大(结合 OBV 等指标验证资金流入)。

0
pkg/strategy/super_trend.go → pkg/strategy/super_trend_bos_waves.go

50
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
}
Loading…
Cancel
Save