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