diff --git a/pkg/indicator/ad.go b/pkg/indicator/ad.go index 463e304eb..31536c8f5 100644 --- a/pkg/indicator/ad.go +++ b/pkg/indicator/ad.go @@ -40,19 +40,11 @@ func (inc *AD) Update(high, low, cloze, volume float64) { } func (inc *AD) Last(i int) float64 { - length := len(inc.Values) - if length == 0 || length-i-1 < 0 { - return 0 - } - return inc.Values[length-i-1] + return inc.Values.Last(i) } func (inc *AD) 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 *AD) Length() int { diff --git a/pkg/indicator/alma.go b/pkg/indicator/alma.go index 6837db766..7f3c806b6 100644 --- a/pkg/indicator/alma.go +++ b/pkg/indicator/alma.go @@ -66,17 +66,11 @@ func (inc *ALMA) Update(value float64) { } func (inc *ALMA) Last(i int) float64 { - if i >= len(inc.Values) { - return 0 - } - return inc.Values[len(inc.Values)-i-1] + return inc.Values.Last(i) } func (inc *ALMA) 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 *ALMA) Length() int { diff --git a/pkg/indicator/atr.go b/pkg/indicator/atr.go index 335c36e2a..d0ed64b83 100644 --- a/pkg/indicator/atr.go +++ b/pkg/indicator/atr.go @@ -89,10 +89,7 @@ func (inc *ATR) Last(i int) float64 { } func (inc *ATR) Index(i int) float64 { - if inc.RMA == nil { - return 0 - } - return inc.RMA.Index(i) + return inc.Last(i) } func (inc *ATR) Length() int { diff --git a/pkg/indicator/atrp.go b/pkg/indicator/atrp.go index 4e8558904..d97bb0af8 100644 --- a/pkg/indicator/atrp.go +++ b/pkg/indicator/atrp.go @@ -81,10 +81,7 @@ func (inc *ATRP) Last(i int) float64 { } func (inc *ATRP) Index(i int) float64 { - if inc.RMA == nil { - return 0 - } - return inc.RMA.Index(i) + return inc.Last(i) } func (inc *ATRP) Length() int { diff --git a/pkg/indicator/emv.go b/pkg/indicator/emv.go index a391a08e7..36d6a36b0 100644 --- a/pkg/indicator/emv.go +++ b/pkg/indicator/emv.go @@ -48,13 +48,6 @@ func (inc *EMV) Update(high, low, vol float64) { inc.Values.Update(result) } -func (inc *EMV) Index(i int) float64 { - if inc.Values == nil { - return 0 - } - return inc.Values.Index(i) -} - func (inc *EMV) Last(i int) float64 { if inc.Values == nil { return 0 @@ -63,6 +56,10 @@ func (inc *EMV) Last(i int) float64 { return inc.Values.Last(i) } +func (inc *EMV) Index(i int) float64 { + return inc.Last(i) +} + func (inc *EMV) Length() int { if inc.Values == nil { return 0 diff --git a/pkg/indicator/ewma.go b/pkg/indicator/ewma.go index e05f30a3c..8d7b13698 100644 --- a/pkg/indicator/ewma.go +++ b/pkg/indicator/ewma.go @@ -55,10 +55,6 @@ func (inc *EWMA) Update(value float64) { } func (inc *EWMA) Last(i int) float64 { - if len(inc.Values) == 0 { - return 0 - } - return inc.Values.Last(i) } diff --git a/pkg/indicator/ghfilter.go b/pkg/indicator/ghfilter.go index e5dea876f..52ea82bba 100644 --- a/pkg/indicator/ghfilter.go +++ b/pkg/indicator/ghfilter.go @@ -45,24 +45,18 @@ func (inc *GHFilter) update(value, uncertainty float64) { inc.lastMeasurement = value } -func (inc *GHFilter) Index(i int) float64 { - return inc.Last(i) -} - func (inc *GHFilter) Length() int { - if inc.Values == nil { - return 0 - } return inc.Values.Length() } func (inc *GHFilter) Last(i int) float64 { - if inc.Values == nil { - return 0.0 - } return inc.Values.Last(i) } +func (inc *GHFilter) Index(i int) float64 { + return inc.Last(i) +} + // interfaces implementation check var _ Simple = &GHFilter{} var _ types.SeriesExtend = &GHFilter{} diff --git a/pkg/indicator/hull.go b/pkg/indicator/hull.go index 7a432d39a..994d5d30d 100644 --- a/pkg/indicator/hull.go +++ b/pkg/indicator/hull.go @@ -44,14 +44,11 @@ func (inc *HULL) Last(i int) float64 { if inc.result == nil { return 0 } - return inc.result.Index(i) + return inc.result.Last(i) } func (inc *HULL) Index(i int) float64 { - if inc.result == nil { - return 0 - } - return inc.result.Index(i) + return inc.Last(i) } func (inc *HULL) Length() int { diff --git a/pkg/indicator/pivothigh.go b/pkg/indicator/pivothigh.go index 52fe7be0b..ec90f57f7 100644 --- a/pkg/indicator/pivothigh.go +++ b/pkg/indicator/pivothigh.go @@ -24,12 +24,8 @@ func (inc *PivotHigh) Length() int { return inc.Values.Length() } -func (inc *PivotHigh) Last(int) float64 { - if len(inc.Values) == 0 { - return 0.0 - } - - return inc.Values.Last(0) +func (inc *PivotHigh) Last(i int) float64 { + return inc.Values.Last(i) } func (inc *PivotHigh) Update(value float64) { diff --git a/pkg/indicator/pivotlow.go b/pkg/indicator/pivotlow.go index 7bdbd58e6..2023fc941 100644 --- a/pkg/indicator/pivotlow.go +++ b/pkg/indicator/pivotlow.go @@ -24,12 +24,8 @@ func (inc *PivotLow) Length() int { return inc.Values.Length() } -func (inc *PivotLow) Last(int) float64 { - if len(inc.Values) == 0 { - return 0.0 - } - - return inc.Values.Last(0) +func (inc *PivotLow) Last(i int) float64 { + return inc.Values.Last(i) } func (inc *PivotLow) Update(value float64) { diff --git a/pkg/indicator/psar.go b/pkg/indicator/psar.go index 5154c1b54..0d19363ac 100644 --- a/pkg/indicator/psar.go +++ b/pkg/indicator/psar.go @@ -34,11 +34,8 @@ type PSAR struct { UpdateCallbacks []func(value float64) } -func (inc *PSAR) Last(int) float64 { - if len(inc.Values) == 0 { - return 0 - } - return inc.Values.Last(0) +func (inc *PSAR) Last(i int) float64 { + return inc.Values.Last(i) } func (inc *PSAR) Length() int { diff --git a/pkg/strategy/drift/driftma.go b/pkg/strategy/drift/driftma.go index ba0468cdc..a737ed4d1 100644 --- a/pkg/strategy/drift/driftma.go +++ b/pkg/strategy/drift/driftma.go @@ -24,8 +24,8 @@ func (s *DriftMA) Update(value, weight float64) { s.ma2.Update(s.drift.Last(0)) } -func (s *DriftMA) Last(int) float64 { - return s.ma2.Last(0) +func (s *DriftMA) Last(i int) float64 { + return s.ma2.Last(i) } func (s *DriftMA) Index(i int) float64 { diff --git a/pkg/strategy/elliottwave/ewo.go b/pkg/strategy/elliottwave/ewo.go index f86706b18..bbe83f488 100644 --- a/pkg/strategy/elliottwave/ewo.go +++ b/pkg/strategy/elliottwave/ewo.go @@ -8,11 +8,11 @@ type ElliottWave struct { } func (s *ElliottWave) Index(i int) float64 { - return s.maQuick.Index(i)/s.maSlow.Index(i) - 1.0 + return s.Last(i) } -func (s *ElliottWave) Last(int) float64 { - return s.maQuick.Last(0)/s.maSlow.Last(0) - 1.0 +func (s *ElliottWave) Last(i int) float64 { + return s.maQuick.Index(i)/s.maSlow.Index(i) - 1.0 } func (s *ElliottWave) Length() int { diff --git a/pkg/strategy/ewoDgtrd/strategy.go b/pkg/strategy/ewoDgtrd/strategy.go index 50af7f4bf..b64203639 100644 --- a/pkg/strategy/ewoDgtrd/strategy.go +++ b/pkg/strategy/ewoDgtrd/strategy.go @@ -180,11 +180,11 @@ type VWEMA struct { V types.UpdatableSeries } -func (inc *VWEMA) Last(int) float64 { - return inc.PV.Last(0) / inc.V.Last(0) +func (inc *VWEMA) Index(i int) float64 { + return inc.Last(i) } -func (inc *VWEMA) Index(i int) float64 { +func (inc *VWEMA) Last(i int) float64 { if i >= inc.PV.Length() { return 0 } diff --git a/pkg/strategy/factorzoo/factors/momentum.go b/pkg/strategy/factorzoo/factors/momentum.go index 827af0976..e491a3848 100644 --- a/pkg/strategy/factorzoo/factors/momentum.go +++ b/pkg/strategy/factorzoo/factors/momentum.go @@ -31,23 +31,14 @@ type MOM struct { } func (inc *MOM) Index(i int) float64 { - if inc.Values == nil { - return 0 - } + return inc.Last(i) +} + +func (inc *MOM) Last(i int) float64 { return inc.Values.Last(i) } -func (inc *MOM) Last(int) float64 { - if inc.Values.Length() == 0 { - return 0 - } - return inc.Values.Last(0) -} - func (inc *MOM) Length() int { - if inc.Values == nil { - return 0 - } return inc.Values.Length() } diff --git a/pkg/strategy/factorzoo/factors/price_mean_reversion.go b/pkg/strategy/factorzoo/factors/price_mean_reversion.go index 7143e547c..fbc4c5ad4 100644 --- a/pkg/strategy/factorzoo/factors/price_mean_reversion.go +++ b/pkg/strategy/factorzoo/factors/price_mean_reversion.go @@ -19,8 +19,8 @@ type PMR struct { types.IntervalWindow types.SeriesBase - Values floats.Slice - SMA *indicator.SMA + Values floats.Slice + SMA *indicator.SMA EndTime time.Time updateCallbacks []func(value float64) @@ -40,20 +40,12 @@ func (inc *PMR) Update(price float64) { } } -func (inc *PMR) Last(int) float64 { - if len(inc.Values) == 0 { - return 0 - } - - return inc.Values[len(inc.Values)-1] +func (inc *PMR) Last(i int) float64 { + return inc.Values.Last(i) } func (inc *PMR) 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 *PMR) Length() int { diff --git a/pkg/strategy/factorzoo/factors/price_volume_divergence.go b/pkg/strategy/factorzoo/factors/price_volume_divergence.go index adc20e02a..f531eb214 100644 --- a/pkg/strategy/factorzoo/factors/price_volume_divergence.go +++ b/pkg/strategy/factorzoo/factors/price_volume_divergence.go @@ -23,8 +23,8 @@ type PVD struct { types.IntervalWindow types.SeriesBase - Values floats.Slice - Prices *types.Queue + Values floats.Slice + Prices *types.Queue Volumes *types.Queue EndTime time.Time @@ -47,20 +47,12 @@ func (inc *PVD) Update(price float64, volume float64) { } } -func (inc *PVD) Last(int) float64 { - if len(inc.Values) == 0 { - return 0 - } - - return inc.Values[len(inc.Values)-1] +func (inc *PVD) Last(i int) float64 { + return inc.Values.Last(i) } func (inc *PVD) 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 *PVD) Length() int { diff --git a/pkg/strategy/factorzoo/factors/return_rate.go b/pkg/strategy/factorzoo/factors/return_rate.go index 3fe3d4156..114e4b9d9 100644 --- a/pkg/strategy/factorzoo/factors/return_rate.go +++ b/pkg/strategy/factorzoo/factors/return_rate.go @@ -35,20 +35,12 @@ func (inc *RR) Update(price float64) { } -func (inc *RR) Last(int) float64 { - if len(inc.Values) == 0 { - return 0 - } - - return inc.Values[len(inc.Values)-1] +func (inc *RR) Last(i int) float64 { + return inc.Values.Last(i) } func (inc *RR) 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 *RR) Length() int { @@ -101,7 +93,7 @@ func (inc *RR) LoadK(allKLines []types.KLine) { inc.EmitUpdate(inc.Last(0)) } -//func calculateReturn(klines []types.KLine, window int, val KLineValueMapper) (float64, error) { +// func calculateReturn(klines []types.KLine, window int, val KLineValueMapper) (float64, error) { // length := len(klines) // if length == 0 || length < window { // return 0.0, fmt.Errorf("insufficient elements for calculating VOL with window = %d", window) @@ -110,4 +102,4 @@ func (inc *RR) LoadK(allKLines []types.KLine) { // rate := val(klines[length-1])/val(klines[length-2]) - 1 // // return rate, nil -//} +// } diff --git a/pkg/strategy/factorzoo/factors/volume_momentum.go b/pkg/strategy/factorzoo/factors/volume_momentum.go index 87029ed9e..02a4c32fe 100644 --- a/pkg/strategy/factorzoo/factors/volume_momentum.go +++ b/pkg/strategy/factorzoo/factors/volume_momentum.go @@ -30,23 +30,14 @@ type VMOM struct { } func (inc *VMOM) Index(i int) float64 { - if inc.Values == nil { - return 0 - } + return inc.Last(i) +} + +func (inc *VMOM) Last(i int) float64 { return inc.Values.Last(i) } -func (inc *VMOM) Last(int) float64 { - if inc.Values.Length() == 0 { - return 0 - } - return inc.Values.Last(0) -} - func (inc *VMOM) Length() int { - if inc.Values == nil { - return 0 - } return inc.Values.Length() } diff --git a/pkg/strategy/harmonic/shark.go b/pkg/strategy/harmonic/shark.go index d7bc287c3..a23d7e62e 100644 --- a/pkg/strategy/harmonic/shark.go +++ b/pkg/strategy/harmonic/shark.go @@ -51,20 +51,12 @@ func (inc *SHARK) Update(high, low, price float64) { } -func (inc *SHARK) Last(int) float64 { - if len(inc.Values) == 0 { - return 0 - } - - return inc.Values[len(inc.Values)-1] +func (inc *SHARK) Last(i int) float64 { + return inc.Values.Last(i) } func (inc *SHARK) 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 *SHARK) Length() int { @@ -107,7 +99,7 @@ func (inc SHARK) SharkLong(highs, lows floats.Slice, p float64, lookback int) fl if lows.Index(b-1) > lows.Index(b) && lows.Index(b) < lows.Index(b+1) { B := lows.Index(b) if hB > B && B > lB { - //log.Infof("got point B:%f", B) + // log.Infof("got point B:%f", B) AB := math.Abs(A - B) hC := B + 1.618*AB lC := B + 1.13*AB @@ -115,24 +107,24 @@ func (inc SHARK) SharkLong(highs, lows floats.Slice, p float64, lookback int) fl if highs.Index(c-1) < highs.Index(c) && highs.Index(c) > highs.Index(c+1) { C := highs.Index(c) if hC > C && C > lC { - //log.Infof("got point C:%f", C) + // log.Infof("got point C:%f", C) XC := math.Abs(X - C) hD := C - 0.886*XC lD := C - 1.13*XC - //for d := 1; d < c; d++ { - //if lows.Index(d-1) > lows.Index(d) && lows.Index(d) < lows.Index(d+1) { - D := p //lows.Index(d) + // for d := 1; d < c; d++ { + // if lows.Index(d-1) > lows.Index(d) && lows.Index(d) < lows.Index(d+1) { + D := p // lows.Index(d) if hD > D && D > lD { BC := math.Abs(B - C) hD2 := C - 1.618*BC lD2 := C - 2.24*BC if hD2 > D && D > lD2 { - //log.Infof("got point D:%f", D) + // log.Infof("got point D:%f", D) score++ } } - //} - //} + // } + // } } } } @@ -161,7 +153,7 @@ func (inc SHARK) SharkShort(highs, lows floats.Slice, p float64, lookback int) f if highs.Index(b-1) > highs.Index(b) && highs.Index(b) < highs.Index(b+1) { B := highs.Index(b) if hB > B && B > lB { - //log.Infof("got point B:%f", B) + // log.Infof("got point B:%f", B) AB := math.Abs(A - B) lC := B - 1.618*AB hC := B - 1.13*AB @@ -169,24 +161,24 @@ func (inc SHARK) SharkShort(highs, lows floats.Slice, p float64, lookback int) f if lows.Index(c-1) < lows.Index(c) && lows.Index(c) > lows.Index(c+1) { C := lows.Index(c) if hC > C && C > lC { - //log.Infof("got point C:%f", C) + // log.Infof("got point C:%f", C) XC := math.Abs(X - C) lD := C + 0.886*XC hD := C + 1.13*XC - //for d := 1; d < c; d++ { - //if lows.Index(d-1) > lows.Index(d) && lows.Index(d) < lows.Index(d+1) { - D := p //lows.Index(d) + // for d := 1; d < c; d++ { + // if lows.Index(d-1) > lows.Index(d) && lows.Index(d) < lows.Index(d+1) { + D := p // lows.Index(d) if hD > D && D > lD { BC := math.Abs(B - C) lD2 := C + 1.618*BC hD2 := C + 2.24*BC if hD2 > D && D > lD2 { - //log.Infof("got point D:%f", D) + // log.Infof("got point D:%f", D) score++ } } - //} - //} + // } + // } } } } diff --git a/pkg/strategy/irr/neg_return_rate.go b/pkg/strategy/irr/neg_return_rate.go index 72fe420fe..f16adecbe 100644 --- a/pkg/strategy/irr/neg_return_rate.go +++ b/pkg/strategy/irr/neg_return_rate.go @@ -53,20 +53,12 @@ func (inc *NRR) Update(openPrice, closePrice float64) { inc.ReturnValues.Push(irr) } -func (inc *NRR) Last(int) float64 { - if len(inc.Values) == 0 { - return 0 - } - - return inc.Values[len(inc.Values)-1] +func (inc *NRR) Last(i int) float64 { + return inc.Values.Last(i) } func (inc *NRR) 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 *NRR) Length() int { diff --git a/pkg/strategy/supertrend/linreg.go b/pkg/strategy/supertrend/linreg.go index 65813aa7f..cc790b0b0 100644 --- a/pkg/strategy/supertrend/linreg.go +++ b/pkg/strategy/supertrend/linreg.go @@ -19,20 +19,13 @@ type LinReg struct { } // Last slope of linear regression baseline -func (lr *LinReg) Last(int) float64 { - if lr.Values.Length() == 0 { - return 0.0 - } - return lr.Values.Last(0) +func (lr *LinReg) Last(i int) float64 { + return lr.Values.Last(i) } // 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.Last(i) } // Length of the slope values diff --git a/pkg/types/filter.go b/pkg/types/filter.go index bdb9e5de0..3c1a2f858 100644 --- a/pkg/types/filter.go +++ b/pkg/types/filter.go @@ -12,7 +12,7 @@ func (f *FilterResult) Last(j int) float64 { return 0 } if len(f.c) > j { - return f.a.Index(f.c[j]) + return f.a.Last(f.c[j]) } l := f.a.Length() k := len(f.c) @@ -21,7 +21,7 @@ func (f *FilterResult) Last(j int) float64 { i = f.c[k-1] + 1 } for ; i < l; i++ { - tmp := f.a.Index(i) + tmp := f.a.Last(i) if f.b(i, tmp) { f.c = append(f.c, i) if j == k { diff --git a/pkg/types/indicator.go b/pkg/types/indicator.go index d8fe3870c..4dd396b05 100644 --- a/pkg/types/indicator.go +++ b/pkg/types/indicator.go @@ -26,7 +26,7 @@ func (a *AbsResult) Last(i int) float64 { } func (a *AbsResult) Index(i int) float64 { - return math.Abs(a.a.Index(i)) + return a.Last(i) } func (a *AbsResult) Length() int { @@ -49,7 +49,7 @@ func LinearRegression(a Series, lookback int) (alpha float64, beta float64) { var weights []float64 for i := 0; i < lookback; i++ { x[i] = float64(i) - y[i] = a.Index(i) + y[i] = a.Last(i) } alpha, beta = stat.LinearRegression(x, y, weights, false) return @@ -83,8 +83,8 @@ func NextCross(a Series, b Series, lookback int) (int, float64, bool) { var weights []float64 for i := 0; i < lookback; i++ { x[i] = float64(i) - y1[i] = a.Index(i) - y2[i] = b.Index(i) + y1[i] = a.Last(i) + y2[i] = b.Last(i) } alpha1, beta1 := stat.LinearRegression(x, y1, weights, false) alpha2, beta2 := stat.LinearRegression(x, y2, weights, false) @@ -113,9 +113,9 @@ func (c *CrossResult) Last() bool { return false } if c.isOver { - return c.a.Last(0)-c.b.Last(0) > 0 && c.a.Index(1)-c.b.Index(1) < 0 + return c.a.Last(0)-c.b.Last(0) > 0 && c.a.Last(1)-c.b.Last(1) < 0 } else { - return c.a.Last(0)-c.b.Last(0) < 0 && c.a.Index(1)-c.b.Index(1) > 0 + return c.a.Last(0)-c.b.Last(0) < 0 && c.a.Last(1)-c.b.Last(1) > 0 } } @@ -124,9 +124,9 @@ func (c *CrossResult) Index(i int) bool { return false } if c.isOver { - return c.a.Index(i)-c.b.Index(i) > 0 && c.a.Index(i+1)-c.b.Index(i+1) < 0 + return c.a.Last(i)-c.b.Last(i) > 0 && c.a.Last(i+1)-c.b.Last(i+1) < 0 } else { - return c.a.Index(i)-c.b.Index(i) < 0 && c.a.Index(i+1)-c.b.Index(i+1) > 0 + return c.a.Last(i)-c.b.Last(i) < 0 && c.a.Last(i+1)-c.b.Last(i+1) > 0 } } @@ -161,7 +161,7 @@ func Highest(a Series, lookback int) float64 { } highest := a.Last(0) for i := 1; i < lookback; i++ { - current := a.Index(i) + current := a.Last(i) if highest < current { highest = current } @@ -175,7 +175,7 @@ func Lowest(a Series, lookback int) float64 { } lowest := a.Last(0) for i := 1; i < lookback; i++ { - current := a.Index(i) + current := a.Last(i) if lowest > current { lowest = current } @@ -247,7 +247,7 @@ func Sub(a interface{}, b interface{}) SeriesExtend { } func (a *MinusSeriesResult) Last(i int) float64 { - return a.a.Index(i) - a.b.Index(i) + return a.a.Last(i) - a.b.Last(i) } func (a *MinusSeriesResult) Index(i int) float64 { @@ -303,7 +303,7 @@ type DivSeriesResult struct { } func (a *DivSeriesResult) Last(i int) float64 { - return a.a.Index(i) / a.b.Index(i) + return a.a.Last(i) / a.b.Last(i) } func (a *DivSeriesResult) Index(i int) float64 { @@ -334,7 +334,7 @@ type MulSeriesResult struct { } func (a *MulSeriesResult) Last(i int) float64 { - return a.a.Index(i) * a.b.Index(i) + return a.a.Last(i) * a.b.Last(i) } func (a *MulSeriesResult) Index(i int) float64 { @@ -427,19 +427,19 @@ func Dot(a interface{}, b interface{}, limit ...int) float64 { } else if isaf && !isbf { sum := 0. for i := 0; i < l; i++ { - sum += aaf * bbs.Index(i) + sum += aaf * bbs.Last(i) } return sum } else if !isaf && isbf { sum := 0. for i := 0; i < l; i++ { - sum += aas.Index(i) * bbf + sum += aas.Last(i) * bbf } return sum } else { sum := 0. for i := 0; i < l; i++ { - sum += aas.Index(i) * bbs.Index(i) + sum += aas.Last(i) * bbs.Index(i) } return sum } @@ -458,7 +458,7 @@ func Array(a Series, limit ...int) (result []float64) { } result = make([]float64, l) for i := 0; i < l; i++ { - result[i] = a.Index(i) + result[i] = a.Last(i) } return } @@ -475,7 +475,7 @@ func Reverse(a Series, limit ...int) (result floats.Slice) { } result = make([]float64, l) for i := 0; i < l; i++ { - result[l-i-1] = a.Index(i) + result[l-i-1] = a.Last(i) } return } @@ -489,7 +489,7 @@ func (c *ChangeResult) Last(i int) float64 { if i+c.offset >= c.a.Length() { return 0 } - return c.a.Index(i) - c.a.Index(i+c.offset) + return c.a.Last(i) - c.a.Last(i+c.offset) } func (c *ChangeResult) Index(i int) float64 { @@ -524,7 +524,7 @@ func (c *PercentageChangeResult) Last(i int) float64 { if i+c.offset >= c.a.Length() { return 0 } - return c.a.Index(i)/c.a.Index(i+c.offset) - 1 + return c.a.Last(i)/c.a.Last(i+c.offset) - 1 } func (c *PercentageChangeResult) Index(i int) float64 { @@ -565,7 +565,7 @@ func Stdev(a Series, params ...int) float64 { avg := Mean(a, length) s := .0 for i := 0; i < length; i++ { - diff := a.Index(i) - avg + diff := a.Last(i) - avg s += diff * diff } if length-ddof == 0 { @@ -588,7 +588,7 @@ func Kendall(a, b Series, length int) float64 { concordant, discordant := 0, 0 for i := 0; i < length; i++ { for j := i + 1; j < length; j++ { - value := (aRanks.Index(i) - aRanks.Index(j)) * (bRanks.Index(i) - bRanks.Index(j)) + value := (aRanks.Last(i) - aRanks.Last(j)) * (bRanks.Last(i) - bRanks.Last(j)) if value > 0 { concordant++ } else { @@ -606,10 +606,10 @@ func Rank(a Series, length int) SeriesExtend { rank := make([]float64, length) mapper := make([]float64, length+1) for i := length - 1; i >= 0; i-- { - ii := a.Index(i) + ii := a.Last(i) counter := 0. for j := 0; j < length; j++ { - if a.Index(j) <= ii { + if a.Last(j) <= ii { counter += 1. } } @@ -633,8 +633,8 @@ func Pearson(a, b Series, length int) float64 { x := make([]float64, length) y := make([]float64, length) for i := 0; i < length; i++ { - x[i] = a.Index(i) - y[i] = b.Index(i) + x[i] = a.Last(i) + y[i] = b.Last(i) } return stat.Correlation(x, y, nil) } @@ -690,7 +690,7 @@ func Covariance(a Series, b Series, length int) float64 { meanb := Mean(b, length) sum := 0.0 for i := 0; i < length; i++ { - sum += (a.Index(i) - meana) * (b.Index(i) - meanb) + sum += (a.Last(i) - meana) * (b.Last(i) - meanb) } sum /= float64(length) return sum @@ -711,7 +711,7 @@ func Skew(a Series, length int) float64 { sum2 := 0.0 sum3 := 0.0 for i := 0; i < length; i++ { - diff := a.Index(i) - mean + diff := a.Last(i) - mean sum2 += diff * diff sum3 += diff * diff * diff } @@ -735,7 +735,7 @@ func (inc *ShiftResult) Last(i int) float64 { return 0 } - return inc.a.Index(inc.offset + i) + return inc.a.Last(inc.offset + i) } func (inc *ShiftResult) Index(i int) float64 { @@ -811,11 +811,11 @@ func Softmax(a Series, window int) SeriesExtend { s := 0.0 max := Highest(a, window) for i := 0; i < window; i++ { - s += math.Exp(a.Index(i) - max) + s += math.Exp(a.Last(i) - max) } out := NewQueue(window) for i := window - 1; i >= 0; i-- { - out.Update(math.Exp(a.Index(i)-max) / s) + out.Update(math.Exp(a.Last(i)-max) / s) } return out } @@ -825,7 +825,7 @@ func Softmax(a Series, window int) SeriesExtend { // - sum(v * ln(v)) func Entropy(a Series, window int) (e float64) { for i := 0; i < window; i++ { - v := a.Index(i) + v := a.Last(i) if v != 0 { e -= v * math.Log(v) } @@ -836,9 +836,9 @@ func Entropy(a Series, window int) (e float64) { // CrossEntropy computes the cross-entropy between the two distributions func CrossEntropy(a, b Series, window int) (e float64) { for i := 0; i < window; i++ { - v := a.Index(i) + v := a.Last(i) if v != 0 { - e -= v * math.Log(b.Index(i)) + e -= v * math.Log(b.Last(i)) } } return e @@ -893,7 +893,7 @@ func LogisticRegression(x []Series, y Series, lookback, iterations int, learning xx := make([][]float64, lookback) for i := 0; i < lookback; i++ { for j := 0; j < features; j++ { - xx[i] = append(xx[i], x[j].Index(lookback-i-1)) + xx[i] = append(xx[i], x[j].Last(lookback-i-1)) } } yy := Reverse(y, lookback) @@ -1002,7 +1002,7 @@ func (canvas *Canvas) Plot(tag string, a Series, endTime Time, length int, inter if a.Length() == 0 { return } - oldest := a.Index(a.Length() - 1) + oldest := a.Last(a.Length() - 1) interval := canvas.Interval if len(intervals) > 0 { interval = intervals[0] @@ -1026,7 +1026,7 @@ func (canvas *Canvas) PlotRaw(tag string, a Series, length int) { if a.Length() == 0 { return } - oldest := a.Index(a.Length() - 1) + oldest := a.Last(a.Length() - 1) canvas.Series = append(canvas.Series, chart.ContinuousSeries{ Name: tag, XValues: x, diff --git a/pkg/types/indicator_test.go b/pkg/types/indicator_test.go index 19c265ea8..da328c666 100644 --- a/pkg/types/indicator_test.go +++ b/pkg/types/indicator_test.go @@ -24,7 +24,7 @@ func TestQueue(t *testing.T) { func TestFloat(t *testing.T) { var a Series = Sub(3., 2.) assert.Equal(t, a.Last(0), 1.) - assert.Equal(t, a.Index(100), 1.) + assert.Equal(t, a.Last(100), 1.) } func TestNextCross(t *testing.T) { @@ -67,8 +67,8 @@ func TestCorr(t *testing.T) { corr := Correlation(&a, &b, 4, Pearson) assert.InDelta(t, corr, -0.8510644, 0.001) out := Rank(&a, 4) - assert.Equal(t, out.Index(0), 2.5) - assert.Equal(t, out.Index(1), 4.0) + assert.Equal(t, out.Last(0), 2.5) + assert.Equal(t, out.Last(1), 4.0) corr = Correlation(&a, &b, 4, Spearman) assert.InDelta(t, corr, -0.94868, 0.001) } @@ -119,7 +119,7 @@ func TestSoftmax(t *testing.T) { out := Softmax(&a, a.Length()) r := floats.Slice{0.8360188027814407, 0.11314284146556013, 0.05083835575299916} for i := 0; i < out.Length(); i++ { - assert.InDelta(t, r.Index(i), out.Index(i), 0.001) + assert.InDelta(t, r.Last(i), out.Last(i), 0.001) } } @@ -128,7 +128,7 @@ func TestSigmoid(t *testing.T) { out := Sigmoid(&a) r := floats.Slice{0.9525741268224334, 0.7310585786300049, 0.8909031788043871} for i := 0; i < out.Length(); i++ { - assert.InDelta(t, r.Index(i), out.Index(i), 0.001, "i=%d", i) + assert.InDelta(t, r.Last(i), out.Last(i), 0.001, "i=%d", i) } } @@ -143,7 +143,6 @@ func TestAdd(t *testing.T) { var b NumberSeries = 2.0 out := Add(&a, &b) assert.Equal(t, out.Last(0), 5.0) - assert.Equal(t, out.Index(0), 5.0) assert.Equal(t, out.Length(), math.MaxInt32) } @@ -153,7 +152,7 @@ func TestDiv(t *testing.T) { out := Div(&a, &b) assert.Equal(t, 1.0, out.Last(0)) assert.Equal(t, 3, out.Length()) - assert.Equal(t, 0.5, out.Index(1)) + assert.Equal(t, 0.5, out.Last(1)) } func TestMul(t *testing.T) { @@ -162,7 +161,7 @@ func TestMul(t *testing.T) { out := Mul(&a, &b) assert.Equal(t, out.Last(0), 4.0) assert.Equal(t, out.Length(), 3) - assert.Equal(t, out.Index(1), 2.0) + assert.Equal(t, out.Last(1), 2.0) } func TestArray(t *testing.T) { diff --git a/pkg/types/kline.go b/pkg/types/kline.go index fcc358176..8df06d297 100644 --- a/pkg/types/kline.go +++ b/pkg/types/kline.go @@ -597,26 +597,11 @@ type KLineSeries struct { kv KValueType } -func (k *KLineSeries) Last(int) float64 { - length := len(*k.lines) - switch k.kv { - case kOpUnknown: - panic("kline series operator unknown") - case kOpenValue: - return (*k.lines)[length-1].GetOpen().Float64() - case kCloseValue: - return (*k.lines)[length-1].GetClose().Float64() - case kLowValue: - return (*k.lines)[length-1].GetLow().Float64() - case kHighValue: - return (*k.lines)[length-1].GetHigh().Float64() - case kVolumeValue: - return (*k.lines)[length-1].Volume.Float64() - } - return 0 +func (k *KLineSeries) Index(i int) float64 { + return k.Last(i) } -func (k *KLineSeries) Index(i int) float64 { +func (k *KLineSeries) Last(i int) float64 { length := len(*k.lines) if length == 0 || length-i-1 < 0 { return 0 diff --git a/pkg/types/omega.go b/pkg/types/omega.go index a89649e4f..0556bb090 100644 --- a/pkg/types/omega.go +++ b/pkg/types/omega.go @@ -17,7 +17,7 @@ func Omega(returns Series, returnThresholds ...float64) float64 { win := 0.0 loss := 0.0 for i := 0; i < length; i++ { - out := threshold - returns.Index(i) + out := threshold - returns.Last(i) if out > 0 { win += out } else { diff --git a/pkg/types/pca.go b/pkg/types/pca.go index 9ecc00a6c..d11a3c15c 100644 --- a/pkg/types/pca.go +++ b/pkg/types/pca.go @@ -2,6 +2,7 @@ package types import ( "fmt" + "gonum.org/v1/gonum/mat" ) @@ -21,7 +22,7 @@ func (pca *PCA) Fit(x []SeriesExtend, lookback int) error { for i, xx := range x { mean := xx.Mean(lookback) for j := 0; j < lookback; j++ { - vec[i+j*i] = xx.Index(j) - mean + vec[i+j*i] = xx.Last(j) - mean } } pca.svd = &mat.SVD{} @@ -40,7 +41,7 @@ func (pca *PCA) Transform(x []SeriesExtend, lookback int, features int) (result vec := make([]float64, lookback*len(x)) for i, xx := range x { for j := 0; j < lookback; j++ { - vec[i+j*i] = xx.Index(j) + vec[i+j*i] = xx.Last(j) } } newX := mat.NewDense(lookback, len(x), vec) diff --git a/pkg/types/queue.go b/pkg/types/queue.go index 5205f802f..ce68877ec 100644 --- a/pkg/types/queue.go +++ b/pkg/types/queue.go @@ -21,6 +21,7 @@ func (inc *Queue) Last(i int) float64 { if i < 0 || len(inc.arr)-i-1 < 0 { return 0 } + return inc.arr[len(inc.arr)-1-i] } diff --git a/pkg/types/series.go b/pkg/types/series.go index 1c4289ee2..f97472b22 100644 --- a/pkg/types/series.go +++ b/pkg/types/series.go @@ -103,7 +103,7 @@ func Sum(a Series, limit ...int) (sum float64) { l = limit[0] } for i := 0; i < l; i++ { - sum += a.Index(i) + sum += a.Last(i) } return sum } diff --git a/pkg/types/seriesbase_imp.go b/pkg/types/seriesbase_imp.go index 1e52ce544..fee51ddc4 100644 --- a/pkg/types/seriesbase_imp.go +++ b/pkg/types/seriesbase_imp.go @@ -12,19 +12,16 @@ type SeriesBase struct { } func (s *SeriesBase) Index(i int) float64 { + return s.Last(i) +} + +func (s *SeriesBase) Last(i int) float64 { if s.Series == nil { return 0 } return s.Series.Last(i) } -func (s *SeriesBase) Last(int) float64 { - if s.Series == nil { - return 0 - } - return s.Series.Last(0) -} - func (s *SeriesBase) Length() int { if s.Series == nil { return 0 diff --git a/pkg/types/sortino.go b/pkg/types/sortino.go index 32acdb3f4..362b94d60 100644 --- a/pkg/types/sortino.go +++ b/pkg/types/sortino.go @@ -6,9 +6,11 @@ import ( // Sortino: Calcluates the sotino ratio of access returns // -// ROI_excess E[ROI] - ROI_risk_free +// ROI_excess E[ROI] - ROI_risk_free +// // sortino = ---------- = ----------------------- -// risk sqrt(E[ROI_drawdown^2]) +// +// risk sqrt(E[ROI_drawdown^2]) // // @param returns (Series): Series of profit/loss percentage every specific interval // @param riskFreeReturns (float): risk-free return rate of year @@ -29,7 +31,7 @@ func Sortino(returns Series, riskFreeReturns float64, periods int, annualize boo } var sum = 0. for i := 0; i < num; i++ { - exRet := returns.Index(i) - avgRiskFreeReturns + exRet := returns.Last(i) - avgRiskFreeReturns if exRet < 0 { sum += exRet * exRet }