first commit
This commit is contained in:
commit
c23020eee5
17
README.md
Normal file
17
README.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# indicator
|
||||
The trade indicator.
|
||||
|
||||
# Indicator Support
|
||||
| indicator | support
|
||||
|----------|------|
|
||||
| EMA | Yes |
|
||||
| SMA | Yes |
|
||||
| SMMA | Yes |
|
||||
| Stoch | No Test|
|
||||
| StochRSI| Yes|
|
||||
|
||||
|
||||
# Cheers to
|
||||
Some indicator refer to [Gekko](https://github.com/thrasher-/gocryptotrader)
|
||||
|
||||
Some indicator refer to tradingview wiki [StochRSI](https://www.tradingview.com/wiki/Stochastic_RSI_(STOCH_RSI))
|
52
boll.go
Normal file
52
boll.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package indicator
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
type Boll struct {
|
||||
*SMA
|
||||
k int
|
||||
mid float64
|
||||
top float64
|
||||
bottom float64
|
||||
}
|
||||
|
||||
func NewBoll(winLen, k int) *Boll {
|
||||
b := new(Boll)
|
||||
b.SMA = NewSMA(winLen)
|
||||
b.k = k
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Boll) Result() float64 {
|
||||
return b.mid
|
||||
}
|
||||
|
||||
func (b *Boll) Update(price float64) {
|
||||
b.SMA.Update(price)
|
||||
b.Cal()
|
||||
}
|
||||
|
||||
func (b *Boll) Cal() {
|
||||
b.mid = b.SMA.result
|
||||
var sd float64
|
||||
for j := 0; j < b.winLen; j++ {
|
||||
sd += math.Pow(b.prices[j]-b.mid, 2)
|
||||
}
|
||||
sd = math.Sqrt(sd/float64(b.winLen)) * float64(b.k)
|
||||
b.top = b.mid + sd
|
||||
b.bottom = b.mid - sd
|
||||
}
|
||||
|
||||
func (b *Boll) Top() float64 {
|
||||
return b.top
|
||||
}
|
||||
|
||||
func (b *Boll) Bottom() float64 {
|
||||
return b.bottom
|
||||
}
|
||||
|
||||
func (b *Boll) Indicator() map[string]float64 {
|
||||
return map[string]float64{"result": b.Result(), "top": b.Top(), "bottom": b.Bottom()}
|
||||
}
|
17
common.go
Normal file
17
common.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package indicator
|
||||
|
||||
type Updater interface {
|
||||
Update(price float64)
|
||||
}
|
||||
|
||||
type Indicator interface {
|
||||
Updater
|
||||
Result() float64
|
||||
}
|
||||
|
||||
type Crosser interface {
|
||||
Updater
|
||||
SlowResult() float64
|
||||
FastResult() float64
|
||||
}
|
||||
|
60
cross_tool.go
Normal file
60
cross_tool.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package indicator
|
||||
|
||||
type CrossTool struct {
|
||||
crosser Crosser
|
||||
fasts [3]float64 // prev fasts
|
||||
slows [3]float64 // prev slows
|
||||
}
|
||||
|
||||
func NewCrossTool(crosser Crosser) *CrossTool {
|
||||
ct := new(CrossTool)
|
||||
ct.crosser = crosser
|
||||
return ct
|
||||
}
|
||||
|
||||
func (ct *CrossTool) Update(price float64) {
|
||||
ct.fasts[2] = ct.fasts[1]
|
||||
ct.fasts[1] = ct.fasts[0]
|
||||
ct.slows[2] = ct.slows[1]
|
||||
ct.slows[1] = ct.slows[0]
|
||||
|
||||
ct.crosser.Update(price)
|
||||
|
||||
ct.fasts[0] = ct.crosser.FastResult()
|
||||
ct.slows[0] = ct.crosser.SlowResult()
|
||||
}
|
||||
|
||||
func (ct *CrossTool) IsCrossUp() bool {
|
||||
prevFast, prevSlow := ct.getPrev()
|
||||
fast, slow := ct.getCurrent()
|
||||
if prevFast < prevSlow && fast > slow {
|
||||
// fmt.Println("up:", ct.fasts, ct.slows)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (ct *CrossTool) IsCrossDown() bool {
|
||||
prevFast, prevSlow := ct.getPrev()
|
||||
fast, slow := ct.getCurrent()
|
||||
if prevFast > prevSlow && fast < slow {
|
||||
// fmt.Println("down:", ct.fasts, ct.slows)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (ct *CrossTool) getCurrent() (fast, slow float64) {
|
||||
fast, slow = ct.fasts[0], ct.slows[0]
|
||||
return
|
||||
}
|
||||
func (ct *CrossTool) getPrev() (prevFast, prevSlow float64) {
|
||||
prevFast = ct.fasts[1]
|
||||
prevSlow = ct.slows[1]
|
||||
// if prev fast is same of prev slow,see prev one
|
||||
if prevFast == prevSlow {
|
||||
prevFast = ct.fasts[2]
|
||||
prevSlow = ct.slows[2]
|
||||
}
|
||||
return
|
||||
}
|
31
ema.go
Normal file
31
ema.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package indicator
|
||||
|
||||
type EMA struct {
|
||||
MABase
|
||||
alpha float64
|
||||
bFirst bool
|
||||
}
|
||||
|
||||
func NewEMA(winLen int) *EMA {
|
||||
e := new(EMA)
|
||||
e.winLen = winLen
|
||||
e.alpha = 2 / float64((e.winLen + 1))
|
||||
e.bFirst = true
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *EMA) Update(price float64) {
|
||||
if e.bFirst {
|
||||
e.result = price
|
||||
e.bFirst = false
|
||||
}
|
||||
e.cal(price)
|
||||
}
|
||||
|
||||
// cal
|
||||
// EMA = alpha * x + (1 - alpha) * EMA[1]
|
||||
// alpha = 2 / (y + 1)
|
||||
func (e *EMA) cal(price float64) {
|
||||
oldResult := e.result
|
||||
e.result = e.alpha*price + (1-e.alpha)*oldResult
|
||||
}
|
26
ma_group.go
Normal file
26
ma_group.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package indicator
|
||||
|
||||
type MAGroup struct {
|
||||
fast Indicator
|
||||
slow Indicator
|
||||
}
|
||||
|
||||
func NewMAGroup(fast, slow Indicator) *MAGroup {
|
||||
mg := new(MAGroup)
|
||||
mg.fast = fast
|
||||
mg.slow = slow
|
||||
return mg
|
||||
}
|
||||
|
||||
func (mg *MAGroup) Update(price float64) {
|
||||
mg.fast.Update(price)
|
||||
mg.slow.Update(price)
|
||||
}
|
||||
|
||||
func (mg *MAGroup) FastResult() float64 {
|
||||
return mg.fast.Result()
|
||||
}
|
||||
|
||||
func (mg *MAGroup) SlowResult() float64 {
|
||||
return mg.slow.Result()
|
||||
}
|
10
mabase.go
Normal file
10
mabase.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package indicator
|
||||
|
||||
type MABase struct {
|
||||
winLen int //window length
|
||||
result float64
|
||||
}
|
||||
|
||||
func (m *MABase) Result() float64 {
|
||||
return m.result
|
||||
}
|
57
macd.go
Normal file
57
macd.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package indicator
|
||||
|
||||
type MACD struct {
|
||||
long Indicator
|
||||
short Indicator
|
||||
signal Indicator
|
||||
dif float64
|
||||
dea float64
|
||||
result float64
|
||||
}
|
||||
|
||||
// NewMACDWithSMA macd signal line with simple ma
|
||||
func NewMACDWithSMA(short, long, signal int) *MACD {
|
||||
ma := new(MACD)
|
||||
ma.short = NewEMA(short)
|
||||
ma.long = NewEMA(long)
|
||||
ma.signal = NewSMA(signal)
|
||||
return ma
|
||||
}
|
||||
|
||||
func NewMACD(short, long, signal int) *MACD {
|
||||
ma := new(MACD)
|
||||
ma.short = NewEMA(short)
|
||||
ma.long = NewEMA(long)
|
||||
ma.signal = NewEMA(signal)
|
||||
return ma
|
||||
}
|
||||
|
||||
func (ma *MACD) Update(price float64) {
|
||||
ma.long.Update(price)
|
||||
ma.short.Update(price)
|
||||
|
||||
ma.dif = ma.short.Result() - ma.long.Result()
|
||||
ma.signal.Update(ma.dif)
|
||||
ma.dea = ma.signal.Result()
|
||||
ma.result = ma.dif - ma.dea
|
||||
}
|
||||
|
||||
func (ma *MACD) Result() float64 {
|
||||
return ma.result
|
||||
}
|
||||
|
||||
func (ma *MACD) DIF() float64 {
|
||||
return ma.dif
|
||||
}
|
||||
|
||||
func (ma *MACD) DEA() float64 {
|
||||
return ma.dea
|
||||
}
|
||||
|
||||
func (ma *MACD) FastResult() float64 {
|
||||
return ma.dif
|
||||
}
|
||||
|
||||
func (ma *MACD) SlowResult() float64 {
|
||||
return ma.dea
|
||||
}
|
52
rsi.go
Normal file
52
rsi.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package indicator
|
||||
|
||||
type RSI struct {
|
||||
winLen int
|
||||
avgU *SMMA
|
||||
avgD *SMMA
|
||||
u float64
|
||||
d float64
|
||||
lastClose *float64
|
||||
rs float64
|
||||
result float64
|
||||
}
|
||||
|
||||
func NewRSI(winLen int) *RSI {
|
||||
r := new(RSI)
|
||||
r.winLen = winLen
|
||||
r.avgU = NewSMMA(r.winLen)
|
||||
r.avgD = NewSMMA(r.winLen)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *RSI) Update(price float64) {
|
||||
if r.lastClose == nil {
|
||||
r.lastClose = &price
|
||||
return
|
||||
}
|
||||
if price > *r.lastClose {
|
||||
r.u = price - *r.lastClose
|
||||
r.d = 0
|
||||
} else {
|
||||
r.u = 0
|
||||
r.d = *r.lastClose - price
|
||||
}
|
||||
r.avgU.Update(r.u)
|
||||
r.avgD.Update(r.d)
|
||||
uResult := r.avgU.Result()
|
||||
dResult := r.avgD.Result()
|
||||
r.rs = uResult / dResult
|
||||
r.result = 100 - (100 / (1 + r.rs))
|
||||
if dResult == 0 {
|
||||
if uResult != 0 {
|
||||
r.result = 100
|
||||
} else {
|
||||
r.result = 0
|
||||
}
|
||||
}
|
||||
r.lastClose = &price
|
||||
}
|
||||
|
||||
func (r *RSI) Result() float64 {
|
||||
return r.result
|
||||
}
|
25
sma.go
Normal file
25
sma.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package indicator
|
||||
|
||||
type SMA struct {
|
||||
MABase
|
||||
prices []float64
|
||||
sum float64
|
||||
age int
|
||||
}
|
||||
|
||||
func NewSMA(winLen int) *SMA {
|
||||
s := new(SMA)
|
||||
s.winLen = winLen
|
||||
s.prices = make([]float64, s.winLen)
|
||||
s.age = 0
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *SMA) Update(price float64) {
|
||||
s.result = price
|
||||
tail := s.prices[s.age]
|
||||
s.prices[s.age] = price
|
||||
s.sum += price - tail
|
||||
s.result = s.sum / float64(s.winLen)
|
||||
s.age = (s.age + 1) % s.winLen
|
||||
}
|
33
smma.go
Normal file
33
smma.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package indicator
|
||||
|
||||
// SMMA Smoothed Moving Average (SMMA)
|
||||
type SMMA struct {
|
||||
MABase
|
||||
sma *SMA
|
||||
age int
|
||||
bFirst bool
|
||||
}
|
||||
|
||||
func NewSMMA(winLen int) *SMMA {
|
||||
sm := new(SMMA)
|
||||
sm.winLen = winLen
|
||||
sm.sma = NewSMA(sm.winLen)
|
||||
sm.bFirst = true
|
||||
return sm
|
||||
}
|
||||
|
||||
func (sm *SMMA) Update(price float64) {
|
||||
if sm.bFirst {
|
||||
nLen := sm.age + 1
|
||||
if nLen < sm.winLen {
|
||||
sm.sma.Update(price)
|
||||
} else if nLen == sm.winLen {
|
||||
sm.sma.Update(price)
|
||||
sm.result = sm.sma.Result()
|
||||
sm.bFirst = false
|
||||
}
|
||||
sm.age++
|
||||
} else {
|
||||
sm.result = (sm.result*float64(sm.winLen-1) + price) / float64(sm.winLen)
|
||||
}
|
||||
}
|
74
stoch.go
Normal file
74
stoch.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
package indicator
|
||||
|
||||
// Stoch just test with StochRSI
|
||||
type Stoch struct {
|
||||
winLen int
|
||||
prices []float64
|
||||
lowest float64
|
||||
highest float64
|
||||
age int
|
||||
bFirst bool
|
||||
result float64
|
||||
kSMA *SMA
|
||||
dSMA *SMA
|
||||
}
|
||||
|
||||
func NewStoch(winLen, periodK, periodD int) *Stoch {
|
||||
s := new(Stoch)
|
||||
s.winLen = winLen
|
||||
s.prices = make([]float64, s.winLen)
|
||||
s.bFirst = true
|
||||
s.kSMA = NewSMA(periodK)
|
||||
s.dSMA = NewSMA(periodD)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Stoch) Update(price float64) {
|
||||
if s.bFirst {
|
||||
s.lowest = price
|
||||
s.highest = price
|
||||
s.bFirst = false
|
||||
return
|
||||
}
|
||||
s.prices[s.age] = price
|
||||
s.age = (s.age + 1) % s.winLen
|
||||
s.highest = highest(s.prices)
|
||||
s.lowest = lowest(s.prices)
|
||||
if s.highest == s.lowest {
|
||||
return
|
||||
}
|
||||
s.result = (100 * (price - s.lowest)) / (s.highest - s.lowest)
|
||||
s.kSMA.Update(s.result)
|
||||
s.dSMA.Update(s.kSMA.Result())
|
||||
}
|
||||
|
||||
func (s *Stoch) Result() float64 {
|
||||
return s.result
|
||||
}
|
||||
|
||||
func (s *Stoch) KResult() float64 {
|
||||
return s.kSMA.Result()
|
||||
}
|
||||
|
||||
func (s *Stoch) DResult() float64 {
|
||||
return s.dSMA.Result()
|
||||
}
|
||||
func lowest(prices []float64) (ret float64) {
|
||||
ret = prices[0]
|
||||
for _, v := range prices {
|
||||
if v < ret {
|
||||
ret = v
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func highest(prices []float64) (ret float64) {
|
||||
ret = prices[0]
|
||||
for _, v := range prices {
|
||||
if v > ret {
|
||||
ret = v
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
43
stochrsi.go
Normal file
43
stochrsi.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package indicator
|
||||
|
||||
// StochRSI
|
||||
// result test with aicoin's bitmex data
|
||||
// maybe it's difference with different website
|
||||
type StochRSI struct {
|
||||
winLen int
|
||||
r *RSI
|
||||
st *Stoch
|
||||
}
|
||||
|
||||
func NewStochRSI(winLen, rsiWinLen, k, d int) *StochRSI {
|
||||
sr := new(StochRSI)
|
||||
sr.winLen = winLen
|
||||
sr.r = NewRSI(winLen)
|
||||
sr.st = NewStoch(rsiWinLen, k, d)
|
||||
return sr
|
||||
}
|
||||
|
||||
func (sr *StochRSI) Update(price float64) {
|
||||
sr.r.Update(price)
|
||||
sr.st.Update(sr.r.Result())
|
||||
}
|
||||
|
||||
func (sr *StochRSI) KResult() float64 {
|
||||
return sr.st.KResult()
|
||||
}
|
||||
|
||||
func (sr *StochRSI) DResult() float64 {
|
||||
return sr.st.DResult()
|
||||
}
|
||||
|
||||
func (sr *StochRSI) Result() float64 {
|
||||
return sr.st.Result()
|
||||
}
|
||||
|
||||
func (sr *StochRSI) FastResult() float64 {
|
||||
return sr.st.KResult()
|
||||
}
|
||||
|
||||
func (sr *StochRSI) SlowResult() float64 {
|
||||
return sr.st.DResult()
|
||||
}
|
227
tool.go
Normal file
227
tool.go
Normal file
|
@ -0,0 +1,227 @@
|
|||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user