mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
all: add parameter index to the Last method
This commit is contained in:
parent
2a074ba11b
commit
5515f588e3
|
@ -48,7 +48,7 @@ func (s *LowerShadowTakeProfit) Bind(session *ExchangeSession, orderExecutor *Ge
|
|||
}
|
||||
|
||||
// skip close price higher than the ewma
|
||||
if closePrice.Float64() > ewma.Last() {
|
||||
if closePrice.Float64() > ewma.Last(0) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ func (s *StopEMA) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExec
|
|||
}
|
||||
|
||||
func (s *StopEMA) Allowed(closePrice fixedpoint.Value) bool {
|
||||
ema := fixedpoint.NewFromFloat(s.stopEWMA.Last())
|
||||
ema := fixedpoint.NewFromFloat(s.stopEWMA.Last(0))
|
||||
if ema.IsZero() {
|
||||
logrus.Infof("stopEMA protection: value is zero, skip")
|
||||
return false
|
||||
|
|
|
@ -29,12 +29,12 @@ func (s *TrendEMA) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExe
|
|||
}
|
||||
|
||||
s.last = s.ewma.Values[s.ewma.Length()-2]
|
||||
s.current = s.ewma.Last()
|
||||
s.current = s.ewma.Last(0)
|
||||
})
|
||||
|
||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) {
|
||||
s.last = s.current
|
||||
s.current = s.ewma.Last()
|
||||
s.current = s.ewma.Last(0)
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -183,12 +183,12 @@ func (s Slice) Addr() *Slice {
|
|||
}
|
||||
|
||||
// Last, Index, Length implements the types.Series interface
|
||||
func (s Slice) Last() float64 {
|
||||
func (s Slice) Last(i int) float64 {
|
||||
length := len(s)
|
||||
if length > 0 {
|
||||
return s[length-1]
|
||||
}
|
||||
if i < 0 || length-1-i < 0 {
|
||||
return 0.0
|
||||
}
|
||||
return s[length-1-i]
|
||||
}
|
||||
|
||||
// Index fetches the element from the end of the slice
|
||||
|
|
|
@ -35,15 +35,16 @@ func (inc *AD) Update(high, low, cloze, volume float64) {
|
|||
moneyFlowVolume = ((2*cloze - high - low) / (high - low)) * volume
|
||||
}
|
||||
|
||||
ad := inc.Last() + moneyFlowVolume
|
||||
ad := inc.Last(0) + moneyFlowVolume
|
||||
inc.Values.Push(ad)
|
||||
}
|
||||
|
||||
func (inc *AD) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
func (inc *AD) Last(i int) float64 {
|
||||
length := len(inc.Values)
|
||||
if length == 0 || length-i-1 < 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
return inc.Values[length-i-1]
|
||||
}
|
||||
|
||||
func (inc *AD) Index(i int) float64 {
|
||||
|
@ -68,7 +69,7 @@ func (inc *AD) CalculateAndUpdate(kLines []types.KLine) {
|
|||
inc.Update(k.High.Float64(), k.Low.Float64(), k.Close.Float64(), k.Volume.Float64())
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
//
|
||||
// @param offset: Gaussian applied to the combo line. 1->ema, 0->sma
|
||||
// @param sigma: the standard deviation applied to the combo line. This makes the combo line sharper
|
||||
//
|
||||
//go:generate callbackgen -type ALMA
|
||||
type ALMA struct {
|
||||
types.SeriesBase
|
||||
|
@ -64,11 +65,11 @@ func (inc *ALMA) Update(value float64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (inc *ALMA) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
func (inc *ALMA) Last(i int) float64 {
|
||||
if i >= len(inc.Values) {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
return inc.Values[len(inc.Values)-i-1]
|
||||
}
|
||||
|
||||
func (inc *ALMA) Index(i int) float64 {
|
||||
|
@ -88,12 +89,12 @@ func (inc *ALMA) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.input == nil {
|
||||
for _, k := range allKLines {
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
return
|
||||
}
|
||||
inc.Update(allKLines[len(allKLines)-1].Close.Float64())
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func (inc *ALMA) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
||||
|
|
|
@ -53,7 +53,7 @@ func Test_ALMA(t *testing.T) {
|
|||
Sigma: 6,
|
||||
}
|
||||
alma.CalculateAndUpdate(tt.kLines)
|
||||
assert.InDelta(t, tt.want, alma.Last(), Delta)
|
||||
assert.InDelta(t, tt.want, alma.Last(0), Delta)
|
||||
assert.InDelta(t, tt.next, alma.Index(1), Delta)
|
||||
assert.Equal(t, tt.all, alma.Length())
|
||||
})
|
||||
|
|
|
@ -74,18 +74,18 @@ func (inc *ATR) Update(high, low, cloze float64) {
|
|||
|
||||
// apply rolling moving average
|
||||
inc.RMA.Update(trueRange)
|
||||
atr := inc.RMA.Last()
|
||||
atr := inc.RMA.Last(0)
|
||||
inc.PercentageVolatility.Push(atr / cloze)
|
||||
if len(inc.PercentageVolatility) > MaxNumOfATR {
|
||||
inc.PercentageVolatility = inc.PercentageVolatility[MaxNumOfATRTruncateSize-1:]
|
||||
}
|
||||
}
|
||||
|
||||
func (inc *ATR) Last() float64 {
|
||||
func (inc *ATR) Last(i int) float64 {
|
||||
if inc.RMA == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.RMA.Last()
|
||||
return inc.RMA.Last(i)
|
||||
}
|
||||
|
||||
func (inc *ATR) Index(i int) float64 {
|
||||
|
@ -110,5 +110,5 @@ func (inc *ATR) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.High.Float64(), k.Low.Float64(), k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ func Test_calculateATR(t *testing.T) {
|
|||
atr.PushK(k)
|
||||
}
|
||||
|
||||
got := atr.Last()
|
||||
got := atr.Last(0)
|
||||
diff := math.Trunc((got-tt.want)*100) / 100
|
||||
if diff != 0 {
|
||||
t.Errorf("calculateATR() = %v, want %v", got, tt.want)
|
||||
|
|
|
@ -69,15 +69,15 @@ func (inc *ATRP) Update(high, low, cloze float64) {
|
|||
|
||||
// apply rolling moving average
|
||||
inc.RMA.Update(trueRange)
|
||||
atr := inc.RMA.Last()
|
||||
atr := inc.RMA.Last(0)
|
||||
inc.PercentageVolatility.Push(atr / cloze)
|
||||
}
|
||||
|
||||
func (inc *ATRP) Last() float64 {
|
||||
func (inc *ATRP) Last(i int) float64 {
|
||||
if inc.RMA == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.RMA.Last()
|
||||
return inc.RMA.Last(i)
|
||||
}
|
||||
|
||||
func (inc *ATRP) Index(i int) float64 {
|
||||
|
@ -109,7 +109,7 @@ func (inc *ATRP) CalculateAndUpdate(kLines []types.KLine) {
|
|||
inc.PushK(k)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
|
||||
}
|
||||
|
||||
|
|
|
@ -84,8 +84,8 @@ func (inc *BOLL) Update(value float64) {
|
|||
inc.SMA.Update(value)
|
||||
inc.StdDev.Update(value)
|
||||
|
||||
var sma = inc.SMA.Last()
|
||||
var stdDev = inc.StdDev.Last()
|
||||
var sma = inc.SMA.Last(0)
|
||||
var stdDev = inc.StdDev.Last(0)
|
||||
var band = inc.K * stdDev
|
||||
|
||||
var upBand = sma + band
|
||||
|
@ -105,7 +105,7 @@ func (inc *BOLL) PushK(k types.KLine) {
|
|||
}
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.SMA.Last(), inc.UpBand.Last(), inc.DownBand.Last())
|
||||
inc.EmitUpdate(inc.SMA.Last(0), inc.UpBand.Last(0), inc.DownBand.Last(0))
|
||||
}
|
||||
|
||||
func (inc *BOLL) LoadK(allKLines []types.KLine) {
|
||||
|
@ -113,7 +113,7 @@ func (inc *BOLL) LoadK(allKLines []types.KLine) {
|
|||
inc.PushK(k)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.SMA.Last(), inc.UpBand.Last(), inc.DownBand.Last())
|
||||
inc.EmitUpdate(inc.SMA.Last(0), inc.UpBand.Last(0), inc.DownBand.Last(0))
|
||||
}
|
||||
|
||||
func (inc *BOLL) CalculateAndUpdate(allKLines []types.KLine) {
|
||||
|
|
|
@ -61,8 +61,8 @@ func TestBOLL(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
boll := BOLL{IntervalWindow: types.IntervalWindow{Window: tt.window}, K: tt.k}
|
||||
boll.CalculateAndUpdate(tt.kLines)
|
||||
assert.InDelta(t, tt.up, boll.UpBand.Last(), Delta)
|
||||
assert.InDelta(t, tt.down, boll.DownBand.Last(), Delta)
|
||||
assert.InDelta(t, tt.up, boll.UpBand.Last(0), Delta)
|
||||
assert.InDelta(t, tt.down, boll.DownBand.Last(0), Delta)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ func (inc *CCI) Update(value float64) {
|
|||
}
|
||||
|
||||
inc.Input.Push(value)
|
||||
tp := inc.TypicalPrice.Last() - inc.Input.Index(inc.Window) + value
|
||||
tp := inc.TypicalPrice.Last(0) - inc.Input.Index(inc.Window) + value
|
||||
inc.TypicalPrice.Push(tp)
|
||||
if len(inc.Input) < inc.Window {
|
||||
return
|
||||
|
@ -55,7 +55,7 @@ func (inc *CCI) Update(value float64) {
|
|||
}
|
||||
md := 0.
|
||||
for i := 0; i < inc.Window; i++ {
|
||||
diff := inc.Input.Index(i) - ma
|
||||
diff := inc.Input.Last(i) - ma
|
||||
md += diff * diff
|
||||
}
|
||||
md = math.Sqrt(md / float64(inc.Window))
|
||||
|
@ -68,18 +68,12 @@ func (inc *CCI) Update(value float64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (inc *CCI) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *CCI) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *CCI) Index(i int) float64 {
|
||||
if i >= len(inc.Values) {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1-i]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *CCI) Length() int {
|
||||
|
@ -96,12 +90,12 @@ func (inc *CCI) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.TypicalPrice.Length() == 0 {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ func Test_CCI(t *testing.T) {
|
|||
cci.Update(value)
|
||||
}
|
||||
|
||||
last := cci.Last()
|
||||
last := cci.Last(0)
|
||||
assert.InDelta(t, 93.250481, last, Delta)
|
||||
assert.InDelta(t, 81.813449, cci.Index(1), Delta)
|
||||
assert.Equal(t, 50-16+1, cci.Length())
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
// Refer: Cumulative Moving Average, Cumulative Average
|
||||
// Refer: https://en.wikipedia.org/wiki/Moving_average
|
||||
//
|
||||
//go:generate callbackgen -type CA
|
||||
type CA struct {
|
||||
types.SeriesBase
|
||||
|
@ -20,7 +21,7 @@ func (inc *CA) Update(x float64) {
|
|||
if len(inc.Values) == 0 {
|
||||
inc.SeriesBase.Series = inc
|
||||
}
|
||||
newVal := (inc.Values.Last()*inc.length + x) / (inc.length + 1.)
|
||||
newVal := (inc.Values.Last(0)*inc.length + x) / (inc.length + 1.)
|
||||
inc.length += 1
|
||||
inc.Values.Push(newVal)
|
||||
if len(inc.Values) > MaxNumOfEWMA {
|
||||
|
@ -29,18 +30,12 @@ func (inc *CA) Update(x float64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (inc *CA) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *CA) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *CA) Index(i int) float64 {
|
||||
if i >= len(inc.Values) {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1-i]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *CA) Length() int {
|
||||
|
@ -56,7 +51,7 @@ func (inc *CA) PushK(k types.KLine) {
|
|||
func (inc *CA) CalculateAndUpdate(allKLines []types.KLine) {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,22 +51,19 @@ func (inc *DEMA) Update(value float64) {
|
|||
}
|
||||
|
||||
inc.a1.Update(value)
|
||||
inc.a2.Update(inc.a1.Last())
|
||||
inc.Values.Push(2*inc.a1.Last() - inc.a2.Last())
|
||||
inc.a2.Update(inc.a1.Last(0))
|
||||
inc.Values.Push(2*inc.a1.Last(0) - inc.a2.Last(0))
|
||||
if len(inc.Values) > MaxNumOfEWMA {
|
||||
inc.Values = inc.Values[MaxNumOfEWMATruncateSize-1:]
|
||||
}
|
||||
}
|
||||
|
||||
func (inc *DEMA) Last() float64 {
|
||||
return inc.Values.Last()
|
||||
func (inc *DEMA) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *DEMA) Index(i int) float64 {
|
||||
if len(inc.Values)-i-1 >= 0 {
|
||||
return inc.Values[len(inc.Values)-1-i]
|
||||
}
|
||||
return 0
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *DEMA) Length() int {
|
||||
|
@ -83,13 +80,13 @@ func (inc *DEMA) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.a1 == nil {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
} else {
|
||||
// last k
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ func Test_DEMA(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
dema := DEMA{IntervalWindow: types.IntervalWindow{Window: 16}}
|
||||
dema.CalculateAndUpdate(tt.kLines)
|
||||
last := dema.Last()
|
||||
last := dema.Last(0)
|
||||
assert.InDelta(t, tt.want, last, Delta)
|
||||
assert.InDelta(t, tt.next, dema.Index(1), Delta)
|
||||
assert.Equal(t, tt.all, dema.Length())
|
||||
|
|
|
@ -72,9 +72,9 @@ func (inc *DMI) Update(high, low, cloze float64) {
|
|||
if inc.atr.Length() < inc.Window {
|
||||
return
|
||||
}
|
||||
k := 100. / inc.atr.Last()
|
||||
dmp := inc.DMP.Last()
|
||||
dmn := inc.DMN.Last()
|
||||
k := 100. / inc.atr.Last(0)
|
||||
dmp := inc.DMP.Last(0)
|
||||
dmn := inc.DMN.Last(0)
|
||||
inc.DIPlus.Update(k * dmp)
|
||||
inc.DIMinus.Update(k * dmn)
|
||||
dx := 100. * math.Abs(dmp-dmn) / (dmp + dmn)
|
||||
|
@ -108,11 +108,11 @@ func (inc *DMI) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.ADX == nil {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.DIPlus.Last(), inc.DIMinus.Last(), inc.ADX.Last())
|
||||
inc.EmitUpdate(inc.DIPlus.Last(0), inc.DIMinus.Last(0), inc.ADX.Last(0))
|
||||
}
|
||||
} else {
|
||||
inc.PushK(last)
|
||||
inc.EmitUpdate(inc.DIPlus.Last(), inc.DIMinus.Last(), inc.ADX.Last())
|
||||
inc.EmitUpdate(inc.DIPlus.Last(0), inc.DIMinus.Last(0), inc.ADX.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,9 +78,9 @@ func Test_DMI(t *testing.T) {
|
|||
ADXSmoothing: 14,
|
||||
}
|
||||
dmi.CalculateAndUpdate(tt.klines)
|
||||
assert.InDelta(t, dmi.GetDIPlus().Last(), tt.want.dip, Delta)
|
||||
assert.InDelta(t, dmi.GetDIMinus().Last(), tt.want.dim, Delta)
|
||||
assert.InDelta(t, dmi.GetADX().Last(), tt.want.adx, Delta)
|
||||
assert.InDelta(t, dmi.GetDIPlus().Last(0), tt.want.dip, Delta)
|
||||
assert.InDelta(t, dmi.GetDIMinus().Last(0), tt.want.dim, Delta)
|
||||
assert.InDelta(t, dmi.GetADX().Last(0), tt.want.adx, Delta)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ func (inc *Drift) Update(value float64) {
|
|||
inc.chng.Update(chng)
|
||||
if inc.chng.Length() >= inc.Window {
|
||||
stdev := types.Stdev(inc.chng, inc.Window)
|
||||
drift := inc.MA.Last() - stdev*stdev*0.5
|
||||
drift := inc.MA.Last(0) - stdev*stdev*0.5
|
||||
inc.Values.Push(drift)
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func (inc *Drift) ZeroPoint() float64 {
|
|||
} else {
|
||||
return N2
|
||||
}*/
|
||||
return inc.LastValue * math.Exp(window*(0.5*stdev*stdev)+chng-inc.MA.Last()*window)
|
||||
return inc.LastValue * math.Exp(window*(0.5*stdev*stdev)+chng-inc.MA.Last(0)*window)
|
||||
}
|
||||
|
||||
func (inc *Drift) Clone() (out *Drift) {
|
||||
|
@ -96,17 +96,11 @@ func (inc *Drift) TestUpdate(value float64) *Drift {
|
|||
}
|
||||
|
||||
func (inc *Drift) Index(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *Drift) Last() float64 {
|
||||
if inc.Values.Length() == 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
func (inc *Drift) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *Drift) Length() int {
|
||||
|
@ -126,12 +120,12 @@ func (inc *Drift) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.chng == nil {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,11 +55,12 @@ func (inc *EMV) Index(i int) float64 {
|
|||
return inc.Values.Index(i)
|
||||
}
|
||||
|
||||
func (inc *EMV) Last() float64 {
|
||||
func (inc *EMV) Last(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *EMV) Length() int {
|
||||
|
|
|
@ -16,7 +16,7 @@ func Test_EMV(t *testing.T) {
|
|||
}
|
||||
emv.Update(63.74, 62.63, 32178836)
|
||||
emv.Update(64.51, 63.85, 36461672)
|
||||
assert.InDelta(t, 1.8, emv.Values.rawValues.Last(), Delta)
|
||||
assert.InDelta(t, 1.8, emv.Values.rawValues.Last(0), Delta)
|
||||
emv.Update(64.57, 63.81, 51372680)
|
||||
emv.Update(64.31, 62.62, 42476356)
|
||||
emv.Update(63.43, 62.73, 29504176)
|
||||
|
@ -30,5 +30,5 @@ func Test_EMV(t *testing.T) {
|
|||
emv.Update(65.25, 64.48, 37015388)
|
||||
emv.Update(64.69, 63.65, 40672116)
|
||||
emv.Update(64.26, 63.68, 35627200)
|
||||
assert.InDelta(t, -0.03, emv.Last(), Delta)
|
||||
assert.InDelta(t, -0.03, emv.Last(0), Delta)
|
||||
}
|
||||
|
|
|
@ -50,24 +50,20 @@ func (inc *EWMA) Update(value float64) {
|
|||
inc.Values = inc.Values[MaxNumOfEWMATruncateSize-1:]
|
||||
}
|
||||
|
||||
ema := (1-multiplier)*inc.Last() + multiplier*value
|
||||
ema := (1-multiplier)*inc.Last(0) + multiplier*value
|
||||
inc.Values.Push(ema)
|
||||
}
|
||||
|
||||
func (inc *EWMA) Last() float64 {
|
||||
func (inc *EWMA) Last(i int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *EWMA) Index(i int) float64 {
|
||||
if i >= len(inc.Values) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return inc.Values[len(inc.Values)-1-i]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *EWMA) Length() int {
|
||||
|
@ -81,7 +77,7 @@ func (inc *EWMA) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func CalculateKLinesEMA(allKLines []types.KLine, priceF KLineValueMapper, window int) float64 {
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
// The Fisher Transform is calculated by taking the natural logarithm of the ratio of the security's current price to its moving average,
|
||||
// and then double-smoothing the result. This resulting line is called the Fisher Transform line, and can be plotted on the price chart
|
||||
// along with the security's price.
|
||||
//
|
||||
//go:generate callbackgen -type FisherTransform
|
||||
type FisherTransform struct {
|
||||
types.SeriesBase
|
||||
|
@ -60,18 +61,15 @@ func (inc *FisherTransform) Update(value float64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (inc *FisherTransform) Last() float64 {
|
||||
func (inc *FisherTransform) Last(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *FisherTransform) Index(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *FisherTransform) Length() int {
|
||||
|
|
|
@ -23,16 +23,12 @@ func NewFloat64Series(v ...float64) Float64Series {
|
|||
return s
|
||||
}
|
||||
|
||||
func (f *Float64Series) Last() float64 {
|
||||
return f.slice.Last()
|
||||
func (f *Float64Series) Last(i int) float64 {
|
||||
return f.slice.Last(i)
|
||||
}
|
||||
|
||||
func (f *Float64Series) Index(i int) float64 {
|
||||
length := len(f.slice)
|
||||
if length == 0 || length-i-1 < 0 {
|
||||
return 0
|
||||
}
|
||||
return f.slice[length-i-1]
|
||||
return f.slice.Last(i)
|
||||
}
|
||||
|
||||
func (f *Float64Series) Length() int {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package indicator
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/datatype/floats"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Refer: https://jamesgoulding.com/Research_II/Ehlers/Ehlers%20(Optimal%20Tracking%20Filters).doc
|
||||
|
@ -39,16 +40,13 @@ func (inc *GHFilter) update(value, uncertainty float64) {
|
|||
lambda := inc.a / inc.b
|
||||
lambda2 := lambda * lambda
|
||||
alpha := (-lambda2 + math.Sqrt(lambda2*lambda2+16*lambda2)) / 8
|
||||
filtered := alpha*value + (1-alpha)*inc.Values.Last()
|
||||
filtered := alpha*value + (1-alpha)*inc.Values.Last(0)
|
||||
inc.Values.Push(filtered)
|
||||
inc.lastMeasurement = value
|
||||
}
|
||||
|
||||
func (inc *GHFilter) Index(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *GHFilter) Length() int {
|
||||
|
@ -58,11 +56,11 @@ func (inc *GHFilter) Length() int {
|
|||
return inc.Values.Length()
|
||||
}
|
||||
|
||||
func (inc *GHFilter) Last() float64 {
|
||||
func (inc *GHFilter) Last(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
// interfaces implementation check
|
||||
|
|
|
@ -6058,7 +6058,7 @@ func Test_GHFilter(t *testing.T) {
|
|||
for _, k := range klines {
|
||||
filter.PushK(k)
|
||||
}
|
||||
got := filter.Last()
|
||||
got := filter.Last(0)
|
||||
got = math.Trunc(got*100.0) / 100.0
|
||||
if got != tt.want {
|
||||
t.Errorf("GHFilter.Last() = %v, want %v", got, tt.want)
|
||||
|
@ -6125,10 +6125,10 @@ func Test_GHFilterEstimationAccurate(t *testing.T) {
|
|||
for i, k := range klines {
|
||||
// square error between last estimated state and current actual state
|
||||
if i > 0 {
|
||||
filterDiff2Sum += klineSquareError(filter.Last(), k)
|
||||
ewmaDiff2Sum += klineSquareError(ewma.Last(), k)
|
||||
filterCloseDiff2Sum += closeSquareError(filter.Last(), k)
|
||||
ewmaCloseDiff2Sum += closeSquareError(ewma.Last(), k)
|
||||
filterDiff2Sum += klineSquareError(filter.Last(0), k)
|
||||
ewmaDiff2Sum += klineSquareError(ewma.Last(0), k)
|
||||
filterCloseDiff2Sum += closeSquareError(filter.Last(0), k)
|
||||
ewmaCloseDiff2Sum += closeSquareError(ewma.Last(0), k)
|
||||
}
|
||||
|
||||
// update estimations
|
||||
|
|
|
@ -22,18 +22,15 @@ type GMA struct {
|
|||
UpdateCallbacks []func(value float64)
|
||||
}
|
||||
|
||||
func (inc *GMA) Last() float64 {
|
||||
func (inc *GMA) Last(i int) float64 {
|
||||
if inc.SMA == nil {
|
||||
return 0.0
|
||||
}
|
||||
return math.Exp(inc.SMA.Last())
|
||||
return math.Exp(inc.SMA.Last(i))
|
||||
}
|
||||
|
||||
func (inc *GMA) Index(i int) float64 {
|
||||
if inc.SMA == nil {
|
||||
return 0.0
|
||||
}
|
||||
return math.Exp(inc.SMA.Index(i))
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *GMA) Length() int {
|
||||
|
|
|
@ -51,10 +51,10 @@ func Test_GMA(t *testing.T) {
|
|||
for _, k := range tt.kLines {
|
||||
gma.PushK(k)
|
||||
}
|
||||
assert.InDelta(t, tt.want, gma.Last(), Delta)
|
||||
assert.InDelta(t, tt.want, gma.Last(0), Delta)
|
||||
assert.InDelta(t, tt.next, gma.Index(1), Delta)
|
||||
gma.Update(tt.update)
|
||||
assert.InDelta(t, tt.updateResult, gma.Last(), Delta)
|
||||
assert.InDelta(t, tt.updateResult, gma.Last(0), Delta)
|
||||
assert.Equal(t, tt.all, gma.Length())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
// the weighted moving average of the input data using a weighting factor of W, where W is the square root of the length of the moving average.
|
||||
// The result is then double-smoothed by taking the weighted moving average of this result using a weighting factor of W/2. This final average
|
||||
// forms the HMA line, which can be used to make predictions about future price movements.
|
||||
//
|
||||
//go:generate callbackgen -type HULL
|
||||
type HULL struct {
|
||||
types.SeriesBase
|
||||
|
@ -36,14 +37,14 @@ func (inc *HULL) Update(value float64) {
|
|||
}
|
||||
inc.ma1.Update(value)
|
||||
inc.ma2.Update(value)
|
||||
inc.result.Update(2*inc.ma1.Last() - inc.ma2.Last())
|
||||
inc.result.Update(2*inc.ma1.Last(0) - inc.ma2.Last(0))
|
||||
}
|
||||
|
||||
func (inc *HULL) Last() float64 {
|
||||
func (inc *HULL) Last(i int) float64 {
|
||||
if inc.result == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.result.Last()
|
||||
return inc.result.Index(i)
|
||||
}
|
||||
|
||||
func (inc *HULL) Index(i int) float64 {
|
||||
|
@ -66,5 +67,5 @@ func (inc *HULL) PushK(k types.KLine) {
|
|||
}
|
||||
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ func Test_HULL(t *testing.T) {
|
|||
hull.PushK(k)
|
||||
}
|
||||
|
||||
last := hull.Last()
|
||||
last := hull.Last(0)
|
||||
assert.InDelta(t, tt.want, last, Delta)
|
||||
assert.InDelta(t, tt.next, hull.Index(1), Delta)
|
||||
assert.Equal(t, tt.all, hull.Length())
|
||||
|
|
|
@ -25,7 +25,7 @@ type KLinePusher interface {
|
|||
// Simple is the simple indicator that only returns one float64 value
|
||||
type Simple interface {
|
||||
KLinePusher
|
||||
Last() float64
|
||||
Last(int) float64
|
||||
OnUpdate(f func(value float64))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package indicator
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/datatype/floats"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Refer: https://www.kalmanfilter.net/kalman1d.html
|
||||
|
@ -25,7 +26,7 @@ type KalmanFilter struct {
|
|||
func (inc *KalmanFilter) Update(value float64) {
|
||||
var measureMove = value
|
||||
if inc.measurements != nil {
|
||||
measureMove = value - inc.measurements.Last()
|
||||
measureMove = value - inc.measurements.Last(0)
|
||||
}
|
||||
inc.update(value, math.Abs(measureMove))
|
||||
}
|
||||
|
@ -46,7 +47,7 @@ func (inc *KalmanFilter) update(value, amp float64) {
|
|||
q := math.Sqrt(types.Mean(inc.amp2)) * float64(1+inc.AdditionalSmoothWindow)
|
||||
|
||||
// update
|
||||
lastPredict := inc.Values.Last()
|
||||
lastPredict := inc.Values.Last(0)
|
||||
curState := value + (value - lastPredict)
|
||||
estimated := lastPredict + inc.k*(curState-lastPredict)
|
||||
|
||||
|
@ -57,24 +58,15 @@ func (inc *KalmanFilter) update(value, amp float64) {
|
|||
}
|
||||
|
||||
func (inc *KalmanFilter) Index(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *KalmanFilter) Length() int {
|
||||
if inc.Values == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Length()
|
||||
}
|
||||
|
||||
func (inc *KalmanFilter) Last() float64 {
|
||||
if inc.Values == nil {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
func (inc *KalmanFilter) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
// interfaces implementation check
|
||||
|
|
|
@ -6065,7 +6065,7 @@ func Test_KalmanFilter(t *testing.T) {
|
|||
for _, k := range klines {
|
||||
filter.PushK(k)
|
||||
}
|
||||
got := filter.Last()
|
||||
got := filter.Last(0)
|
||||
got = math.Trunc(got*100.0) / 100.0
|
||||
if got != tt.want {
|
||||
t.Errorf("KalmanFilter.Last() = %v, want %v", got, tt.want)
|
||||
|
@ -6160,10 +6160,10 @@ func Test_KalmanFilterEstimationAccurate(t *testing.T) {
|
|||
for _, k := range klines {
|
||||
// square error between last estimated state and current actual state
|
||||
if ewma.Length() > 0 {
|
||||
filterDiff2Sum += klineSquareError(filter.Last(), k)
|
||||
ewmaDiff2Sum += klineSquareError(ewma.Last(), k)
|
||||
filterCloseDiff2Sum += closeSquareError(filter.Last(), k)
|
||||
ewmaCloseDiff2Sum += closeSquareError(ewma.Last(), k)
|
||||
filterDiff2Sum += klineSquareError(filter.Last(0), k)
|
||||
ewmaDiff2Sum += klineSquareError(ewma.Last(0), k)
|
||||
filterCloseDiff2Sum += closeSquareError(filter.Last(0), k)
|
||||
ewmaCloseDiff2Sum += closeSquareError(ewma.Last(0), k)
|
||||
numEstimations++
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
// The Klinger Oscillator is calculated by taking the difference between a 34-period and 55-period moving average.
|
||||
// Usually the indicator is using together with a 9-period or 13-period of moving average as the signal line.
|
||||
// This indicator is often used to identify potential turning points in the market, as well as to confirm the strength of a trend.
|
||||
//
|
||||
//go:generate callbackgen -type KlingerOscillator
|
||||
type KlingerOscillator struct {
|
||||
types.SeriesBase
|
||||
|
@ -30,17 +31,11 @@ func (inc *KlingerOscillator) Length() int {
|
|||
return inc.Fast.Length()
|
||||
}
|
||||
|
||||
func (inc *KlingerOscillator) Last() float64 {
|
||||
func (inc *KlingerOscillator) Last(i int) float64 {
|
||||
if inc.Fast == nil || inc.Slow == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.Fast.Last() - inc.Slow.Last()
|
||||
}
|
||||
func (inc *KlingerOscillator) Index(i int) float64 {
|
||||
if inc.Fast == nil || inc.Slow == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.Fast.Index(i) - inc.Slow.Index(i)
|
||||
return inc.Fast.Last(i) - inc.Slow.Last(i)
|
||||
}
|
||||
|
||||
func (inc *KlingerOscillator) Update(high, low, cloze, volume float64) {
|
||||
|
|
|
@ -38,12 +38,12 @@ func (l *Line) Bind(updater KLineWindowUpdater) {
|
|||
updater.OnKLineWindowUpdate(l.handleKLineWindowUpdate)
|
||||
}
|
||||
|
||||
func (l *Line) Last() float64 {
|
||||
return (l.end-l.start)/float64(l.startIndex-l.endIndex)*float64(l.endIndex) + l.end
|
||||
func (l *Line) Last(i int) float64 {
|
||||
return (l.end-l.start)/float64(l.startIndex-l.endIndex)*float64(l.endIndex-i) + l.end
|
||||
}
|
||||
|
||||
func (l *Line) Index(i int) float64 {
|
||||
return (l.end-l.start)/float64(l.startIndex-l.endIndex)*float64(l.endIndex-i) + l.end
|
||||
return l.Last(i)
|
||||
}
|
||||
|
||||
func (l *Line) Length() int {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package indicator
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/datatype/floats"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
var logLinReg = logrus.WithField("indicator", "LinReg")
|
||||
|
||||
// LinReg is Linear Regression baseline
|
||||
//
|
||||
//go:generate callbackgen -type LinReg
|
||||
type LinReg struct {
|
||||
types.SeriesBase
|
||||
|
@ -28,11 +30,8 @@ type LinReg struct {
|
|||
}
|
||||
|
||||
// Last slope of linear regression baseline
|
||||
func (lr *LinReg) Last() float64 {
|
||||
if lr.Values.Length() == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return lr.Values.Last()
|
||||
func (lr *LinReg) Last(i int) float64 {
|
||||
return lr.Values.Last(i)
|
||||
}
|
||||
|
||||
// LastRatio of slope to price
|
||||
|
@ -40,16 +39,12 @@ func (lr *LinReg) LastRatio() float64 {
|
|||
if lr.ValueRatios.Length() == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return lr.ValueRatios.Last()
|
||||
return lr.ValueRatios.Last(0)
|
||||
}
|
||||
|
||||
// Index returns the slope of specified index
|
||||
func (lr *LinReg) Index(i int) float64 {
|
||||
if i >= lr.Values.Length() {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return lr.Values.Index(i)
|
||||
return lr.Values.Last(i)
|
||||
}
|
||||
|
||||
// IndexRatio returns the slope ratio
|
||||
|
@ -58,7 +53,7 @@ func (lr *LinReg) IndexRatio(i int) float64 {
|
|||
return 0.0
|
||||
}
|
||||
|
||||
return lr.ValueRatios.Index(i)
|
||||
return lr.ValueRatios.Last(i)
|
||||
}
|
||||
|
||||
// Length of the slope values
|
||||
|
@ -99,9 +94,9 @@ func (lr *LinReg) Update(kline types.KLine) {
|
|||
endPrice := average - slope*sumX/length + slope
|
||||
startPrice := endPrice + slope*(length-1)
|
||||
lr.Values.Push((endPrice - startPrice) / (length - 1))
|
||||
lr.ValueRatios.Push(lr.Values.Last() / kline.GetClose().Float64())
|
||||
lr.ValueRatios.Push(lr.Values.Last(0) / kline.GetClose().Float64())
|
||||
|
||||
logLinReg.Debugf("linear regression baseline slope: %f", lr.Last())
|
||||
logLinReg.Debugf("linear regression baseline slope: %f", lr.Last(0))
|
||||
}
|
||||
|
||||
func (lr *LinReg) BindK(target KLineClosedEmitter, symbol string, interval types.Interval) {
|
||||
|
|
|
@ -33,5 +33,5 @@ func (inc *Low) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.Low.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
|
|
@ -59,14 +59,14 @@ func (inc *MACDLegacy) Update(x float64) {
|
|||
inc.slowEWMA.Update(x)
|
||||
|
||||
// update MACD value, it's also the signal line
|
||||
fast := inc.fastEWMA.Last()
|
||||
slow := inc.slowEWMA.Last()
|
||||
fast := inc.fastEWMA.Last(0)
|
||||
slow := inc.slowEWMA.Last(0)
|
||||
macd := fast - slow
|
||||
inc.Values.Push(macd)
|
||||
|
||||
// update signal line
|
||||
inc.signalLine.Update(macd)
|
||||
signal := inc.signalLine.Last()
|
||||
signal := inc.signalLine.Last(0)
|
||||
|
||||
// update histogram
|
||||
histogram := macd - signal
|
||||
|
@ -75,7 +75,7 @@ func (inc *MACDLegacy) Update(x float64) {
|
|||
inc.EmitUpdate(macd, signal, histogram)
|
||||
}
|
||||
|
||||
func (inc *MACDLegacy) Last() float64 {
|
||||
func (inc *MACDLegacy) Last(int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
@ -106,21 +106,12 @@ type MACDValues struct {
|
|||
*MACDLegacy
|
||||
}
|
||||
|
||||
func (inc *MACDValues) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *MACDValues) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *MACDValues) Index(i int) float64 {
|
||||
length := len(inc.Values)
|
||||
if length == 0 || length-1-i < 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return inc.Values[length-1+i]
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *MACDValues) Length() int {
|
||||
|
|
|
@ -45,7 +45,7 @@ func Test_calculateMACD(t *testing.T) {
|
|||
macd.PushK(k)
|
||||
}
|
||||
|
||||
got := macd.Last()
|
||||
got := macd.Last(0)
|
||||
diff := math.Trunc((got-tt.want)*100) / 100
|
||||
if diff != 0 {
|
||||
t.Errorf("calculateMACD() = %v, want %v", got, tt.want)
|
||||
|
|
|
@ -40,24 +40,18 @@ func (inc *OBV) Update(price, volume float64) {
|
|||
}
|
||||
|
||||
if volume < inc.PrePrice {
|
||||
inc.Values.Push(inc.Last() - volume)
|
||||
inc.Values.Push(inc.Last(0) - volume)
|
||||
} else {
|
||||
inc.Values.Push(inc.Last() + volume)
|
||||
inc.Values.Push(inc.Last(0) + volume)
|
||||
}
|
||||
}
|
||||
|
||||
func (inc *OBV) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *OBV) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *OBV) Index(i int) float64 {
|
||||
if len(inc.Values)-i <= 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
var _ types.SeriesExtend = &OBV{}
|
||||
|
@ -75,7 +69,7 @@ func (inc *OBV) CalculateAndUpdate(kLines []types.KLine) {
|
|||
inc.PushK(k)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
|
||||
//go:generate callbackgen -type Pivot
|
||||
type Pivot struct {
|
||||
types.IntervalWindow
|
||||
|
@ -105,12 +104,12 @@ func calculatePivot(klines []types.KLine, window int, valLow KLineValueMapper, v
|
|||
}
|
||||
|
||||
pl := 0.
|
||||
if lows.Min() == lows.Index(int(window/2.)-1) {
|
||||
if lows.Min() == lows.Last(int(window/2.)-1) {
|
||||
pl = lows.Min()
|
||||
}
|
||||
|
||||
ph := 0.
|
||||
if highs.Max() == highs.Index(int(window/2.)-1) {
|
||||
if highs.Max() == highs.Last(int(window/2.)-1) {
|
||||
ph = highs.Max()
|
||||
}
|
||||
|
||||
|
|
|
@ -24,12 +24,12 @@ func (inc *PivotHigh) Length() int {
|
|||
return inc.Values.Length()
|
||||
}
|
||||
|
||||
func (inc *PivotHigh) Last() float64 {
|
||||
func (inc *PivotHigh) Last(int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return inc.Values.Last()
|
||||
return inc.Values.Last(0)
|
||||
}
|
||||
|
||||
func (inc *PivotHigh) Update(value float64) {
|
||||
|
@ -60,5 +60,5 @@ func (inc *PivotHigh) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.High.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ func (inc *PivotLow) Length() int {
|
|||
return inc.Values.Length()
|
||||
}
|
||||
|
||||
func (inc *PivotLow) Last() float64 {
|
||||
func (inc *PivotLow) Last(int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return inc.Values.Last()
|
||||
return inc.Values.Last(0)
|
||||
}
|
||||
|
||||
func (inc *PivotLow) Update(value float64) {
|
||||
|
@ -60,7 +60,7 @@ func (inc *PivotLow) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.Low.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func calculatePivotHigh(highs floats.Slice, left, right int) (float64, bool) {
|
||||
|
|
|
@ -34,11 +34,11 @@ type PSAR struct {
|
|||
UpdateCallbacks []func(value float64)
|
||||
}
|
||||
|
||||
func (inc *PSAR) Last() float64 {
|
||||
func (inc *PSAR) Last(int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
return inc.Values.Last(0)
|
||||
}
|
||||
|
||||
func (inc *PSAR) Length() int {
|
||||
|
@ -46,8 +46,8 @@ func (inc *PSAR) Length() int {
|
|||
}
|
||||
|
||||
func (inc *PSAR) falling() bool {
|
||||
up := inc.High.Last() - inc.High.Index(1)
|
||||
dn := inc.Low.Index(1) - inc.Low.Last()
|
||||
up := inc.High.Last(0) - inc.High.Index(1)
|
||||
dn := inc.Low.Index(1) - inc.Low.Last(0)
|
||||
return (dn > up) && (dn > 0)
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ func (inc *PSAR) Update(high, low float64) {
|
|||
inc.High.Update(high)
|
||||
inc.Low.Update(low)
|
||||
if !isFirst {
|
||||
ppsar := inc.Values.Last()
|
||||
ppsar := inc.Values.Last(0)
|
||||
if inc.Falling { // falling formula
|
||||
psar := ppsar - inc.AF*(ppsar-inc.EP)
|
||||
h := inc.High.Shift(1).Highest(2)
|
||||
|
|
|
@ -36,5 +36,5 @@ func Test_PSAR(t *testing.T) {
|
|||
}
|
||||
assert.Equal(t, psar.Length(), 29)
|
||||
assert.Equal(t, psar.AF, 0.04)
|
||||
assert.Equal(t, psar.Last(), 0.16)
|
||||
assert.Equal(t, psar.Last(0), 0.16)
|
||||
}
|
||||
|
|
|
@ -78,16 +78,12 @@ func (inc *RMA) Update(x float64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (inc *RMA) Last() float64 {
|
||||
return inc.Values.Last()
|
||||
func (inc *RMA) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *RMA) Index(i int) float64 {
|
||||
length := len(inc.Values)
|
||||
if length == 0 || length-i-1 < 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[length-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *RMA) Length() int {
|
||||
|
@ -116,7 +112,7 @@ func (inc *RMA) CalculateAndUpdate(kLines []types.KLine) {
|
|||
inc.PushK(last)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func (inc *RMA) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
||||
|
|
|
@ -65,19 +65,12 @@ func (inc *RSI) Update(price float64) {
|
|||
inc.PreviousAvgLoss = avgLoss
|
||||
}
|
||||
|
||||
func (inc *RSI) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *RSI) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *RSI) Index(i int) float64 {
|
||||
length := len(inc.Values)
|
||||
if length <= 0 || length-i-1 < 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values[length-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *RSI) Length() int {
|
||||
|
@ -99,7 +92,7 @@ func (inc *RSI) CalculateAndUpdate(kLines []types.KLine) {
|
|||
inc.PushK(k)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
|
||||
}
|
||||
|
||||
|
|
|
@ -22,19 +22,12 @@ type SMA struct {
|
|||
UpdateCallbacks []func(value float64)
|
||||
}
|
||||
|
||||
func (inc *SMA) Last() float64 {
|
||||
if inc.Values.Length() == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
func (inc *SMA) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *SMA) Index(i int) float64 {
|
||||
if i >= inc.Values.Length() {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *SMA) Length() int {
|
||||
|
@ -81,7 +74,7 @@ func (inc *SMA) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Values.Last())
|
||||
inc.EmitUpdate(inc.Values.Last(0))
|
||||
}
|
||||
|
||||
func (inc *SMA) LoadK(allKLines []types.KLine) {
|
||||
|
|
|
@ -58,10 +58,10 @@ func Test_SMA(t *testing.T) {
|
|||
sma.PushK(k)
|
||||
}
|
||||
|
||||
assert.InDelta(t, tt.want, sma.Last(), Delta)
|
||||
assert.InDelta(t, tt.want, sma.Last(0), Delta)
|
||||
assert.InDelta(t, tt.next, sma.Index(1), Delta)
|
||||
sma.Update(tt.update)
|
||||
assert.InDelta(t, tt.updateResult, sma.Last(), Delta)
|
||||
assert.InDelta(t, tt.updateResult, sma.Last(0), Delta)
|
||||
assert.Equal(t, tt.all, sma.Length())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -50,9 +50,9 @@ func (inc *SSF) Update(value float64) {
|
|||
}
|
||||
|
||||
result := inc.c1*value +
|
||||
inc.c2*inc.Values.Index(0) +
|
||||
inc.c3*inc.Values.Index(1) +
|
||||
inc.c4*inc.Values.Index(2)
|
||||
inc.c2*inc.Values.Last(0) +
|
||||
inc.c3*inc.Values.Last(1) +
|
||||
inc.c4*inc.Values.Last(2)
|
||||
inc.Values.Push(result)
|
||||
} else { // poles == 2
|
||||
if inc.Values == nil {
|
||||
|
@ -65,17 +65,18 @@ func (inc *SSF) Update(value float64) {
|
|||
inc.Values = floats.Slice{}
|
||||
}
|
||||
result := inc.c1*value +
|
||||
inc.c2*inc.Values.Index(0) +
|
||||
inc.c3*inc.Values.Index(1)
|
||||
inc.c2*inc.Values.Last(0) +
|
||||
inc.c3*inc.Values.Last(1)
|
||||
inc.Values.Push(result)
|
||||
}
|
||||
}
|
||||
|
||||
func (inc *SSF) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *SSF) Index(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *SSF) Length() int {
|
||||
|
@ -85,13 +86,6 @@ func (inc *SSF) Length() int {
|
|||
return inc.Values.Length()
|
||||
}
|
||||
|
||||
func (inc *SSF) Last() float64 {
|
||||
if inc.Values == nil {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
}
|
||||
|
||||
var _ types.SeriesExtend = &SSF{}
|
||||
|
||||
func (inc *SSF) PushK(k types.KLine) {
|
||||
|
@ -102,12 +96,12 @@ func (inc *SSF) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.Values != nil {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
return
|
||||
}
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ func Test_SSF(t *testing.T) {
|
|||
Poles: tt.poles,
|
||||
}
|
||||
ssf.CalculateAndUpdate(tt.kLines)
|
||||
assert.InDelta(t, tt.want, ssf.Last(), Delta)
|
||||
assert.InDelta(t, tt.want, ssf.Last(0), Delta)
|
||||
assert.InDelta(t, tt.next, ssf.Index(1), Delta)
|
||||
assert.Equal(t, tt.all, ssf.Length())
|
||||
})
|
||||
|
|
|
@ -21,19 +21,12 @@ type StdDev struct {
|
|||
updateCallbacks []func(value float64)
|
||||
}
|
||||
|
||||
func (inc *StdDev) Last() float64 {
|
||||
if inc.Values.Length() == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
func (inc *StdDev) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *StdDev) Index(i int) float64 {
|
||||
if i >= inc.Values.Length() {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *StdDev) Length() int {
|
||||
|
@ -76,7 +69,7 @@ func (inc *StdDev) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
inc.PushK(last)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Values.Last())
|
||||
inc.EmitUpdate(inc.Values.Last(0))
|
||||
}
|
||||
|
||||
func (inc *StdDev) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
||||
|
|
|
@ -50,16 +50,12 @@ type Supertrend struct {
|
|||
UpdateCallbacks []func(value float64)
|
||||
}
|
||||
|
||||
func (inc *Supertrend) Last() float64 {
|
||||
return inc.trendPrices.Last()
|
||||
func (inc *Supertrend) Last(i int) float64 {
|
||||
return inc.trendPrices.Last(i)
|
||||
}
|
||||
|
||||
func (inc *Supertrend) Index(i int) float64 {
|
||||
length := inc.Length()
|
||||
if length == 0 || length-i-1 < 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.trendPrices[length-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *Supertrend) Length() int {
|
||||
|
@ -94,13 +90,13 @@ func (inc *Supertrend) Update(highPrice, lowPrice, closePrice float64) {
|
|||
src := (highPrice + lowPrice) / 2
|
||||
|
||||
// Update uptrend
|
||||
inc.uptrendPrice = src - inc.AverageTrueRange.Last()*inc.ATRMultiplier
|
||||
inc.uptrendPrice = src - inc.AverageTrueRange.Last(0)*inc.ATRMultiplier
|
||||
if inc.previousClosePrice > inc.previousUptrendPrice {
|
||||
inc.uptrendPrice = math.Max(inc.uptrendPrice, inc.previousUptrendPrice)
|
||||
}
|
||||
|
||||
// Update downtrend
|
||||
inc.downtrendPrice = src + inc.AverageTrueRange.Last()*inc.ATRMultiplier
|
||||
inc.downtrendPrice = src + inc.AverageTrueRange.Last(0)*inc.ATRMultiplier
|
||||
if inc.previousClosePrice < inc.previousDowntrendPrice {
|
||||
inc.downtrendPrice = math.Min(inc.downtrendPrice, inc.previousDowntrendPrice)
|
||||
}
|
||||
|
@ -115,7 +111,7 @@ func (inc *Supertrend) Update(highPrice, lowPrice, closePrice float64) {
|
|||
}
|
||||
|
||||
// Update signal
|
||||
if inc.AverageTrueRange.Last() <= 0 {
|
||||
if inc.AverageTrueRange.Last(0) <= 0 {
|
||||
inc.tradeSignal = types.DirectionNone
|
||||
} else if inc.trend == types.DirectionUp && inc.previousTrend == types.DirectionDown {
|
||||
inc.tradeSignal = types.DirectionUp
|
||||
|
@ -138,7 +134,7 @@ func (inc *Supertrend) Update(highPrice, lowPrice, closePrice float64) {
|
|||
|
||||
logst.Debugf("Update supertrend result: closePrice: %v, uptrendPrice: %v, downtrendPrice: %v, trend: %v,"+
|
||||
" tradeSignal: %v, AverageTrueRange.Last(): %v", inc.closePrice, inc.uptrendPrice, inc.downtrendPrice,
|
||||
inc.trend, inc.tradeSignal, inc.AverageTrueRange.Last())
|
||||
inc.trend, inc.tradeSignal, inc.AverageTrueRange.Last(0))
|
||||
}
|
||||
|
||||
func (inc *Supertrend) GetSignal() types.Direction {
|
||||
|
@ -152,12 +148,12 @@ func (inc *Supertrend) Direction() types.Direction {
|
|||
|
||||
// LastSupertrendSupport return the current supertrend support
|
||||
func (inc *Supertrend) LastSupertrendSupport() float64 {
|
||||
return inc.supportLine.Last()
|
||||
return inc.supportLine.Last(0)
|
||||
}
|
||||
|
||||
// LastSupertrendResistance return the current supertrend resistance
|
||||
func (inc *Supertrend) LastSupertrendResistance() float64 {
|
||||
return inc.resistanceLine.Last()
|
||||
return inc.resistanceLine.Last(0)
|
||||
}
|
||||
|
||||
var _ types.SeriesExtend = &Supertrend{}
|
||||
|
@ -169,7 +165,7 @@ func (inc *Supertrend) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.GetHigh().Float64(), k.GetLow().Float64(), k.GetClose().Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
|
||||
}
|
||||
|
||||
|
@ -192,7 +188,7 @@ func (inc *Supertrend) CalculateAndUpdate(kLines []types.KLine) {
|
|||
inc.PushK(k)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
inc.EndTime = kLines[len(kLines)-1].EndTime.Time()
|
||||
}
|
||||
|
||||
|
|
|
@ -50,16 +50,12 @@ type PivotSupertrend struct {
|
|||
UpdateCallbacks []func(value float64)
|
||||
}
|
||||
|
||||
func (inc *PivotSupertrend) Last() float64 {
|
||||
return inc.trendPrices.Last()
|
||||
func (inc *PivotSupertrend) Last(i int) float64 {
|
||||
return inc.trendPrices.Last(i)
|
||||
}
|
||||
|
||||
func (inc *PivotSupertrend) Index(i int) float64 {
|
||||
length := inc.Length()
|
||||
if length == 0 || length-i-1 < 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.trendPrices[length-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *PivotSupertrend) Length() int {
|
||||
|
@ -80,8 +76,8 @@ func (inc *PivotSupertrend) Update(highPrice, lowPrice, closePrice float64) {
|
|||
inc.trend = types.DirectionUp
|
||||
}
|
||||
|
||||
inc.previousPivotLow = inc.PivotLow.Last()
|
||||
inc.previousPivotHigh = inc.PivotHigh.Last()
|
||||
inc.previousPivotLow = inc.PivotLow.Last(0)
|
||||
inc.previousPivotHigh = inc.PivotHigh.Last(0)
|
||||
|
||||
// Update High / Low pivots
|
||||
inc.PivotLow.Update(lowPrice)
|
||||
|
@ -101,9 +97,9 @@ func (inc *PivotSupertrend) Update(highPrice, lowPrice, closePrice float64) {
|
|||
// Initialize lastPp as soon as pivots are made
|
||||
if inc.lastPp == 0 || math.IsNaN(inc.lastPp) {
|
||||
if inc.PivotHigh.Length() > 0 {
|
||||
inc.lastPp = inc.PivotHigh.Last()
|
||||
inc.lastPp = inc.PivotHigh.Last(0)
|
||||
} else if inc.PivotLow.Length() > 0 {
|
||||
inc.lastPp = inc.PivotLow.Last()
|
||||
inc.lastPp = inc.PivotLow.Last(0)
|
||||
} else {
|
||||
inc.lastPp = math.NaN()
|
||||
return
|
||||
|
@ -111,28 +107,28 @@ func (inc *PivotSupertrend) Update(highPrice, lowPrice, closePrice float64) {
|
|||
}
|
||||
|
||||
// Set lastPp to the latest pivotPoint (only changed when new pivot is found)
|
||||
if inc.PivotHigh.Last() != inc.previousPivotHigh {
|
||||
inc.lastPp = inc.PivotHigh.Last()
|
||||
} else if inc.PivotLow.Last() != inc.previousPivotLow {
|
||||
inc.lastPp = inc.PivotLow.Last()
|
||||
if inc.PivotHigh.Last(0) != inc.previousPivotHigh {
|
||||
inc.lastPp = inc.PivotHigh.Last(0)
|
||||
} else if inc.PivotLow.Last(0) != inc.previousPivotLow {
|
||||
inc.lastPp = inc.PivotLow.Last(0)
|
||||
}
|
||||
|
||||
// calculate the Center line using pivot points
|
||||
if inc.src == 0 || math.IsNaN(inc.src) {
|
||||
inc.src = inc.lastPp
|
||||
} else {
|
||||
//weighted calculation
|
||||
// weighted calculation
|
||||
inc.src = (inc.src*2 + inc.lastPp) / 3
|
||||
}
|
||||
|
||||
// Update uptrend
|
||||
inc.uptrendPrice = inc.src - inc.AverageTrueRange.Last()*inc.ATRMultiplier
|
||||
inc.uptrendPrice = inc.src - inc.AverageTrueRange.Last(0)*inc.ATRMultiplier
|
||||
if inc.previousClosePrice > inc.previousUptrendPrice {
|
||||
inc.uptrendPrice = math.Max(inc.uptrendPrice, inc.previousUptrendPrice)
|
||||
}
|
||||
|
||||
// Update downtrend
|
||||
inc.downtrendPrice = inc.src + inc.AverageTrueRange.Last()*inc.ATRMultiplier
|
||||
inc.downtrendPrice = inc.src + inc.AverageTrueRange.Last(0)*inc.ATRMultiplier
|
||||
if inc.previousClosePrice < inc.previousDowntrendPrice {
|
||||
inc.downtrendPrice = math.Min(inc.downtrendPrice, inc.previousDowntrendPrice)
|
||||
}
|
||||
|
@ -147,7 +143,7 @@ func (inc *PivotSupertrend) Update(highPrice, lowPrice, closePrice float64) {
|
|||
}
|
||||
|
||||
// Update signal
|
||||
if inc.AverageTrueRange.Last() <= 0 {
|
||||
if inc.AverageTrueRange.Last(0) <= 0 {
|
||||
inc.tradeSignal = types.DirectionNone
|
||||
} else if inc.trend == types.DirectionUp && inc.previousTrend == types.DirectionDown {
|
||||
inc.tradeSignal = types.DirectionUp
|
||||
|
@ -170,7 +166,7 @@ func (inc *PivotSupertrend) Update(highPrice, lowPrice, closePrice float64) {
|
|||
|
||||
logpst.Debugf("Update pivot point supertrend result: closePrice: %v, uptrendPrice: %v, downtrendPrice: %v, trend: %v,"+
|
||||
" tradeSignal: %v, AverageTrueRange.Last(): %v", inc.closePrice, inc.uptrendPrice, inc.downtrendPrice,
|
||||
inc.trend, inc.tradeSignal, inc.AverageTrueRange.Last())
|
||||
inc.trend, inc.tradeSignal, inc.AverageTrueRange.Last(0))
|
||||
}
|
||||
|
||||
// GetSignal returns signal (Down, None or Up)
|
||||
|
@ -185,12 +181,12 @@ func (inc *PivotSupertrend) Direction() types.Direction {
|
|||
|
||||
// LastSupertrendSupport return the current supertrend support value
|
||||
func (inc *PivotSupertrend) LastSupertrendSupport() float64 {
|
||||
return inc.supportLine.Last()
|
||||
return inc.supportLine.Last(0)
|
||||
}
|
||||
|
||||
// LastSupertrendResistance return the current supertrend resistance value
|
||||
func (inc *PivotSupertrend) LastSupertrendResistance() float64 {
|
||||
return inc.resistanceLine.Last()
|
||||
return inc.resistanceLine.Last(0)
|
||||
}
|
||||
|
||||
var _ types.SeriesExtend = &PivotSupertrend{}
|
||||
|
@ -202,7 +198,7 @@ func (inc *PivotSupertrend) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.GetHigh().Float64(), k.GetLow().Float64(), k.GetClose().Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func (inc *PivotSupertrend) BindK(target KLineClosedEmitter, symbol string, interval types.Interval) {
|
||||
|
|
|
@ -36,26 +36,20 @@ func (inc *TEMA) Update(value float64) {
|
|||
inc.A3 = &EWMA{IntervalWindow: inc.IntervalWindow}
|
||||
}
|
||||
inc.A1.Update(value)
|
||||
a1 := inc.A1.Last()
|
||||
a1 := inc.A1.Last(0)
|
||||
inc.A2.Update(a1)
|
||||
a2 := inc.A2.Last()
|
||||
a2 := inc.A2.Last(0)
|
||||
inc.A3.Update(a2)
|
||||
a3 := inc.A3.Last()
|
||||
a3 := inc.A3.Last(0)
|
||||
inc.Values.Push(3*a1 - 3*a2 + a3)
|
||||
}
|
||||
|
||||
func (inc *TEMA) Last() float64 {
|
||||
if len(inc.Values) > 0 {
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
}
|
||||
return 0.0
|
||||
func (inc *TEMA) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *TEMA) Index(i int) float64 {
|
||||
if i >= len(inc.Values) {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *TEMA) Length() int {
|
||||
|
@ -72,12 +66,12 @@ func (inc *TEMA) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.A1 == nil {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ func Test_TEMA(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
tema := TEMA{IntervalWindow: types.IntervalWindow{Window: 16}}
|
||||
tema.CalculateAndUpdate(tt.kLines)
|
||||
last := tema.Last()
|
||||
last := tema.Last(0)
|
||||
assert.InDelta(t, tt.want, last, Delta)
|
||||
assert.InDelta(t, tt.next, tema.Index(1), Delta)
|
||||
assert.Equal(t, tt.all, tema.Length())
|
||||
|
|
|
@ -57,28 +57,18 @@ func (inc *TILL) Update(value float64) {
|
|||
}
|
||||
|
||||
inc.e1.Update(value)
|
||||
inc.e2.Update(inc.e1.Last())
|
||||
inc.e3.Update(inc.e2.Last())
|
||||
inc.e4.Update(inc.e3.Last())
|
||||
inc.e5.Update(inc.e4.Last())
|
||||
inc.e6.Update(inc.e5.Last())
|
||||
inc.e2.Update(inc.e1.Last(0))
|
||||
inc.e3.Update(inc.e2.Last(0))
|
||||
inc.e4.Update(inc.e3.Last(0))
|
||||
inc.e5.Update(inc.e4.Last(0))
|
||||
inc.e6.Update(inc.e5.Last(0))
|
||||
}
|
||||
|
||||
func (inc *TILL) Last() float64 {
|
||||
if inc.e1 == nil || inc.e1.Length() == 0 {
|
||||
return 0
|
||||
}
|
||||
e3 := inc.e3.Last()
|
||||
e4 := inc.e4.Last()
|
||||
e5 := inc.e5.Last()
|
||||
e6 := inc.e6.Last()
|
||||
return inc.c1*e6 + inc.c2*e5 + inc.c3*e4 + inc.c4*e3
|
||||
}
|
||||
|
||||
func (inc *TILL) Index(i int) float64 {
|
||||
func (inc *TILL) Last(i int) float64 {
|
||||
if inc.e1 == nil || inc.e1.Length() <= i {
|
||||
return 0
|
||||
}
|
||||
|
||||
e3 := inc.e3.Index(i)
|
||||
e4 := inc.e4.Index(i)
|
||||
e5 := inc.e5.Index(i)
|
||||
|
@ -86,6 +76,10 @@ func (inc *TILL) Index(i int) float64 {
|
|||
return inc.c1*e6 + inc.c2*e5 + inc.c3*e4 + inc.c4*e3
|
||||
}
|
||||
|
||||
func (inc *TILL) Index(i int) float64 {
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *TILL) Length() int {
|
||||
if inc.e1 == nil {
|
||||
return 0
|
||||
|
@ -101,7 +95,7 @@ func (inc *TILL) PushK(k types.KLine) {
|
|||
}
|
||||
|
||||
inc.Update(k.Close.Float64())
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func (inc *TILL) LoadK(allKLines []types.KLine) {
|
||||
|
|
|
@ -57,7 +57,7 @@ func Test_TILL(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
till := TILL{IntervalWindow: types.IntervalWindow{Window: 16}}
|
||||
till.CalculateAndUpdate(tt.kLines)
|
||||
last := till.Last()
|
||||
last := till.Last(0)
|
||||
assert.InDelta(t, tt.want, last, Delta)
|
||||
assert.InDelta(t, tt.next, till.Index(1), Delta)
|
||||
assert.Equal(t, tt.all, till.Length())
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
// Refer: Triangular Moving Average
|
||||
// Refer URL: https://ja.wikipedia.org/wiki/移動平均
|
||||
//
|
||||
//go:generate callbackgen -type TMA
|
||||
type TMA struct {
|
||||
types.SeriesBase
|
||||
|
@ -24,21 +25,15 @@ func (inc *TMA) Update(value float64) {
|
|||
}
|
||||
|
||||
inc.s1.Update(value)
|
||||
inc.s2.Update(inc.s1.Last())
|
||||
inc.s2.Update(inc.s1.Last(0))
|
||||
}
|
||||
|
||||
func (inc *TMA) Last() float64 {
|
||||
if inc.s2 == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.s2.Last()
|
||||
func (inc *TMA) Last(i int) float64 {
|
||||
return inc.s2.Last(i)
|
||||
}
|
||||
|
||||
func (inc *TMA) Index(i int) float64 {
|
||||
if inc.s2 == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.s2.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *TMA) Length() int {
|
||||
|
@ -58,12 +53,12 @@ func (inc *TMA) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.s1 == nil {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
// Refer: True Strength Index
|
||||
// Refer URL: https://www.investopedia.com/terms/t/tsi.asp
|
||||
//
|
||||
//go:generate callbackgen -type TSI
|
||||
type TSI struct {
|
||||
types.SeriesBase
|
||||
|
@ -66,10 +67,10 @@ func (inc *TSI) Update(value float64) {
|
|||
apc := math.Abs(pc)
|
||||
inc.Apcs.Update(apc)
|
||||
|
||||
inc.Pcds.Update(inc.Pcs.Last())
|
||||
inc.Apcds.Update(inc.Apcs.Last())
|
||||
inc.Pcds.Update(inc.Pcs.Last(0))
|
||||
inc.Apcds.Update(inc.Apcs.Last(0))
|
||||
|
||||
tsi := (inc.Pcds.Last() / inc.Apcds.Last()) * 100.
|
||||
tsi := (inc.Pcds.Last(0) / inc.Apcds.Last(0)) * 100.
|
||||
inc.Values.Push(tsi)
|
||||
if inc.Values.Length() > MaxNumOfEWMA {
|
||||
inc.Values = inc.Values[MaxNumOfEWMATruncateSize-1:]
|
||||
|
@ -80,12 +81,12 @@ func (inc *TSI) Length() int {
|
|||
return inc.Values.Length()
|
||||
}
|
||||
|
||||
func (inc *TSI) Last() float64 {
|
||||
return inc.Values.Last()
|
||||
func (inc *TSI) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *TSI) Index(i int) float64 {
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *TSI) PushK(k types.KLine) {
|
||||
|
|
|
@ -32,5 +32,5 @@ func Test_TSI(t *testing.T) {
|
|||
}
|
||||
assert.Equal(t, tsi.Length(), 29)
|
||||
Delta := 1.5e-2
|
||||
assert.InDelta(t, tsi.Last(), 22.89, Delta)
|
||||
assert.InDelta(t, tsi.Last(0), 22.89, Delta)
|
||||
}
|
||||
|
|
|
@ -70,20 +70,20 @@ func (inc *UtBotAlert) Update(highPrice, lowPrice, closePrice float64) {
|
|||
// Update ATR
|
||||
inc.AverageTrueRange.Update(highPrice, lowPrice, closePrice)
|
||||
|
||||
nLoss := inc.AverageTrueRange.Last() * inc.KeyValue
|
||||
nLoss := inc.AverageTrueRange.Last(0) * inc.KeyValue
|
||||
|
||||
// xATRTrailingStop
|
||||
if inc.xATRTrailingStop.Length() == 0 {
|
||||
// For first run
|
||||
inc.xATRTrailingStop.Update(0)
|
||||
|
||||
} else if closePrice > inc.xATRTrailingStop.Index(1) && inc.previousClosePrice > inc.xATRTrailingStop.Index(1) {
|
||||
inc.xATRTrailingStop.Update(math.Max(inc.xATRTrailingStop.Index(1), closePrice-nLoss))
|
||||
} else if closePrice > inc.xATRTrailingStop.Last(1) && inc.previousClosePrice > inc.xATRTrailingStop.Last(1) {
|
||||
inc.xATRTrailingStop.Update(math.Max(inc.xATRTrailingStop.Last(1), closePrice-nLoss))
|
||||
|
||||
} else if closePrice < inc.xATRTrailingStop.Index(1) && inc.previousClosePrice < inc.xATRTrailingStop.Index(1) {
|
||||
inc.xATRTrailingStop.Update(math.Min(inc.xATRTrailingStop.Index(1), closePrice+nLoss))
|
||||
} else if closePrice < inc.xATRTrailingStop.Last(1) && inc.previousClosePrice < inc.xATRTrailingStop.Last(1) {
|
||||
inc.xATRTrailingStop.Update(math.Min(inc.xATRTrailingStop.Last(1), closePrice+nLoss))
|
||||
|
||||
} else if closePrice > inc.xATRTrailingStop.Index(1) {
|
||||
} else if closePrice > inc.xATRTrailingStop.Last(1) {
|
||||
inc.xATRTrailingStop.Update(closePrice - nLoss)
|
||||
|
||||
} else {
|
||||
|
@ -91,19 +91,19 @@ func (inc *UtBotAlert) Update(highPrice, lowPrice, closePrice float64) {
|
|||
}
|
||||
|
||||
// pos
|
||||
if inc.previousClosePrice < inc.xATRTrailingStop.Index(1) && closePrice > inc.xATRTrailingStop.Index(1) {
|
||||
if inc.previousClosePrice < inc.xATRTrailingStop.Last(1) && closePrice > inc.xATRTrailingStop.Last(1) {
|
||||
inc.pos = types.DirectionUp
|
||||
} else if inc.previousClosePrice > inc.xATRTrailingStop.Index(1) && closePrice < inc.xATRTrailingStop.Index(1) {
|
||||
} else if inc.previousClosePrice > inc.xATRTrailingStop.Last(1) && closePrice < inc.xATRTrailingStop.Last(1) {
|
||||
inc.pos = types.DirectionDown
|
||||
} else {
|
||||
inc.pos = inc.previousPos
|
||||
}
|
||||
|
||||
above := closePrice > inc.xATRTrailingStop.Last() && inc.previousClosePrice < inc.xATRTrailingStop.Index(1)
|
||||
below := closePrice < inc.xATRTrailingStop.Last() && inc.previousClosePrice > inc.xATRTrailingStop.Index(1)
|
||||
above := closePrice > inc.xATRTrailingStop.Last(0) && inc.previousClosePrice < inc.xATRTrailingStop.Last(1)
|
||||
below := closePrice < inc.xATRTrailingStop.Last(0) && inc.previousClosePrice > inc.xATRTrailingStop.Last(1)
|
||||
|
||||
buy := closePrice > inc.xATRTrailingStop.Last() && above // buy
|
||||
sell := closePrice < inc.xATRTrailingStop.Last() && below // sell
|
||||
buy := closePrice > inc.xATRTrailingStop.Last(0) && above // buy
|
||||
sell := closePrice < inc.xATRTrailingStop.Last(0) && below // sell
|
||||
|
||||
inc.buyValue.Push(buy)
|
||||
inc.sellValue.Push(sell)
|
||||
|
|
|
@ -71,7 +71,7 @@ func Test_ATR2(t *testing.T) {
|
|||
stream.EmitKLineClosed(k)
|
||||
}
|
||||
|
||||
got := atr.Last()
|
||||
got := atr.Last(0)
|
||||
diff := math.Trunc((got-tt.want)*100) / 100
|
||||
if diff != 0 {
|
||||
t.Errorf("ATR2() = %v, want %v", got, tt.want)
|
||||
|
|
|
@ -30,7 +30,7 @@ func (s *EWMAStream) calculateAndPush(v float64) {
|
|||
}
|
||||
|
||||
func (s *EWMAStream) calculate(v float64) float64 {
|
||||
last := s.slice.Last()
|
||||
last := s.slice.Last(0)
|
||||
m := s.multiplier
|
||||
return (1.0-m)*last + m*v
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ func (s *RSIStream) calculate(_ float64) float64 {
|
|||
var sourceLen = s.source.Length()
|
||||
var limit = min(s.window, sourceLen)
|
||||
for i := 0; i < limit; i++ {
|
||||
value := s.source.Index(i)
|
||||
prev := s.source.Index(i + 1)
|
||||
value := s.source.Last(i)
|
||||
prev := s.source.Last(i + 1)
|
||||
change := value - prev
|
||||
if change >= 0 {
|
||||
gainSum += change
|
||||
|
|
|
@ -72,7 +72,7 @@ func Test_TR_and_RMA(t *testing.T) {
|
|||
stream.EmitKLineClosed(k)
|
||||
}
|
||||
|
||||
got := rma.Last()
|
||||
got := rma.Last(0)
|
||||
diff := math.Trunc((got-tt.want)*100) / 100
|
||||
if diff != 0 {
|
||||
t.Errorf("RMA(TR()) = %v, want %v", got, tt.want)
|
||||
|
|
|
@ -58,18 +58,18 @@ func (inc *VIDYA) Update(value float64) {
|
|||
change := types.Change(&inc.input)
|
||||
CMO := math.Abs(types.Sum(change, inc.Window) / types.Sum(types.Abs(change), inc.Window))
|
||||
alpha := 2. / float64(inc.Window+1)
|
||||
inc.Values.Push(value*alpha*CMO + inc.Values.Last()*(1.-alpha*CMO))
|
||||
inc.Values.Push(value*alpha*CMO + inc.Values.Last(0)*(1.-alpha*CMO))
|
||||
if inc.Values.Length() > MaxNumOfEWMA {
|
||||
inc.Values = inc.Values[MaxNumOfEWMATruncateSize-1:]
|
||||
}
|
||||
}
|
||||
|
||||
func (inc *VIDYA) Last() float64 {
|
||||
return inc.Values.Last()
|
||||
func (inc *VIDYA) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *VIDYA) Index(i int) float64 {
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *VIDYA) Length() int {
|
||||
|
@ -86,12 +86,12 @@ func (inc *VIDYA) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.input.Length() == 0 {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@ import (
|
|||
func Test_VIDYA(t *testing.T) {
|
||||
vidya := &VIDYA{IntervalWindow: types.IntervalWindow{Window: 16}}
|
||||
vidya.Update(1)
|
||||
assert.Equal(t, vidya.Last(), 1.)
|
||||
assert.Equal(t, vidya.Last(0), 1.)
|
||||
vidya.Update(2)
|
||||
newV := 2./17.*2. + 1.*(1.-2./17.)
|
||||
assert.Equal(t, vidya.Last(), newV)
|
||||
assert.Equal(t, vidya.Last(0), newV)
|
||||
vidya.Update(1)
|
||||
assert.Equal(t, vidya.Last(), vidya.Index(1))
|
||||
assert.Equal(t, vidya.Last(0), vidya.Index(1))
|
||||
}
|
||||
|
|
|
@ -26,18 +26,12 @@ type Volatility struct {
|
|||
UpdateCallbacks []func(value float64)
|
||||
}
|
||||
|
||||
func (inc *Volatility) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *Volatility) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *Volatility) Index(i int) float64 {
|
||||
if len(inc.Values)-i <= 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *Volatility) Length() int {
|
||||
|
|
|
@ -56,20 +56,12 @@ func (inc *VWAP) Update(price, volume float64) {
|
|||
inc.Values.Push(vwap)
|
||||
}
|
||||
|
||||
func (inc *VWAP) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *VWAP) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *VWAP) Index(i int) float64 {
|
||||
length := len(inc.Values)
|
||||
if length == 0 || length-i-1 < 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return inc.Values[length-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *VWAP) Length() int {
|
||||
|
@ -91,7 +83,7 @@ func (inc *VWAP) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
inc.PushK(k)
|
||||
}
|
||||
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
inc.EndTime = allKLines[len(allKLines)-1].EndTime.Time()
|
||||
}
|
||||
|
||||
|
@ -112,5 +104,5 @@ func calculateVWAP(klines []types.KLine, priceF KLineValueMapper, window int) fl
|
|||
for _, k := range klines {
|
||||
vwap.Update(priceF(k), k.Volume.Float64())
|
||||
}
|
||||
return vwap.Last()
|
||||
return vwap.Last(0)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
// VWMA = SMA(pv, window) / SMA(volumes, window)
|
||||
//
|
||||
// Volume Weighted Moving Average
|
||||
//- https://www.motivewave.com/studies/volume_weighted_moving_average.htm
|
||||
// - https://www.motivewave.com/studies/volume_weighted_moving_average.htm
|
||||
//
|
||||
// The Volume Weighted Moving Average (VWMA) is a technical analysis indicator that is used to smooth price data and reduce the lag
|
||||
// associated with traditional moving averages. It is calculated by taking the weighted moving average of the input data, with the
|
||||
|
@ -36,19 +36,12 @@ type VWMA struct {
|
|||
updateCallbacks []func(value float64)
|
||||
}
|
||||
|
||||
func (inc *VWMA) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *VWMA) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *VWMA) Index(i int) float64 {
|
||||
length := len(inc.Values)
|
||||
if length == 0 || length-i-1 < 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values[length-i-1]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *VWMA) Length() int {
|
||||
|
@ -70,8 +63,8 @@ func (inc *VWMA) Update(price, volume float64) {
|
|||
inc.PriceVolumeSMA.Update(price * volume)
|
||||
inc.VolumeSMA.Update(volume)
|
||||
|
||||
pv := inc.PriceVolumeSMA.Last()
|
||||
v := inc.VolumeSMA.Last()
|
||||
pv := inc.PriceVolumeSMA.Last(0)
|
||||
v := inc.VolumeSMA.Last(0)
|
||||
vwma := pv / v
|
||||
inc.Values.Push(vwma)
|
||||
}
|
||||
|
@ -104,7 +97,7 @@ func (inc *VWMA) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
}
|
||||
|
||||
inc.EndTime = last.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Values.Last())
|
||||
inc.EmitUpdate(inc.Values.Last(0))
|
||||
}
|
||||
|
||||
func (inc *VWMA) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
// Refer: https://tradingview.com/script/aDymGrFx-Drift-Study-Inspired-by-Monte-Carlo-Simulations-with-BM-KL/
|
||||
// Brownian Motion's drift factor
|
||||
// could be used in Monte Carlo Simulations
|
||||
//
|
||||
//go:generate callbackgen -type WeightedDrift
|
||||
type WeightedDrift struct {
|
||||
types.SeriesBase
|
||||
|
@ -54,7 +55,7 @@ func (inc *WeightedDrift) Update(value float64, weight float64) {
|
|||
}
|
||||
if inc.chng.Length() >= inc.Window {
|
||||
stdev := types.Stdev(inc.chng, inc.Window)
|
||||
drift := inc.MA.Last() - stdev*stdev*0.5
|
||||
drift := inc.MA.Last(0) - stdev*stdev*0.5
|
||||
inc.Values.Push(drift)
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +78,7 @@ func (inc *WeightedDrift) ZeroPoint() float64 {
|
|||
} else {
|
||||
return N2
|
||||
}*/
|
||||
return inc.LastValue * math.Exp(window*(0.5*stdev*stdev)+chng-inc.MA.Last()*window)
|
||||
return inc.LastValue * math.Exp(window*(0.5*stdev*stdev)+chng-inc.MA.Last(0)*window)
|
||||
}
|
||||
|
||||
func (inc *WeightedDrift) Clone() (out *WeightedDrift) {
|
||||
|
@ -100,17 +101,11 @@ func (inc *WeightedDrift) TestUpdate(value float64, weight float64) *WeightedDri
|
|||
}
|
||||
|
||||
func (inc *WeightedDrift) Index(i int) float64 {
|
||||
if inc.Values == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *WeightedDrift) Last() float64 {
|
||||
if inc.Values.Length() == 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
func (inc *WeightedDrift) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *WeightedDrift) Length() int {
|
||||
|
@ -130,12 +125,12 @@ func (inc *WeightedDrift) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.chng == nil {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,25 +33,17 @@ func (inc *WWMA) Update(value float64) {
|
|||
inc.Values = inc.Values[MaxNumOfWWMATruncateSize-1:]
|
||||
}
|
||||
|
||||
last := inc.Last()
|
||||
last := inc.Last(0)
|
||||
wma := last + (value-last)/float64(inc.Window)
|
||||
inc.Values.Push(wma)
|
||||
}
|
||||
|
||||
func (inc *WWMA) Last() float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return inc.Values[len(inc.Values)-1]
|
||||
func (inc *WWMA) Last(i int) float64 {
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *WWMA) Index(i int) float64 {
|
||||
if i >= len(inc.Values) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return inc.Values[len(inc.Values)-1-i]
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *WWMA) Length() int {
|
||||
|
@ -76,7 +68,7 @@ func (inc *WWMA) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if doable {
|
||||
inc.PushK(k)
|
||||
inc.LastOpenTime = k.StartTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,17 +27,14 @@ type ZLEMA struct {
|
|||
}
|
||||
|
||||
func (inc *ZLEMA) Index(i int) float64 {
|
||||
if inc.zlema == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.zlema.Index(i)
|
||||
return inc.Last(i)
|
||||
}
|
||||
|
||||
func (inc *ZLEMA) Last() float64 {
|
||||
func (inc *ZLEMA) Last(i int) float64 {
|
||||
if inc.zlema == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.zlema.Last()
|
||||
return inc.zlema.Last(i)
|
||||
}
|
||||
|
||||
func (inc *ZLEMA) Length() int {
|
||||
|
@ -74,12 +71,12 @@ func (inc *ZLEMA) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
if inc.zlema == nil {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ func Test_ZLEMA(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
zlema := ZLEMA{IntervalWindow: types.IntervalWindow{Window: 16}}
|
||||
zlema.CalculateAndUpdate(tt.kLines)
|
||||
last := zlema.Last()
|
||||
last := zlema.Last(0)
|
||||
assert.InDelta(t, tt.want, last, Delta)
|
||||
assert.InDelta(t, tt.next, zlema.Index(1), Delta)
|
||||
assert.Equal(t, tt.all, zlema.Length())
|
||||
|
|
|
@ -59,9 +59,9 @@ func (d *DynamicExposureBollBand) initialize(symbol string, session *bbgo.Exchan
|
|||
|
||||
// getMaxExposure returns the max exposure
|
||||
func (d *DynamicExposureBollBand) getMaxExposure(price float64, trend types.Direction) (fixedpoint.Value, error) {
|
||||
downBand := d.dynamicExposureBollBand.DownBand.Last()
|
||||
upBand := d.dynamicExposureBollBand.UpBand.Last()
|
||||
sma := d.dynamicExposureBollBand.SMA.Last()
|
||||
downBand := d.dynamicExposureBollBand.DownBand.Last(0)
|
||||
upBand := d.dynamicExposureBollBand.UpBand.Last(0)
|
||||
sma := d.dynamicExposureBollBand.SMA.Last(0)
|
||||
log.Infof("dynamicExposureBollBand bollinger band: up %f sma %f down %f", upBand, sma, downBand)
|
||||
|
||||
bandPercentage := 0.0
|
||||
|
|
|
@ -114,7 +114,7 @@ func (ds *DynamicAmpSpread) update(kline types.KLine) {
|
|||
|
||||
func (ds *DynamicAmpSpread) getAskSpread() (askSpread float64, err error) {
|
||||
if ds.AskSpreadScale != nil && ds.dynamicAskSpread.Length() >= ds.Window {
|
||||
askSpread, err = ds.AskSpreadScale.Scale(ds.dynamicAskSpread.Last())
|
||||
askSpread, err = ds.AskSpreadScale.Scale(ds.dynamicAskSpread.Last(0))
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not calculate dynamicAskSpread")
|
||||
return 0, err
|
||||
|
@ -128,7 +128,7 @@ func (ds *DynamicAmpSpread) getAskSpread() (askSpread float64, err error) {
|
|||
|
||||
func (ds *DynamicAmpSpread) getBidSpread() (bidSpread float64, err error) {
|
||||
if ds.BidSpreadScale != nil && ds.dynamicBidSpread.Length() >= ds.Window {
|
||||
bidSpread, err = ds.BidSpreadScale.Scale(ds.dynamicBidSpread.Last())
|
||||
bidSpread, err = ds.BidSpreadScale.Scale(ds.dynamicBidSpread.Last(0))
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not calculate dynamicBidSpread")
|
||||
return 0, err
|
||||
|
@ -224,12 +224,12 @@ func (ds *DynamicSpreadBollWidthRatio) getWeightedBBWidthRatio(positiveSigmoid b
|
|||
// - To ask spread, the higher neutral band get greater ratio
|
||||
// - To bid spread, the lower neutral band get greater ratio
|
||||
|
||||
defaultMid := ds.defaultBoll.SMA.Last()
|
||||
defaultUpper := ds.defaultBoll.UpBand.Last()
|
||||
defaultLower := ds.defaultBoll.DownBand.Last()
|
||||
defaultMid := ds.defaultBoll.SMA.Last(0)
|
||||
defaultUpper := ds.defaultBoll.UpBand.Last(0)
|
||||
defaultLower := ds.defaultBoll.DownBand.Last(0)
|
||||
defaultWidth := defaultUpper - defaultLower
|
||||
neutralUpper := ds.neutralBoll.UpBand.Last()
|
||||
neutralLower := ds.neutralBoll.DownBand.Last()
|
||||
neutralUpper := ds.neutralBoll.UpBand.Last(0)
|
||||
neutralLower := ds.neutralBoll.DownBand.Last(0)
|
||||
factor := defaultWidth / ds.Sensitivity
|
||||
var weightedUpper, weightedLower, weightedDivUpper, weightedDivLower float64
|
||||
if positiveSigmoid {
|
||||
|
|
|
@ -92,7 +92,7 @@ func (s *PerTrade) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
|||
// min-max scaling
|
||||
ofsMax := orderFlowSize.Tail(100).Max()
|
||||
ofsMin := orderFlowSize.Tail(100).Min()
|
||||
ofsMinMax := (orderFlowSize.Last() - ofsMin) / (ofsMax - ofsMin)
|
||||
ofsMinMax := (orderFlowSize.Last(0) - ofsMin) / (ofsMax - ofsMin)
|
||||
// preserves temporal dependency via polar encoded angles
|
||||
orderFlowSizeMinMax.Push(ofsMinMax)
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ func (s *PerTrade) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
|||
// min-max scaling
|
||||
ofnMax := orderFlowNumber.Tail(100).Max()
|
||||
ofnMin := orderFlowNumber.Tail(100).Min()
|
||||
ofnMinMax := (orderFlowNumber.Last() - ofnMin) / (ofnMax - ofnMin)
|
||||
ofnMinMax := (orderFlowNumber.Last(0) - ofnMin) / (ofnMax - ofnMin)
|
||||
// preserves temporal dependency via polar encoded angles
|
||||
orderFlowNumberMinMax.Push(ofnMinMax)
|
||||
}
|
||||
|
@ -167,9 +167,9 @@ func (s *PerTrade) placeTrade(ctx context.Context, side types.SideType, quantity
|
|||
|
||||
func outlier(fs floats.Slice, multiplier float64) int {
|
||||
stddev := stat.StdDev(fs, nil)
|
||||
if fs.Last() > fs.Mean()+multiplier*stddev {
|
||||
if fs.Last(0) > fs.Mean()+multiplier*stddev {
|
||||
return 1
|
||||
} else if fs.Last() < fs.Mean()-multiplier*stddev {
|
||||
} else if fs.Last(0) < fs.Mean()-multiplier*stddev {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
|
|
|
@ -135,7 +135,7 @@ func (s *Strategy) generateGridBuyOrders(session *bbgo.ExchangeSession) ([]types
|
|||
ema99 := s.StandardIndicatorSet.EWMA(types.IntervalWindow{Interval: s.Interval, Window: 99})
|
||||
ema25 := s.StandardIndicatorSet.EWMA(types.IntervalWindow{Interval: s.Interval, Window: 25})
|
||||
ema7 := s.StandardIndicatorSet.EWMA(types.IntervalWindow{Interval: s.Interval, Window: 7})
|
||||
if ema7.Last() > ema25.Last()*1.001 && ema25.Last() > ema99.Last()*1.0005 {
|
||||
if ema7.Last(0) > ema25.Last(0)*1.001 && ema25.Last(0) > ema99.Last(0)*1.0005 {
|
||||
log.Infof("all ema lines trend up, skip buy")
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ func (s *Strategy) generateGridSellOrders(session *bbgo.ExchangeSession) ([]type
|
|||
ema99 := s.StandardIndicatorSet.EWMA(types.IntervalWindow{Interval: s.Interval, Window: 99})
|
||||
ema25 := s.StandardIndicatorSet.EWMA(types.IntervalWindow{Interval: s.Interval, Window: 25})
|
||||
ema7 := s.StandardIndicatorSet.EWMA(types.IntervalWindow{Interval: s.Interval, Window: 7})
|
||||
if ema7.Last() < ema25.Last()*(1-0.004) && ema25.Last() < ema99.Last()*(1-0.0005) {
|
||||
if ema7.Last(0) < ema25.Last(0)*(1-0.004) && ema25.Last(0) < ema99.Last(0)*(1-0.0005) {
|
||||
log.Infof("all ema lines trend down, skip sell")
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ func (ds *DynamicSpreadAmpSettings) update(kline types.KLine) {
|
|||
|
||||
func (ds *DynamicSpreadAmpSettings) getAskSpread() (askSpread float64, err error) {
|
||||
if ds.AskSpreadScale != nil && ds.dynamicAskSpread.Length() >= ds.Window {
|
||||
askSpread, err = ds.AskSpreadScale.Scale(ds.dynamicAskSpread.Last())
|
||||
askSpread, err = ds.AskSpreadScale.Scale(ds.dynamicAskSpread.Last(0))
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not calculate dynamicAskSpread")
|
||||
return 0, err
|
||||
|
@ -140,7 +140,7 @@ func (ds *DynamicSpreadAmpSettings) getAskSpread() (askSpread float64, err error
|
|||
|
||||
func (ds *DynamicSpreadAmpSettings) getBidSpread() (bidSpread float64, err error) {
|
||||
if ds.BidSpreadScale != nil && ds.dynamicBidSpread.Length() >= ds.Window {
|
||||
bidSpread, err = ds.BidSpreadScale.Scale(ds.dynamicBidSpread.Last())
|
||||
bidSpread, err = ds.BidSpreadScale.Scale(ds.dynamicBidSpread.Last(0))
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not calculate dynamicBidSpread")
|
||||
return 0, err
|
||||
|
@ -224,12 +224,12 @@ func (ds *DynamicSpreadBollWidthRatioSettings) getWeightedBBWidthRatio(positiveS
|
|||
// - To ask spread, the higher neutral band get greater ratio
|
||||
// - To bid spread, the lower neutral band get greater ratio
|
||||
|
||||
defaultMid := ds.defaultBoll.SMA.Last()
|
||||
defaultUpper := ds.defaultBoll.UpBand.Last()
|
||||
defaultLower := ds.defaultBoll.DownBand.Last()
|
||||
defaultMid := ds.defaultBoll.SMA.Last(0)
|
||||
defaultUpper := ds.defaultBoll.UpBand.Last(0)
|
||||
defaultLower := ds.defaultBoll.DownBand.Last(0)
|
||||
defaultWidth := defaultUpper - defaultLower
|
||||
neutralUpper := ds.neutralBoll.UpBand.Last()
|
||||
neutralLower := ds.neutralBoll.DownBand.Last()
|
||||
neutralUpper := ds.neutralBoll.UpBand.Last(0)
|
||||
neutralLower := ds.neutralBoll.DownBand.Last(0)
|
||||
factor := defaultWidth / ds.Sensitivity
|
||||
var weightedUpper, weightedLower, weightedDivUpper, weightedDivLower float64
|
||||
if positiveSigmoid {
|
||||
|
|
|
@ -278,9 +278,9 @@ func (s *Strategy) placeOrders(ctx context.Context, midPrice fixedpoint.Value, k
|
|||
baseBalance, hasBaseBalance := balances[s.Market.BaseCurrency]
|
||||
quoteBalance, hasQuoteBalance := balances[s.Market.QuoteCurrency]
|
||||
|
||||
downBand := s.defaultBoll.DownBand.Last()
|
||||
upBand := s.defaultBoll.UpBand.Last()
|
||||
sma := s.defaultBoll.SMA.Last()
|
||||
downBand := s.defaultBoll.DownBand.Last(0)
|
||||
upBand := s.defaultBoll.UpBand.Last(0)
|
||||
sma := s.defaultBoll.SMA.Last(0)
|
||||
log.Infof("%s bollinger band: up %f sma %f down %f", s.Symbol, upBand, sma, downBand)
|
||||
|
||||
bandPercentage := calculateBandPercentage(upBand, downBand, sma, midPrice.Float64())
|
||||
|
@ -351,7 +351,7 @@ func (s *Strategy) placeOrders(ctx context.Context, midPrice fixedpoint.Value, k
|
|||
// WHEN: price breaks the upper band (price > window 2) == strongUpTrend
|
||||
// THEN: we apply strongUpTrend skew
|
||||
if s.TradeInBand {
|
||||
if !inBetween(midPrice.Float64(), s.neutralBoll.DownBand.Last(), s.neutralBoll.UpBand.Last()) {
|
||||
if !inBetween(midPrice.Float64(), s.neutralBoll.DownBand.Last(0), s.neutralBoll.UpBand.Last(0)) {
|
||||
log.Infof("tradeInBand is set, skip placing orders when the price is outside of the band")
|
||||
return
|
||||
}
|
||||
|
@ -410,7 +410,7 @@ func (s *Strategy) placeOrders(ctx context.Context, midPrice fixedpoint.Value, k
|
|||
canSell = false
|
||||
}
|
||||
|
||||
if s.BuyBelowNeutralSMA && midPrice.Float64() > s.neutralBoll.SMA.Last() {
|
||||
if s.BuyBelowNeutralSMA && midPrice.Float64() > s.neutralBoll.SMA.Last(0) {
|
||||
canBuy = false
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ const (
|
|||
)
|
||||
|
||||
func detectPriceTrend(inc *indicator.BOLL, price float64) PriceTrend {
|
||||
if inBetween(price, inc.DownBand.Last(), inc.UpBand.Last()) {
|
||||
if inBetween(price, inc.DownBand.Last(0), inc.UpBand.Last(0)) {
|
||||
return NeutralTrend
|
||||
}
|
||||
|
||||
|
|
|
@ -17,19 +17,19 @@ func (s *DriftMA) Update(value, weight float64) {
|
|||
if s.ma1.Length() == 0 {
|
||||
return
|
||||
}
|
||||
s.drift.Update(s.ma1.Last(), weight)
|
||||
s.drift.Update(s.ma1.Last(0), weight)
|
||||
if s.drift.Length() == 0 {
|
||||
return
|
||||
}
|
||||
s.ma2.Update(s.drift.Last())
|
||||
s.ma2.Update(s.drift.Last(0))
|
||||
}
|
||||
|
||||
func (s *DriftMA) Last() float64 {
|
||||
return s.ma2.Last()
|
||||
func (s *DriftMA) Last(int) float64 {
|
||||
return s.ma2.Last(0)
|
||||
}
|
||||
|
||||
func (s *DriftMA) Index(i int) float64 {
|
||||
return s.ma2.Index(i)
|
||||
return s.ma2.Last(i)
|
||||
}
|
||||
|
||||
func (s *DriftMA) Length() int {
|
||||
|
|
|
@ -9,7 +9,7 @@ func (s *Strategy) CheckStopLoss() bool {
|
|||
}
|
||||
}
|
||||
if s.UseAtr {
|
||||
atr := s.atr.Last()
|
||||
atr := s.atr.Last(0)
|
||||
if s.sellPrice > 0 && s.sellPrice+atr <= s.highestPrice ||
|
||||
s.buyPrice > 0 && s.buyPrice-atr >= s.lowestPrice {
|
||||
return true
|
||||
|
|
|
@ -261,8 +261,8 @@ func (s *Strategy) initIndicators(store *bbgo.SerialMarketDataStore) error {
|
|||
high := kline.High.Float64()
|
||||
low := kline.Low.Float64()
|
||||
s.ma.Update(source)
|
||||
s.stdevHigh.Update(high - s.ma.Last())
|
||||
s.stdevLow.Update(s.ma.Last() - low)
|
||||
s.stdevHigh.Update(high - s.ma.Last(0))
|
||||
s.stdevLow.Update(s.ma.Last(0) - low)
|
||||
s.drift.Update(source, kline.Volume.Abs().Float64())
|
||||
s.trendLine.Update(source)
|
||||
s.atr.PushK(kline)
|
||||
|
@ -485,7 +485,7 @@ func (s *Strategy) klineHandlerMin(ctx context.Context, kline types.KLine, count
|
|||
return
|
||||
}
|
||||
// for doing the trailing stoploss during backtesting
|
||||
atr := s.atr.Last()
|
||||
atr := s.atr.Last(0)
|
||||
price := s.getLastPrice()
|
||||
pricef := price.Float64()
|
||||
|
||||
|
@ -538,7 +538,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine, counter
|
|||
|
||||
s.drift.Update(sourcef, kline.Volume.Abs().Float64())
|
||||
s.atr.PushK(kline)
|
||||
atr := s.atr.Last()
|
||||
atr := s.atr.Last(0)
|
||||
|
||||
price := kline.Close // s.getLastPrice()
|
||||
pricef := price.Float64()
|
||||
|
@ -563,7 +563,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine, counter
|
|||
return
|
||||
}
|
||||
|
||||
log.Infof("highdiff: %3.2f open: %8v, close: %8v, high: %8v, low: %8v, time: %v %v", s.stdevHigh.Last(), kline.Open, kline.Close, kline.High, kline.Low, kline.StartTime, kline.EndTime)
|
||||
log.Infof("highdiff: %3.2f open: %8v, close: %8v, high: %8v, low: %8v, time: %v %v", s.stdevHigh.Last(0), kline.Open, kline.Close, kline.High, kline.Low, kline.StartTime, kline.EndTime)
|
||||
|
||||
s.positionLock.Lock()
|
||||
if s.lowestPrice > 0 && lowf < s.lowestPrice {
|
||||
|
@ -596,7 +596,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine, counter
|
|||
shortCondition := drift[1] >= 0 && drift[0] <= 0 || (drift[1] >= drift[0] && drift[1] <= 0) || ddrift[1] >= 0 && ddrift[0] <= 0 || (ddrift[1] >= ddrift[0] && ddrift[1] <= 0)
|
||||
longCondition := drift[1] <= 0 && drift[0] >= 0 || (drift[1] <= drift[0] && drift[1] >= 0) || ddrift[1] <= 0 && ddrift[0] >= 0 || (ddrift[1] <= ddrift[0] && ddrift[1] >= 0)
|
||||
if shortCondition && longCondition {
|
||||
if s.priceLines.Index(1) > s.priceLines.Last() {
|
||||
if s.priceLines.Index(1) > s.priceLines.Last(0) {
|
||||
longCondition = false
|
||||
} else {
|
||||
shortCondition = false
|
||||
|
@ -625,7 +625,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine, counter
|
|||
}
|
||||
|
||||
if longCondition {
|
||||
source = source.Sub(fixedpoint.NewFromFloat(s.stdevLow.Last() * s.HighLowVarianceMultiplier))
|
||||
source = source.Sub(fixedpoint.NewFromFloat(s.stdevLow.Last(0) * s.HighLowVarianceMultiplier))
|
||||
if source.Compare(price) > 0 {
|
||||
source = price
|
||||
}
|
||||
|
@ -654,7 +654,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine, counter
|
|||
return
|
||||
}
|
||||
|
||||
log.Infof("source in long %v %v %f", source, price, s.stdevLow.Last())
|
||||
log.Infof("source in long %v %v %f", source, price, s.stdevLow.Last(0))
|
||||
|
||||
o, err := s.SubmitOrder(ctx, *submitOrder)
|
||||
if err != nil {
|
||||
|
@ -675,12 +675,12 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine, counter
|
|||
return
|
||||
}
|
||||
if shortCondition {
|
||||
source = source.Add(fixedpoint.NewFromFloat(s.stdevHigh.Last() * s.HighLowVarianceMultiplier))
|
||||
source = source.Add(fixedpoint.NewFromFloat(s.stdevHigh.Last(0) * s.HighLowVarianceMultiplier))
|
||||
if source.Compare(price) < 0 {
|
||||
source = price
|
||||
}
|
||||
|
||||
log.Infof("source in short: %v %v %f", source, price, s.stdevLow.Last())
|
||||
log.Infof("source in short: %v %v %f", source, price, s.stdevLow.Last(0))
|
||||
|
||||
opt := s.OpenPositionOptions
|
||||
opt.Short = true
|
||||
|
|
|
@ -11,8 +11,8 @@ func (s *ElliottWave) Index(i int) float64 {
|
|||
return s.maQuick.Index(i)/s.maSlow.Index(i) - 1.0
|
||||
}
|
||||
|
||||
func (s *ElliottWave) Last() float64 {
|
||||
return s.maQuick.Last()/s.maSlow.Last() - 1.0
|
||||
func (s *ElliottWave) Last(int) float64 {
|
||||
return s.maQuick.Last(0)/s.maSlow.Last(0) - 1.0
|
||||
}
|
||||
|
||||
func (s *ElliottWave) Length() int {
|
||||
|
|
|
@ -199,12 +199,12 @@ func (s *Strategy) smartCancel(ctx context.Context, pricef float64) int {
|
|||
if s.counter-s.orderPendingCounter[order.OrderID] >= s.PendingMinInterval {
|
||||
toCancel = true
|
||||
} else if order.Side == types.SideTypeBuy {
|
||||
if order.Price.Float64()+s.atr.Last()*2 <= pricef {
|
||||
if order.Price.Float64()+s.atr.Last(0)*2 <= pricef {
|
||||
toCancel = true
|
||||
}
|
||||
} else if order.Side == types.SideTypeSell {
|
||||
// 75% of the probability
|
||||
if order.Price.Float64()-s.atr.Last()*2 >= pricef {
|
||||
if order.Price.Float64()-s.atr.Last(0)*2 >= pricef {
|
||||
toCancel = true
|
||||
}
|
||||
} else {
|
||||
|
@ -425,7 +425,7 @@ func (s *Strategy) klineHandlerMin(ctx context.Context, kline types.KLine) {
|
|||
stoploss := s.Stoploss.Float64()
|
||||
price := s.getLastPrice()
|
||||
pricef := price.Float64()
|
||||
atr := s.atr.Last()
|
||||
atr := s.atr.Last(0)
|
||||
|
||||
numPending := s.smartCancel(ctx, pricef)
|
||||
if numPending > 0 {
|
||||
|
@ -476,7 +476,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
|
||||
s.smartCancel(ctx, pricef)
|
||||
|
||||
atr := s.atr.Last()
|
||||
atr := s.atr.Last(0)
|
||||
ewo := types.Array(s.ewo, 4)
|
||||
if len(ewo) < 4 {
|
||||
return
|
||||
|
|
|
@ -93,7 +93,7 @@ func (s *Strategy) clear(ctx context.Context, orderExecutor bbgo.OrderExecutor)
|
|||
|
||||
func (s *Strategy) place(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession, indicator types.Float64Indicator, closePrice fixedpoint.Value) {
|
||||
closePriceF := closePrice.Float64()
|
||||
movingAveragePriceF := indicator.Last()
|
||||
movingAveragePriceF := indicator.Last(0)
|
||||
|
||||
// skip it if it's near zero because it's not loaded yet
|
||||
if movingAveragePriceF < 0.0001 {
|
||||
|
|
|
@ -27,11 +27,11 @@ func NewHeikinAshi(size int) *HeikinAshi {
|
|||
|
||||
func (s *HeikinAshi) Print() string {
|
||||
return fmt.Sprintf("Heikin c: %.3f, o: %.3f, h: %.3f, l: %.3f, v: %.3f",
|
||||
s.Close.Last(),
|
||||
s.Open.Last(),
|
||||
s.High.Last(),
|
||||
s.Low.Last(),
|
||||
s.Volume.Last())
|
||||
s.Close.Last(0),
|
||||
s.Open.Last(0),
|
||||
s.High.Last(0),
|
||||
s.Low.Last(0),
|
||||
s.Volume.Last(0))
|
||||
}
|
||||
|
||||
func (inc *HeikinAshi) Update(kline types.KLine) {
|
||||
|
@ -40,7 +40,7 @@ func (inc *HeikinAshi) Update(kline types.KLine) {
|
|||
high := kline.High.Float64()
|
||||
low := kline.Low.Float64()
|
||||
newClose := (open + high + low + cloze) / 4.
|
||||
newOpen := (inc.Open.Last() + inc.Close.Last()) / 2.
|
||||
newOpen := (inc.Open.Last(0) + inc.Close.Last(0)) / 2.
|
||||
inc.Close.Update(newClose)
|
||||
inc.Open.Update(newOpen)
|
||||
inc.High.Update(math.Max(math.Max(high, newOpen), newClose))
|
||||
|
|
|
@ -139,7 +139,7 @@ func NewCCISTOCH(i types.Interval, filterHigh, filterLow float64) *CCISTOCH {
|
|||
|
||||
func (inc *CCISTOCH) Update(cloze float64) {
|
||||
inc.cci.Update(cloze)
|
||||
inc.stoch.Update(inc.cci.Last(), inc.cci.Last(), inc.cci.Last())
|
||||
inc.stoch.Update(inc.cci.Last(0), inc.cci.Last(0), inc.cci.Last(0))
|
||||
inc.ma.Update(inc.stoch.LastD())
|
||||
}
|
||||
|
||||
|
@ -180,19 +180,19 @@ type VWEMA struct {
|
|||
V types.UpdatableSeries
|
||||
}
|
||||
|
||||
func (inc *VWEMA) Last() float64 {
|
||||
return inc.PV.Last() / inc.V.Last()
|
||||
func (inc *VWEMA) Last(int) float64 {
|
||||
return inc.PV.Last(0) / inc.V.Last(0)
|
||||
}
|
||||
|
||||
func (inc *VWEMA) Index(i int) float64 {
|
||||
if i >= inc.PV.Length() {
|
||||
return 0
|
||||
}
|
||||
vi := inc.V.Index(i)
|
||||
vi := inc.V.Last(i)
|
||||
if vi == 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.PV.Index(i) / vi
|
||||
return inc.PV.Last(i) / vi
|
||||
}
|
||||
|
||||
func (inc *VWEMA) Length() int {
|
||||
|
@ -262,11 +262,11 @@ func (s *Strategy) SetupIndicators(store *bbgo.MarketDataStore) {
|
|||
if s.heikinAshi.Close.Length() == 0 {
|
||||
for _, kline := range window {
|
||||
s.heikinAshi.Update(kline)
|
||||
s.ccis.Update(getSource(window).Last())
|
||||
s.ccis.Update(getSource(window).Last(0))
|
||||
}
|
||||
} else {
|
||||
s.heikinAshi.Update(window[len(window)-1])
|
||||
s.ccis.Update(getSource(window).Last())
|
||||
s.ccis.Update(getSource(window).Last(0))
|
||||
}
|
||||
})
|
||||
if s.UseEma {
|
||||
|
@ -283,7 +283,7 @@ func (s *Strategy) SetupIndicators(store *bbgo.MarketDataStore) {
|
|||
ema34.Update(cloze)
|
||||
}
|
||||
} else {
|
||||
cloze := getSource(window).Last()
|
||||
cloze := getSource(window).Last(0)
|
||||
ema5.Update(cloze)
|
||||
ema34.Update(cloze)
|
||||
}
|
||||
|
@ -306,7 +306,7 @@ func (s *Strategy) SetupIndicators(store *bbgo.MarketDataStore) {
|
|||
sma34.Update(cloze)
|
||||
}
|
||||
} else {
|
||||
cloze := getSource(window).Last()
|
||||
cloze := getSource(window).Last(0)
|
||||
sma5.Update(cloze)
|
||||
sma34.Update(cloze)
|
||||
}
|
||||
|
@ -330,14 +330,14 @@ func (s *Strategy) SetupIndicators(store *bbgo.MarketDataStore) {
|
|||
vols := getVol(window)
|
||||
if evwma5.PV.Length() == 0 {
|
||||
for i := clozes.Length() - 1; i >= 0; i-- {
|
||||
price := clozes.Index(i)
|
||||
vol := vols.Index(i)
|
||||
price := clozes.Last(i)
|
||||
vol := vols.Last(i)
|
||||
evwma5.UpdateVal(price, vol)
|
||||
evwma34.UpdateVal(price, vol)
|
||||
}
|
||||
} else {
|
||||
price := clozes.Last()
|
||||
vol := vols.Last()
|
||||
price := clozes.Last(0)
|
||||
vol := vols.Last(0)
|
||||
evwma5.UpdateVal(price, vol)
|
||||
evwma34.UpdateVal(price, vol)
|
||||
}
|
||||
|
@ -363,7 +363,7 @@ func (s *Strategy) SetupIndicators(store *bbgo.MarketDataStore) {
|
|||
sig.Update(ewoValue)
|
||||
}
|
||||
} else {
|
||||
sig.Update(s.ewo.Last())
|
||||
sig.Update(s.ewo.Last(0))
|
||||
}
|
||||
})
|
||||
s.ewoSignal = sig
|
||||
|
@ -381,7 +381,7 @@ func (s *Strategy) SetupIndicators(store *bbgo.MarketDataStore) {
|
|||
sig.Update(ewoValue)
|
||||
}
|
||||
} else {
|
||||
sig.Update(s.ewo.Last())
|
||||
sig.Update(s.ewo.Last(0))
|
||||
}
|
||||
})
|
||||
s.ewoSignal = sig
|
||||
|
@ -398,13 +398,13 @@ func (s *Strategy) SetupIndicators(store *bbgo.MarketDataStore) {
|
|||
// lazy init
|
||||
ewoVals := s.ewo.Reverse()
|
||||
for i, ewoValue := range ewoVals {
|
||||
vol := window.Volume().Index(i)
|
||||
vol := window.Volume().Last(i)
|
||||
sig.PV.Update(ewoValue * vol)
|
||||
sig.V.Update(vol)
|
||||
}
|
||||
} else {
|
||||
vol := window.Volume().Last()
|
||||
sig.PV.Update(s.ewo.Last() * vol)
|
||||
vol := window.Volume().Last(0)
|
||||
sig.PV.Update(s.ewo.Last(0) * vol)
|
||||
sig.V.Update(vol)
|
||||
}
|
||||
})
|
||||
|
@ -663,11 +663,13 @@ func (s *Strategy) GetLastPrice() fixedpoint.Value {
|
|||
// - TP by (lastprice < peak price - atr) || (lastprice > bottom price + atr)
|
||||
// - SL by s.StopLoss (Abs(price_diff / price) > s.StopLoss)
|
||||
// - entry condition on ewo(Elliott wave oscillator) Crosses ewoSignal(ma on ewo, signalWindow)
|
||||
// * buy signal on (crossover on previous K bar and no crossunder on latest K bar)
|
||||
// * sell signal on (crossunder on previous K bar and no crossunder on latest K bar)
|
||||
// - buy signal on (crossover on previous K bar and no crossunder on latest K bar)
|
||||
// - sell signal on (crossunder on previous K bar and no crossunder on latest K bar)
|
||||
//
|
||||
// - and filtered by the following rules:
|
||||
// * buy: buy signal ON, kline Close > Open, Close > ma5, Close > ma34, CCI Stochastic Buy signal
|
||||
// * sell: sell signal ON, kline Close < Open, Close < ma5, Close < ma34, CCI Stochastic Sell signal
|
||||
// - buy: buy signal ON, kline Close > Open, Close > ma5, Close > ma34, CCI Stochastic Buy signal
|
||||
// - sell: sell signal ON, kline Close < Open, Close < ma5, Close < ma34, CCI Stochastic Sell signal
|
||||
//
|
||||
// - or entry when ma34 +- atr * 3 gets touched
|
||||
// - entry price: latestPrice +- atr / 2 (short,long), close at market price
|
||||
// Cancel non-fully filled orders on new signal (either in same direction or not)
|
||||
|
@ -784,8 +786,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
s.SetupIndicators(store)
|
||||
|
||||
// local peak of ewo
|
||||
shortSig := s.ewo.Last() < s.ewo.Index(1) && s.ewo.Index(1) > s.ewo.Index(2)
|
||||
longSig := s.ewo.Last() > s.ewo.Index(1) && s.ewo.Index(1) < s.ewo.Index(2)
|
||||
shortSig := s.ewo.Last(0) < s.ewo.Last(1) && s.ewo.Last(1) > s.ewo.Last(2)
|
||||
longSig := s.ewo.Last(0) > s.ewo.Last(1) && s.ewo.Last(1) < s.ewo.Last(2)
|
||||
|
||||
sellOrderTPSL := func(price fixedpoint.Value) {
|
||||
lastPrice := s.GetLastPrice()
|
||||
|
@ -798,8 +800,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
}
|
||||
balances := session.GetAccount().Balances()
|
||||
quoteBalance := balances[s.Market.QuoteCurrency].Available
|
||||
atr := fixedpoint.NewFromFloat(s.atr.Last())
|
||||
atrx2 := fixedpoint.NewFromFloat(s.atr.Last() * 2)
|
||||
atr := fixedpoint.NewFromFloat(s.atr.Last(0))
|
||||
atrx2 := fixedpoint.NewFromFloat(s.atr.Last(0) * 2)
|
||||
buyall := false
|
||||
if s.bottomPrice.IsZero() || s.bottomPrice.Compare(price) > 0 {
|
||||
s.bottomPrice = price
|
||||
|
@ -809,7 +811,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
spBack := s.sellPrice
|
||||
reason := -1
|
||||
if quoteBalance.Div(lastPrice).Compare(s.Market.MinQuantity) >= 0 && quoteBalance.Compare(s.Market.MinNotional) >= 0 {
|
||||
base := fixedpoint.NewFromFloat(s.ma34.Last())
|
||||
base := fixedpoint.NewFromFloat(s.ma34.Last(0))
|
||||
// TP
|
||||
if lastPrice.Compare(s.sellPrice) < 0 && (longSig ||
|
||||
(!atrx2.IsZero() && base.Sub(atrx2).Compare(lastPrice) >= 0)) {
|
||||
|
@ -903,8 +905,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
}
|
||||
balances := session.GetAccount().Balances()
|
||||
baseBalance := balances[s.Market.BaseCurrency].Available
|
||||
atr := fixedpoint.NewFromFloat(s.atr.Last())
|
||||
atrx2 := fixedpoint.NewFromFloat(s.atr.Last() * 2)
|
||||
atr := fixedpoint.NewFromFloat(s.atr.Last(0))
|
||||
atrx2 := fixedpoint.NewFromFloat(s.atr.Last(0) * 2)
|
||||
sellall := false
|
||||
if s.peakPrice.IsZero() || s.peakPrice.Compare(price) < 0 {
|
||||
s.peakPrice = price
|
||||
|
@ -915,7 +917,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
reason := -1
|
||||
if baseBalance.Compare(s.Market.MinQuantity) >= 0 && baseBalance.Mul(lastPrice).Compare(s.Market.MinNotional) >= 0 {
|
||||
// TP
|
||||
base := fixedpoint.NewFromFloat(s.ma34.Last())
|
||||
base := fixedpoint.NewFromFloat(s.ma34.Last(0))
|
||||
if lastPrice.Compare(s.buyPrice) > 0 && (shortSig ||
|
||||
(!atrx2.IsZero() && base.Add(atrx2).Compare(lastPrice) <= 0)) {
|
||||
sellall = true
|
||||
|
@ -1089,10 +1091,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
balances := session.GetAccount().Balances()
|
||||
baseBalance := balances[s.Market.BaseCurrency].Total()
|
||||
quoteBalance := balances[s.Market.QuoteCurrency].Total()
|
||||
atr := fixedpoint.NewFromFloat(s.atr.Last())
|
||||
atr := fixedpoint.NewFromFloat(s.atr.Last(0))
|
||||
if !s.Environment.IsBackTesting() {
|
||||
log.Infof("Get last price: %v, ewo %f, ewoSig %f, ccis: %f, atr %v, kline: %v, balance[base]: %v balance[quote]: %v",
|
||||
lastPrice, s.ewo.Last(), s.ewoSignal.Last(), s.ccis.ma.Last(), atr, kline, baseBalance, quoteBalance)
|
||||
lastPrice, s.ewo.Last(0), s.ewoSignal.Last(0), s.ccis.ma.Last(0), atr, kline, baseBalance, quoteBalance)
|
||||
}
|
||||
|
||||
if kline.Interval != s.Interval {
|
||||
|
@ -1104,21 +1106,21 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
priceChangeRate := (priceHighest - priceLowest) / priceHighest / 14
|
||||
ewoHighest := types.Highest(s.ewoHistogram, 233)
|
||||
|
||||
s.ewoChangeRate = math.Abs(s.ewoHistogram.Last() / ewoHighest * priceChangeRate)
|
||||
s.ewoChangeRate = math.Abs(s.ewoHistogram.Last(0) / ewoHighest * priceChangeRate)
|
||||
|
||||
longSignal := types.CrossOver(s.ewo, s.ewoSignal)
|
||||
shortSignal := types.CrossUnder(s.ewo, s.ewoSignal)
|
||||
|
||||
base := s.ma34.Last()
|
||||
sellLine := base + s.atr.Last()*3
|
||||
buyLine := base - s.atr.Last()*3
|
||||
base := s.ma34.Last(0)
|
||||
sellLine := base + s.atr.Last(0)*3
|
||||
buyLine := base - s.atr.Last(0)*3
|
||||
clozes := getClose(window)
|
||||
opens := getOpen(window)
|
||||
|
||||
// get trend flags
|
||||
bull := clozes.Last() > opens.Last()
|
||||
breakThrough := clozes.Last() > s.ma5.Last() && clozes.Last() > s.ma34.Last()
|
||||
breakDown := clozes.Last() < s.ma5.Last() && clozes.Last() < s.ma34.Last()
|
||||
bull := clozes.Last(0) > opens.Last(0)
|
||||
breakThrough := clozes.Last(0) > s.ma5.Last(0) && clozes.Last(0) > s.ma34.Last(0)
|
||||
breakDown := clozes.Last(0) < s.ma5.Last(0) && clozes.Last(0) < s.ma34.Last(0)
|
||||
|
||||
// kline breakthrough ma5, ma34 trend up, and cci Stochastic bull
|
||||
IsBull := bull && breakThrough && s.ccis.BuySignal() && s.ewoChangeRate < s.EwoChangeFilterHigh && s.ewoChangeRate > s.EwoChangeFilterLow
|
||||
|
@ -1141,7 +1143,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
|
||||
// backup, since the s.sellPrice will be cleared when doing ClosePosition
|
||||
sellPrice := s.sellPrice
|
||||
log.Errorf("ewoChangeRate %v, emv %v", s.ewoChangeRate, s.emv.Last())
|
||||
log.Errorf("ewoChangeRate %v, emv %v", s.ewoChangeRate, s.emv.Last(0))
|
||||
|
||||
// calculate report
|
||||
if closeOrder, _ := s.PlaceBuyOrder(ctx, price); closeOrder != nil {
|
||||
|
@ -1175,7 +1177,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
|
||||
// backup, since the s.buyPrice will be cleared when doing ClosePosition
|
||||
buyPrice := s.buyPrice
|
||||
log.Errorf("ewoChangeRate: %v, emv %v", s.ewoChangeRate, s.emv.Last())
|
||||
log.Errorf("ewoChangeRate: %v, emv %v", s.ewoChangeRate, s.emv.Last(0))
|
||||
|
||||
// calculate report
|
||||
if closeOrder, _ := s.PlaceSellOrder(ctx, price); closeOrder != nil {
|
||||
|
|
|
@ -34,14 +34,14 @@ func (inc *MOM) Index(i int) float64 {
|
|||
if inc.Values == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Index(i)
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *MOM) Last() float64 {
|
||||
func (inc *MOM) Last(int) float64 {
|
||||
if inc.Values.Length() == 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
return inc.Values.Last(0)
|
||||
}
|
||||
|
||||
func (inc *MOM) Length() int {
|
||||
|
@ -51,7 +51,7 @@ func (inc *MOM) Length() int {
|
|||
return inc.Values.Length()
|
||||
}
|
||||
|
||||
//var _ types.SeriesExtend = &MOM{}
|
||||
// var _ types.SeriesExtend = &MOM{}
|
||||
|
||||
func (inc *MOM) Update(open, close float64) {
|
||||
if inc.SeriesBase.Series == nil {
|
||||
|
@ -62,7 +62,7 @@ func (inc *MOM) Update(open, close float64) {
|
|||
inc.opens.Update(open)
|
||||
inc.closes.Update(close)
|
||||
if inc.opens.Length() >= inc.Window && inc.closes.Length() >= inc.Window {
|
||||
gap := inc.opens.Last()/inc.closes.Index(1) - 1
|
||||
gap := inc.opens.Last(0)/inc.closes.Index(1) - 1
|
||||
inc.Values.Push(gap)
|
||||
}
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ func (inc *MOM) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ func (inc *MOM) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.Open.Float64(), k.Close.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func calculateMomentum(klines []types.KLine, window int, valA KLineValueMapper, valB KLineValueMapper) (float64, error) {
|
||||
|
|
|
@ -35,12 +35,12 @@ func (inc *PMR) Update(price float64) {
|
|||
}
|
||||
inc.SMA.Update(price)
|
||||
if inc.SMA.Length() >= inc.Window {
|
||||
reversion := inc.SMA.Last() / price
|
||||
reversion := inc.SMA.Last(0) / price
|
||||
inc.Values.Push(reversion)
|
||||
}
|
||||
}
|
||||
|
||||
func (inc *PMR) Last() float64 {
|
||||
func (inc *PMR) Last(int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -65,11 +65,11 @@ func (inc *PMR) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ func (inc *PMR) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(indicator.KLineClosePriceMapper(k))
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func CalculateKLinesPMR(allKLines []types.KLine, window int) float64 {
|
||||
|
|
|
@ -47,7 +47,7 @@ func (inc *PVD) Update(price float64, volume float64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (inc *PVD) Last() float64 {
|
||||
func (inc *PVD) Last(int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ func (inc *PVD) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ func (inc *PVD) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(indicator.KLineClosePriceMapper(k), indicator.KLineVolumeMapper(k))
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func CalculateKLinesPVD(allKLines []types.KLine, window int) float64 {
|
||||
|
|
|
@ -30,12 +30,12 @@ func (inc *RR) Update(price float64) {
|
|||
inc.prices = types.NewQueue(inc.Window)
|
||||
}
|
||||
inc.prices.Update(price)
|
||||
irr := inc.prices.Last()/inc.prices.Index(1) - 1
|
||||
irr := inc.prices.Last(0)/inc.prices.Index(1) - 1
|
||||
inc.Values.Push(irr)
|
||||
|
||||
}
|
||||
|
||||
func (inc *RR) Last() float64 {
|
||||
func (inc *RR) Last(int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -60,11 +60,11 @@ func (inc *RR) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,14 +91,14 @@ func (inc *RR) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(indicator.KLineClosePriceMapper(k))
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func (inc *RR) LoadK(allKLines []types.KLine) {
|
||||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
//func calculateReturn(klines []types.KLine, window int, val KLineValueMapper) (float64, error) {
|
||||
|
|
|
@ -33,14 +33,14 @@ func (inc *VMOM) Index(i int) float64 {
|
|||
if inc.Values == nil {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Index(i)
|
||||
return inc.Values.Last(i)
|
||||
}
|
||||
|
||||
func (inc *VMOM) Last() float64 {
|
||||
func (inc *VMOM) Last(int) float64 {
|
||||
if inc.Values.Length() == 0 {
|
||||
return 0
|
||||
}
|
||||
return inc.Values.Last()
|
||||
return inc.Values.Last(0)
|
||||
}
|
||||
|
||||
func (inc *VMOM) Length() int {
|
||||
|
@ -59,7 +59,7 @@ func (inc *VMOM) Update(volume float64) {
|
|||
}
|
||||
inc.volumes.Update(volume)
|
||||
if inc.volumes.Length() >= inc.Window {
|
||||
v := inc.volumes.Last() / inc.volumes.Mean()
|
||||
v := inc.volumes.Last(0) / inc.volumes.Mean()
|
||||
inc.Values.Push(v)
|
||||
}
|
||||
}
|
||||
|
@ -69,11 +69,11 @@ func (inc *VMOM) CalculateAndUpdate(allKLines []types.KLine) {
|
|||
for _, k := range allKLines {
|
||||
inc.PushK(k)
|
||||
}
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
} else {
|
||||
k := allKLines[len(allKLines)-1]
|
||||
inc.PushK(k)
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ func (inc *VMOM) PushK(k types.KLine) {
|
|||
|
||||
inc.Update(k.Volume.Float64())
|
||||
inc.EndTime = k.EndTime.Time()
|
||||
inc.EmitUpdate(inc.Last())
|
||||
inc.EmitUpdate(inc.Last(0))
|
||||
}
|
||||
|
||||
func calculateVolumeMomentum(klines []types.KLine, window int, valV KLineValueMapper, valP KLineValueMapper) (float64, error) {
|
||||
|
@ -110,7 +110,7 @@ func calculateVolumeMomentum(klines []types.KLine, window int, valV KLineValueMa
|
|||
vma += valV(p)
|
||||
}
|
||||
vma /= float64(window)
|
||||
momentum := valV(klines[length-1]) / vma //* (valP(klines[length-1-2]) / valP(klines[length-1]))
|
||||
momentum := valV(klines[length-1]) / vma // * (valP(klines[length-1-2]) / valP(klines[length-1]))
|
||||
|
||||
return momentum, nil
|
||||
}
|
||||
|
|
|
@ -104,11 +104,11 @@ func (s *Linear) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.General
|
|||
|
||||
// use the last value from indicators, or the SeriesExtends' predict function. (e.g., look back: 5)
|
||||
input := []float64{
|
||||
s.divergence.Last(),
|
||||
s.reversion.Last(),
|
||||
s.drift.Last(),
|
||||
s.momentum.Last(),
|
||||
s.volume.Last(),
|
||||
s.divergence.Last(0),
|
||||
s.reversion.Last(0),
|
||||
s.drift.Last(0),
|
||||
s.momentum.Last(0),
|
||||
s.volume.Last(0),
|
||||
}
|
||||
pred := model.Predict(input)
|
||||
predLst.Update(pred)
|
||||
|
|
|
@ -213,7 +213,7 @@ func (s *Strategy) generateSubmitOrders(ctx context.Context) ([]types.SubmitOrde
|
|||
log.Infof("mid price: %+v", midPrice)
|
||||
|
||||
if s.ATRMultiplier.Float64() > 0 {
|
||||
atr := fixedpoint.NewFromFloat(s.atr.Last())
|
||||
atr := fixedpoint.NewFromFloat(s.atr.Last(0))
|
||||
log.Infof("atr: %s", atr.String())
|
||||
s.HalfSpreadRatio = s.ATRMultiplier.Mul(atr).Div(midPrice)
|
||||
log.Infof("half spread ratio: %s", s.HalfSpreadRatio.String())
|
||||
|
|
|
@ -75,7 +75,7 @@ func (s *Strategy) updateBidOrders(orderExecutor bbgo.OrderExecutor, session *bb
|
|||
return
|
||||
}
|
||||
|
||||
var startPrice = fixedpoint.NewFromFloat(s.ewma.Last()).Mul(s.Percentage)
|
||||
var startPrice = fixedpoint.NewFromFloat(s.ewma.Last(0)).Mul(s.Percentage)
|
||||
|
||||
var submitOrders []types.SubmitOrder
|
||||
for i := 0; i < s.GridNum; i++ {
|
||||
|
|
|
@ -21,7 +21,7 @@ type A18 struct {
|
|||
UpdateCallbacks []func(val float64)
|
||||
}
|
||||
|
||||
func (inc *A18) Last() float64 {
|
||||
func (inc *A18) Last(int) float64 {
|
||||
if len(inc.Values) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
@ -84,8 +84,8 @@ func calculateA18(klines []types.KLine, valClose KLineValueMapper) (float64, err
|
|||
closes.Push(valClose(k))
|
||||
}
|
||||
|
||||
delay5 := closes.Index(4)
|
||||
curr := closes.Index(0)
|
||||
delay5 := closes.Last(4)
|
||||
curr := closes.Last(0)
|
||||
alpha := curr / delay5
|
||||
|
||||
return alpha, nil
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user