indicator/tool.go
2024-06-25 23:17:36 +08:00

228 lines
4.5 KiB
Go

package indicator
import (
"encoding/json"
"fmt"
"reflect"
"strings"
)
type NewCommonIndicatorFunc func(params ...int) (CommonIndicator, error)
var (
ExtraIndicators = map[string]NewCommonIndicatorFunc{}
)
// CommonIndicator
type CommonIndicator interface {
Indicator
Indicator() map[string]float64
}
func RegisterIndicator(name string, fn NewCommonIndicatorFunc) {
ExtraIndicators[name] = fn
}
type JsonIndicator struct {
CommonIndicator
}
func NewJsonIndicator(m CommonIndicator) *JsonIndicator {
return &JsonIndicator{CommonIndicator: m}
}
func (j *JsonIndicator) MarshalJSON() (buf []byte, err error) {
ret := j.Indicator()
buf, err = json.Marshal(ret)
return
}
func NewCommonIndicator(name string, params ...int) (ind CommonIndicator, err error) {
name = strings.ToUpper(name)
nLen := len(params)
if nLen == 0 {
err = fmt.Errorf("%s params can't be empty", name)
return
}
switch name {
case "EMA":
if nLen >= 2 {
maGroup := NewMAGroup(NewEMA(params[0]), NewEMA(params[1]))
ind = NewMixed(nil, maGroup)
} else {
ema := NewEMA(params[0])
ind = NewMixed(ema, nil)
}
case "MACD":
if nLen < 3 {
err = fmt.Errorf("%s params not enough", name)
} else {
macd := NewMACD(params[0], params[1], params[2])
ind = NewMixed(macd, macd)
}
case "SMAMACD":
if nLen < 3 {
err = fmt.Errorf("%s params not enough", name)
} else {
macd := NewMACDWithSMA(params[0], params[1], params[2])
ind = NewMixed(macd, macd)
}
case "SMA":
if nLen >= 2 {
maGroup := NewMAGroup(NewSMA(params[0]), NewSMA(params[1]))
ind = NewMixed(nil, maGroup)
} else {
sma := NewSMA(params[0])
ind = NewMixed(sma, nil)
}
case "SMMA":
if nLen >= 2 {
maGroup := NewMAGroup(NewSMMA(params[0]), NewSMMA(params[1]))
ind = NewMixed(nil, maGroup)
} else {
smma := NewSMMA(params[0])
ind = NewMixed(smma, nil)
}
case "STOCHRSI":
if nLen < 4 {
err = fmt.Errorf("%s params not enough", name)
} else {
stochRSI := NewStochRSI(params[0], params[1], params[2], params[3])
ind = NewMixed(stochRSI, stochRSI)
}
case "RSI":
if nLen >= 2 {
maGroup := NewMAGroup(NewRSI(params[0]), NewRSI(params[1]))
ind = NewMixed(nil, maGroup)
} else {
rsi := NewRSI(params[0])
ind = NewMixed(rsi, nil)
}
case "BOLL":
if nLen >= 2 {
boll := NewBoll(params[0], params[1])
ind = boll
} else {
err = fmt.Errorf("%s params not enough", name)
}
default:
fn, ok := ExtraIndicators[name]
if !ok {
err = fmt.Errorf("%s indicator not support", name)
} else {
ind, err = fn(params...)
}
}
if err == nil {
ind = NewJsonIndicator(ind)
}
return
}
type Mixed struct {
indicator Indicator
crossIndicator Crosser
isSameOne bool
crossTool *CrossTool
}
func NewMixed(indicator Indicator, crossIndicator Crosser) *Mixed {
m := new(Mixed)
m.indicator = indicator
m.crossIndicator = crossIndicator
if m.crossIndicator != nil {
m.crossTool = NewCrossTool(m.crossIndicator)
}
m.checkSameOne()
return m
}
func (m *Mixed) checkSameOne() {
if reflect.ValueOf(m.indicator) == reflect.ValueOf(m.crossIndicator) {
m.isSameOne = true
} else {
m.isSameOne = false
}
}
func (m *Mixed) Update(price float64) {
if m.crossTool != nil {
m.crossTool.Update(price)
}
if !m.isSameOne && m.indicator != nil {
m.indicator.Update(price)
}
}
func (m *Mixed) FastResult() float64 {
if m.crossIndicator != nil {
return m.crossIndicator.FastResult()
}
return 0
}
func (m *Mixed) SlowResult() float64 {
if m.crossIndicator != nil {
return m.crossIndicator.SlowResult()
}
return 0
}
func (m *Mixed) IsCrossUp() bool {
if m.crossTool == nil {
fmt.Println("cross tool is nil")
return false
}
return m.crossTool.IsCrossUp()
}
func (m *Mixed) IsCrossDown() bool {
if m.crossTool == nil {
return false
}
return m.crossTool.IsCrossDown()
}
func (m *Mixed) Result() float64 {
if m.indicator != nil {
return m.indicator.Result()
}
return 0
}
func (m *Mixed) SupportResult() bool {
if m.indicator != nil {
return true
}
return false
}
func (m *Mixed) SupportSlowFast() bool {
if m.crossIndicator != nil {
return true
}
return false
}
func (m *Mixed) Indicator() map[string]float64 {
ret := make(map[string]float64)
if m.SupportResult() {
ret["result"] = m.Result()
}
if m.SupportSlowFast() {
ret["fast"] = m.FastResult()
ret["slow"] = m.SlowResult()
if m.IsCrossDown() {
ret["crossDown"] = 1
} else {
ret["crossDown"] = 0
}
if m.IsCrossUp() {
ret["crossUp"] = 1
} else {
ret["crossUp"] = 0
}
}
return ret
}