Browse Source

indicator plot

main
strange 9 months ago
parent
commit
a852658b12
  1. 4
      api/pub.proto
  2. 2
      api/trading.proto
  3. 49
      internal/trading/trading_grpc_server.go
  4. 2
      internal/trading/trading_service.go
  5. 12
      pkg/indicator/indicator_plot.go
  6. 1
      pkg/indicator/indicator_registry.go
  7. 124
      pkg/indicator/macd.go
  8. 110
      pkg/indicator/macd0.go
  9. 12
      pkg/strategy/gold_x.go
  10. 9
      pkg/strategy/super_trend2_macd.go

4
api/pub.proto

@ -168,9 +168,9 @@ message IndicatorPlotSeries {
string state = 1; string state = 1;
int32 type = 2; int32 type = 2;
google.protobuf.Struct props = 3; google.protobuf.Struct props = 3;
repeated IndicatorStateToPlotProps state2Props = 4; repeated IndicatorStateEnumProps stateEnumProps = 4;
} }
message IndicatorStateToPlotProps { message IndicatorStateEnumProps {
string state = 1; string state = 1;
map<int32, google.protobuf.Struct> enumProps = 2; map<int32, google.protobuf.Struct> enumProps = 2;
} }

2
api/trading.proto

@ -33,7 +33,7 @@ message RspIndicatorSeries {
} }
message IndicatorState { message IndicatorState {
string state = 1; string state = 1;
repeated double value = 2; repeated double matrix = 2;
} }
message ReqStrategySeries { message ReqStrategySeries {

49
internal/trading/trading_grpc_server.go

@ -3,8 +3,11 @@ package trading
import ( import (
"context" "context"
"sig-pub/api/pb" "sig-pub/api/pb"
"sig-pub/pkg/indicator"
"sig-pub/pkg/types" "sig-pub/pkg/types"
"sig-pub/pkg/utils/times" "sig-pub/pkg/utils/times"
"google.golang.org/protobuf/types/known/structpb"
) )
type TradingGrpcServer struct { type TradingGrpcServer struct {
@ -27,8 +30,48 @@ func (svr *TradingGrpcServer) IndicatorPlots(ctx context.Context, req *pb.ReqInd
if err != nil { if err != nil {
return return
} }
for _, plot := range plots { rsp = new(pb.RspIndicatorPlots)
_ = plot for name, plot := range plots {
p := &pb.IndicatorPlot{Indicator: name}
p.Series, err = mappingIndicatorPlotSeries(plot.Series)
if err != nil {
return nil, err
}
for _, series := range plot.StateSeries {
ps, err := mappingIndicatorPlotSeries(series)
if err != nil {
return rsp, err
}
p.StateSeries = append(p.StateSeries, ps)
}
rsp.Plots = append(rsp.Plots, p)
}
return
}
func mappingIndicatorPlotSeries(ps indicator.PlotSeries) (splot *pb.IndicatorPlotSeries, err error) {
seriesProps, err := structpb.NewStruct(ps.Props)
if err != nil {
return
}
splot = &pb.IndicatorPlotSeries{
State: ps.State,
Type: int32(ps.Type),
Props: seriesProps,
StateEnumProps: nil,
}
for state, valueProps := range ps.State2Props {
s2p := &pb.IndicatorStateEnumProps{
State: state,
EnumProps: make(map[int32]*structpb.Struct),
}
for v, props := range valueProps {
s2p.EnumProps[int32(v)], err = structpb.NewStruct(props)
if err != nil {
return
}
}
splot.StateEnumProps = append(splot.StateEnumProps, s2p)
} }
return return
} }
@ -46,7 +89,7 @@ func (svr *TradingGrpcServer) IndicatorSeries(ctx context.Context, req *pb.ReqIn
for state, value := range states { for state, value := range states {
rsp.States = append(rsp.States, &pb.IndicatorState{ rsp.States = append(rsp.States, &pb.IndicatorState{
State: state, State: state,
Value: value, Matrix: value,
}) })
} }
return return

2
internal/trading/trading_service.go

@ -265,7 +265,7 @@ func (svc *TradingService) IndicatorSeries(ctx context.Context, indicatorName st
// 状态填充 // 状态填充
for _, state := range indicatorStates { for _, state := range indicatorStates {
sv, _ := indicatorContext.State().Get(state, 0) sv, _ := indicatorContext.State().Get(state, 0)
states[state] = append(states[state], sv) states[state] = append(states[state], math.Round(sv*pow)/pow)
} }
return return
}) })

12
pkg/indicator/indicator_plot.go

@ -29,10 +29,14 @@ const (
) )
// Series 绘图颜色 // Series 绘图颜色
type Color string const (
ColorRed string = "red"
ColorGreen string = "green"
ColorYellow string = "yellow"
ColorBlue string = "blue"
)
const ( const (
ColorRed Color = "red" // calc tokens: > >= == < <= + - * / %
ColorGreen Color = "green" // 大于等于小于 In, NotIn ...
ColorYellow Color = "yellow"
) )

1
pkg/indicator/indicator_registry.go

@ -22,6 +22,7 @@ func (r *IndicatorRegistry) Init() (err error) {
r.MustRegistIndicator(&SMA{}) r.MustRegistIndicator(&SMA{})
r.MustRegistIndicator(&ATR{}) r.MustRegistIndicator(&ATR{})
r.MustRegistIndicator(&EMA{}) r.MustRegistIndicator(&EMA{})
r.MustRegistIndicator(&MACD{})
r.MustRegistIndicator(&MacdDIF{}) r.MustRegistIndicator(&MacdDIF{})
r.MustRegistIndicator(&MacdDEA{}) r.MustRegistIndicator(&MacdDEA{})
r.MustRegistIndicator(&Macd{}) r.MustRegistIndicator(&Macd{})

124
pkg/indicator/macd.go

@ -1,110 +1,68 @@
package indicator package indicator
import ( import "sig-pub/pkg/types"
"sig-pub/pkg/types"
)
// Macd macd柱状图计算 type MACD struct {
// Macd 拆分成: Macd(柱状图), MacdDIF线, MacdDEA(信号线)
// 计算 MacdDIF 线 (DIF): 反映短期趋势与长期趋势的“收敛/散度”
// Macd: https://www.investopedia.com/terms/m/macd.asp
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: "快线周期"}, // 12
{Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"}, {Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"}, // 26
{Name: "singal", Type: types.InputTypeUInt, Desc: "信号线周期"}, {Name: "singal", Type: types.InputTypeUInt, Desc: "信号线周期"}, // 9
},
State: []string{"dif", "dea"},
Plot: Plot{
Series: PlotSeries{Type: PlotSeriesHistogram, Props: PlotProps{"color": ColorGreen}, State2Props: map[string]map[float64]PlotProps{
"vector": {
-1: {"vector >= 0": 1, "color": ColorRed},
1: {"vector < 0": 1, "color": ColorGreen},
},
}},
StateSeries: []PlotSeries{
{State: "dif", Type: PlotSeriesLine, Props: PlotProps{"color": ColorYellow}},
{State: "dea", Type: PlotSeriesLine, Props: PlotProps{"color": ColorBlue}},
}, },
}
}
func (c *Macd) CandlePeriods(ctx IIndicatorContext) int16 {
return max(
ctx.Indicator("MacdDIF", ctx.Input()).CandlePeriods(),
ctx.Indicator("MacdDEA", ctx.Input()).CandlePeriods(),
)
}
func (c *Macd) Calculate(ctx IIndicatorContext) (vector float64) {
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
}
type MacdDIF struct {
}
// indicator interface
func (c *MacdDIF) Meta() IndicatorMeta {
return IndicatorMeta{
Name: "MacdDIF",
Input: []types.InputArg{
{Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"},
{Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"},
}, },
} }
} }
func (c *MacdDIF) CandlePeriods(ctx IIndicatorContext) int16 { func (c *MACD) 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(),
) ) + ctx.Input().Int16("singal") + 1
} }
// Calculate 计算单根k线sma指标 // Calculate macd计算从第max(fast, slow)期开始稳定
func (c *MacdDIF) Calculate(ctx IIndicatorContext) (vector float64) { func (c *MACD) Calculate(ctx IIndicatorContext) (vector float64) {
fast := ctx.Input().Int16("fast") // 12 fast := ctx.Input().Int16("fast")
slow := ctx.Input().Int16("slow") // 26 slow := ctx.Input().Int16("slow")
singal := ctx.Input().Int16("singal")
// macd计算从第max(fast, slow)期开始稳定 // macd dif
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_dif := fastEma - slowEma
vector = macd ctx.State().Set("dif", macd_dif)
return
}
// MacdDEA macd信号线计算
type MacdDEA struct {
}
func (c *MacdDEA) Meta() IndicatorMeta {
return IndicatorMeta{
Name: "MacdDEA",
Input: []types.InputArg{
{Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"},
{Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"},
{Name: "singal", Type: types.InputTypeUInt, Desc: "信号线周期"},
},
}
}
func (c *MacdDEA) CandlePeriods(ctx IIndicatorContext) int16 { // macd dea
return ctx.Indicator("MacdDIF", ctx.Input()).CandlePeriods() + ctx.Input().Int16("singal") + 1 deaPrev, ok := ctx.State().Get("dea", 1)
}
func (c *MacdDEA) Calculate(ctx IIndicatorContext) (vector float64) {
singal := ctx.Input().Int16("singal") // 9
deaPrev, ok := ctx.State().Get("_vector", 1)
if !ok { if !ok {
// 初始值前9期的 MACD_DIF SMA // 初始值前9期的 MACD_DIF SMA
macdDifs := ctx.Indicator("MacdDIF", ctx.Input()).Series(1, singal) difs, ok := ctx.State().Series("dif", 1, singal)
deaPrev = macdDifs.Avg() if !ok {
return
}
deaPrev = difs.Avg()
} }
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)
vector = dea // macd hist
beta := 2 / float64(singal+1)
macd_dea := beta*macd_dif + (1-beta)*deaPrev
ctx.State().Set("dea", macd_dea)
vector = (macd_dif - macd_dea) * 2
return return
} }

110
pkg/indicator/macd0.go

@ -0,0 +1,110 @@
package indicator
import (
"sig-pub/pkg/types"
)
// Macd macd柱状图计算
// Macd 拆分成: Macd(柱状图), MacdDIF线, MacdDEA(信号线)
// 计算 MacdDIF 线 (DIF): 反映短期趋势与长期趋势的“收敛/散度”
// Macd: https://www.investopedia.com/terms/m/macd.asp
type Macd struct {
}
func (c *Macd) Meta() IndicatorMeta {
return IndicatorMeta{
Name: "Macd",
Input: []types.InputArg{
{Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"},
{Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"},
{Name: "singal", Type: types.InputTypeUInt, Desc: "信号线周期"},
},
}
}
func (c *Macd) CandlePeriods(ctx IIndicatorContext) int16 {
return max(
ctx.Indicator("MacdDIF", ctx.Input()).CandlePeriods(),
ctx.Indicator("MacdDEA", ctx.Input()).CandlePeriods(),
)
}
func (c *Macd) Calculate(ctx IIndicatorContext) (vector float64) {
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
}
type MacdDIF struct {
}
// indicator interface
func (c *MacdDIF) Meta() IndicatorMeta {
return IndicatorMeta{
Name: "MacdDIF",
Input: []types.InputArg{
{Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"},
{Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"},
},
}
}
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(),
)
}
// Calculate 计算单根k线sma指标
func (c *MacdDIF) Calculate(ctx IIndicatorContext) (vector float64) {
fast := ctx.Input().Int16("fast") // 12
slow := ctx.Input().Int16("slow") // 26
// macd计算从第max(fast, slow)期开始稳定
fastEma := ctx.Indicator("EMA", fast).Get(0)
slowEma := ctx.Indicator("EMA", slow).Get(0)
macd := fastEma - slowEma
vector = macd
return
}
// MacdDEA macd信号线计算
type MacdDEA struct {
}
func (c *MacdDEA) Meta() IndicatorMeta {
return IndicatorMeta{
Name: "MacdDEA",
Input: []types.InputArg{
{Name: "fast", Type: types.InputTypeUInt, Desc: "快线周期"},
{Name: "slow", Type: types.InputTypeUInt, Desc: "慢线周期"},
{Name: "singal", Type: types.InputTypeUInt, Desc: "信号线周期"},
},
}
}
func (c *MacdDEA) CandlePeriods(ctx IIndicatorContext) int16 {
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)
if !ok {
// 初始值前9期的 MACD_DIF SMA
macdDifs := ctx.Indicator("MacdDIF", ctx.Input()).Series(1, singal)
deaPrev = macdDifs.Avg()
}
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)
vector = dea
return
}

12
pkg/strategy/gold_x.go

@ -32,16 +32,16 @@ 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("MacdDIF", 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柱状图 macd := ctx.Indicator("MACD", ctx.Input())
macdDea := ctx.Indicator("MacdDEA", ctx.Input()).Series(0, 2) // macd_dea信号线
macdDif := ctx.Indicator("MacdDIF", ctx.Input()).Series(0, 2) // macd_dif线 macdHist := macd.Get(0)
macdDea := macd.StateSeries("dea", 0, 2)
macdDif := macd.StateSeries("dif", 0, 2)
// todo 包装方法 crossover/crossunder // todo 包装方法 crossover/crossunder
// 1.MACD DIF线接近或上穿零轴(表示整体多头市场) // 1.MACD DIF线接近或上穿零轴(表示整体多头市场)

9
pkg/strategy/super_trend2_macd.go

@ -35,9 +35,7 @@ func (s *SuperTrend2Macd) CandlePeriods(ctx ISingleSigStrategyContext) int16 {
return max( return max(
ctx.Indicator("SuperTrend", types.Input{"window": 10, "mul": 3}).CandlePeriods(), ctx.Indicator("SuperTrend", types.Input{"window": 10, "mul": 3}).CandlePeriods(),
ctx.Indicator("SuperTrend", types.Input{"window": 14, "mul": 2}).CandlePeriods(), ctx.Indicator("SuperTrend", types.Input{"window": 14, "mul": 2}).CandlePeriods(),
ctx.Indicator("MacdDEA", types.Input{"fast": 12, "slow": 26, "singal": 9}).CandlePeriods(), ctx.Indicator("MACD", types.Input{"fast": 12, "slow": 26, "singal": 9}).CandlePeriods(),
ctx.Indicator("MacdDIF", types.Input{"fast": 12, "slow": 26, "singal": 9}).CandlePeriods(),
21,
) )
} }
@ -51,8 +49,9 @@ func (s *SuperTrend2Macd) Update(ctx ISingleSigStrategyContext) (side types.Side
trend1Directions := superTrend1.StateSeries("direction", 0, 2) trend1Directions := superTrend1.StateSeries("direction", 0, 2)
trend2Directions := superTrend2.StateSeries("direction", 0, 2) trend2Directions := superTrend2.StateSeries("direction", 0, 2)
macdDea := ctx.Indicator("MacdDEA", types.Input{"fast": 12, "slow": 26, "singal": 9}).Series(0, 2) // macd_dea信号线 macd := ctx.Indicator("MACD", types.Input{"fast": 12, "slow": 26, "singal": 9})
macdDif := ctx.Indicator("MacdDIF", types.Input{"fast": 12, "slow": 26, "singal": 9}).Series(0, 2) // macd_dif线 macdDea := macd.StateSeries("dea", 0, 2)
macdDif := macd.StateSeries("dif", 0, 2)
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] // 死叉

Loading…
Cancel
Save