diff --git a/pkg/datatype/floats/map.go b/pkg/datatype/floats/map.go new file mode 100644 index 000000000..efdcf82fe --- /dev/null +++ b/pkg/datatype/floats/map.go @@ -0,0 +1,42 @@ +package floats + +type Map map[string]float64 + +func (m Map) Sum() float64 { + sum := 0.0 + for _, v := range m { + sum += v + } + return sum +} + +func (m Map) MulScalar(x float64) Map { + o := Map{} + for k, v := range m { + o[k] = v * x + } + + return o +} +func (m Map) DivScalar(x float64) Map { + o := Map{} + for k, v := range m { + o[k] = v / x + } + + return o +} + +func (m Map) Normalize() Map { + sum := m.Sum() + if sum == 0 { + panic("zero sum") + } + + o := Map{} + for k, v := range m { + o[k] = v / sum + } + + return o +} diff --git a/pkg/datatype/floats/slice.go b/pkg/datatype/floats/slice.go new file mode 100644 index 000000000..4aab25eb8 --- /dev/null +++ b/pkg/datatype/floats/slice.go @@ -0,0 +1,151 @@ +package floats + +import ( + "math" + + "gonum.org/v1/gonum/floats" +) + +type Slice []float64 + +func New(a ...float64) Slice { + return Slice(a) +} + +func (s *Slice) Push(v float64) { + *s = append(*s, v) +} + +func (s *Slice) Update(v float64) { + *s = append(*s, v) +} + +func (s *Slice) Pop(i int64) (v float64) { + v = (*s)[i] + *s = append((*s)[:i], (*s)[i+1:]...) + return v +} + +func (s Slice) Max() float64 { + return floats.Max(s) +} + +func (s Slice) Min() float64 { + return floats.Min(s) +} + +func (s Slice) Sum() (sum float64) { + return floats.Sum(s) +} + +func (s Slice) Mean() (mean float64) { + length := len(s) + if length == 0 { + panic("zero length slice") + } + return s.Sum() / float64(length) +} + +func (s Slice) Tail(size int) Slice { + length := len(s) + if length <= size { + win := make(Slice, length) + copy(win, s) + return win + } + + win := make(Slice, size) + copy(win, s[length-size:]) + return win +} + +func (s Slice) Diff() (values Slice) { + for i, v := range s { + if i == 0 { + values.Push(0) + continue + } + values.Push(v - s[i-1]) + } + return values +} + +func (s Slice) PositiveValuesOrZero() (values Slice) { + for _, v := range s { + values.Push(math.Max(v, 0)) + } + return values +} + +func (s Slice) NegativeValuesOrZero() (values Slice) { + for _, v := range s { + values.Push(math.Min(v, 0)) + } + return values +} + +func (s Slice) Abs() (values Slice) { + for _, v := range s { + values.Push(math.Abs(v)) + } + return values +} + +func (s Slice) MulScalar(x float64) (values Slice) { + for _, v := range s { + values.Push(v * x) + } + return values +} + +func (s Slice) DivScalar(x float64) (values Slice) { + for _, v := range s { + values.Push(v / x) + } + return values +} + +func (s Slice) Mul(other Slice) (values Slice) { + if len(s) != len(other) { + panic("slice lengths do not match") + } + + for i, v := range s { + values.Push(v * other[i]) + } + + return values +} + +func (s Slice) Dot(other Slice) float64 { + return floats.Dot(s, other) +} + +func (s Slice) Normalize() Slice { + return s.DivScalar(s.Sum()) +} + +func (s *Slice) Last() float64 { + length := len(*s) + if length > 0 { + return (*s)[length-1] + } + return 0.0 +} + +func (s *Slice) Index(i int) float64 { + length := len(*s) + if length-i <= 0 || i < 0 { + return 0.0 + } + return (*s)[length-i-1] +} + +func (s *Slice) Length() int { + return len(*s) +} + +func (s Slice) Addr() *Slice { + return &s +} + diff --git a/pkg/indicator/ad.go b/pkg/indicator/ad.go index dc04de306..e94f8d246 100644 --- a/pkg/indicator/ad.go +++ b/pkg/indicator/ad.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -16,7 +17,7 @@ Accumulation/Distribution Indicator (A/D) type AD struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice PrePrice float64 EndTime time.Time diff --git a/pkg/indicator/alma.go b/pkg/indicator/alma.go index ab39a6c8e..2558344a3 100644 --- a/pkg/indicator/alma.go +++ b/pkg/indicator/alma.go @@ -3,6 +3,7 @@ package indicator import ( "math" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -19,9 +20,9 @@ type ALMA struct { Sigma int // required: recommend to be 5 weight []float64 sum float64 - input []float64 - Values types.Float64Slice - UpdateCallbacks []func(value float64) + input []float64 + Values floats.Slice + UpdateCallbacks []func(value float64) } const MaxNumOfALMA = 5_000 diff --git a/pkg/indicator/atr.go b/pkg/indicator/atr.go index 77605ce2f..3a9b85365 100644 --- a/pkg/indicator/atr.go +++ b/pkg/indicator/atr.go @@ -4,6 +4,7 @@ import ( "math" "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +12,7 @@ import ( type ATR struct { types.SeriesBase types.IntervalWindow - PercentageVolatility types.Float64Slice + PercentageVolatility floats.Slice PreviousClose float64 RMA *RMA diff --git a/pkg/indicator/atrp.go b/pkg/indicator/atrp.go index 4d1d377b7..03c4f2071 100644 --- a/pkg/indicator/atrp.go +++ b/pkg/indicator/atrp.go @@ -4,6 +4,7 @@ import ( "math" "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -18,7 +19,7 @@ import ( type ATRP struct { types.SeriesBase types.IntervalWindow - PercentageVolatility types.Float64Slice + PercentageVolatility floats.Slice PreviousClose float64 RMA *RMA diff --git a/pkg/indicator/boll.go b/pkg/indicator/boll.go index f29fb714a..712481ffc 100644 --- a/pkg/indicator/boll.go +++ b/pkg/indicator/boll.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -29,8 +30,8 @@ type BOLL struct { SMA *SMA StdDev *StdDev - UpBand types.Float64Slice - DownBand types.Float64Slice + UpBand floats.Slice + DownBand floats.Slice EndTime time.Time diff --git a/pkg/indicator/cci.go b/pkg/indicator/cci.go index 6a75ff563..ee3190d0a 100644 --- a/pkg/indicator/cci.go +++ b/pkg/indicator/cci.go @@ -3,6 +3,7 @@ package indicator import ( "math" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -13,10 +14,10 @@ import ( type CCI struct { types.SeriesBase types.IntervalWindow - Input types.Float64Slice - TypicalPrice types.Float64Slice - MA types.Float64Slice - Values types.Float64Slice + Input floats.Slice + TypicalPrice floats.Slice + MA floats.Slice + Values floats.Slice UpdateCallbacks []func(value float64) } diff --git a/pkg/indicator/cma.go b/pkg/indicator/cma.go index d319bd41f..37dad3f8c 100644 --- a/pkg/indicator/cma.go +++ b/pkg/indicator/cma.go @@ -1,6 +1,7 @@ package indicator import ( + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -9,9 +10,9 @@ import ( //go:generate callbackgen -type CA type CA struct { types.SeriesBase - Interval types.Interval - Values types.Float64Slice - length float64 + Interval types.Interval + Values floats.Slice + length float64 UpdateCallbacks []func(value float64) } diff --git a/pkg/indicator/dema.go b/pkg/indicator/dema.go index 993d2c447..601cb8380 100644 --- a/pkg/indicator/dema.go +++ b/pkg/indicator/dema.go @@ -1,6 +1,7 @@ package indicator import ( + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +12,7 @@ import ( type DEMA struct { types.IntervalWindow types.SeriesBase - Values types.Float64Slice + Values floats.Slice a1 *EWMA a2 *EWMA diff --git a/pkg/indicator/drift.go b/pkg/indicator/drift.go index 1146bfddc..81633f399 100644 --- a/pkg/indicator/drift.go +++ b/pkg/indicator/drift.go @@ -3,6 +3,7 @@ package indicator import ( "math" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -13,9 +14,9 @@ import ( type Drift struct { types.SeriesBase types.IntervalWindow - chng *types.Queue - Values types.Float64Slice - MA types.UpdatableSeriesExtend + chng *types.Queue + Values floats.Slice + MA types.UpdatableSeriesExtend LastValue float64 UpdateCallbacks []func(value float64) diff --git a/pkg/indicator/ewma.go b/pkg/indicator/ewma.go index 50d0059ca..84b92fbb5 100644 --- a/pkg/indicator/ewma.go +++ b/pkg/indicator/ewma.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +16,7 @@ type EWMA struct { types.IntervalWindow types.SeriesBase - Values types.Float64Slice + Values floats.Slice EndTime time.Time updateCallbacks []func(value float64) diff --git a/pkg/indicator/fisher.go b/pkg/indicator/fisher.go index cd9ce4dac..98678afd8 100644 --- a/pkg/indicator/fisher.go +++ b/pkg/indicator/fisher.go @@ -3,6 +3,7 @@ package indicator import ( "math" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +12,7 @@ type FisherTransform struct { types.SeriesBase types.IntervalWindow prices *types.Queue - Values types.Float64Slice + Values floats.Slice UpdateCallbacks []func(value float64) } diff --git a/pkg/indicator/low.go b/pkg/indicator/low.go index c654a0f45..77d0457ea 100644 --- a/pkg/indicator/low.go +++ b/pkg/indicator/low.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +12,7 @@ type Low struct { types.IntervalWindow types.SeriesBase - Values types.Float64Slice + Values floats.Slice EndTime time.Time updateCallbacks []func(value float64) diff --git a/pkg/indicator/macd.go b/pkg/indicator/macd.go index 89ba97294..fe14a0efe 100644 --- a/pkg/indicator/macd.go +++ b/pkg/indicator/macd.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -19,11 +20,11 @@ type MACD struct { types.IntervalWindow // 9 ShortPeriod int // 12 LongPeriod int // 26 - Values types.Float64Slice - FastEWMA *EWMA + Values floats.Slice + FastEWMA *EWMA SlowEWMA *EWMA - SignalLine *EWMA - Histogram types.Float64Slice + SignalLine *EWMA + Histogram floats.Slice EndTime time.Time diff --git a/pkg/indicator/obv.go b/pkg/indicator/obv.go index 3fd663063..4d13fbfa2 100644 --- a/pkg/indicator/obv.go +++ b/pkg/indicator/obv.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -16,7 +17,7 @@ On-Balance Volume (OBV) Definition type OBV struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice PrePrice float64 EndTime time.Time diff --git a/pkg/indicator/obv_test.go b/pkg/indicator/obv_test.go index a70a0be4b..a4bc0ad21 100644 --- a/pkg/indicator/obv_test.go +++ b/pkg/indicator/obv_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) @@ -30,7 +31,7 @@ func Test_calculateOBV(t *testing.T) { name string kLines []types.KLine window int - want types.Float64Slice + want floats.Slice }{ { name: "trivial_case", @@ -38,13 +39,13 @@ func Test_calculateOBV(t *testing.T) { []fixedpoint.Value{fixedpoint.Zero}, []fixedpoint.Value{fixedpoint.One}, ), window: 0, - want: types.Float64Slice{1.0}, + want: floats.Slice{1.0}, }, { name: "easy_case", kLines: buildKLines(input1, input2), window: 0, - want: types.Float64Slice{3, 1, -1, 5}, + want: floats.Slice{3, 1, -1, 5}, }, } diff --git a/pkg/indicator/pivot.go b/pkg/indicator/pivot.go index e781475b2..8e027e410 100644 --- a/pkg/indicator/pivot.go +++ b/pkg/indicator/pivot.go @@ -6,6 +6,7 @@ import ( log "github.com/sirupsen/logrus" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -15,8 +16,8 @@ type Pivot struct { types.IntervalWindow // Values - Lows types.Float64Slice // higher low - Highs types.Float64Slice // lower high + Lows floats.Slice // higher low + Highs floats.Slice // lower high EndTime time.Time @@ -96,8 +97,8 @@ func calculatePivot(klines []types.KLine, window int, valLow KLineValueMapper, v return 0., 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var lows types.Float64Slice - var highs types.Float64Slice + var lows floats.Slice + var highs floats.Slice for _, k := range klines { lows.Push(valLow(k)) highs.Push(valHigh(k)) diff --git a/pkg/indicator/pivot_low.go b/pkg/indicator/pivot_low.go index 4603b1244..526b27adf 100644 --- a/pkg/indicator/pivot_low.go +++ b/pkg/indicator/pivot_low.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -12,8 +13,8 @@ type PivotLow struct { types.IntervalWindow - Lows types.Float64Slice - Values types.Float64Slice + Lows floats.Slice + Values floats.Slice EndTime time.Time updateCallbacks []func(value float64) @@ -62,7 +63,7 @@ func (inc *PivotLow) PushK(k types.KLine) { inc.EmitUpdate(inc.Last()) } -func calculatePivotF(values types.Float64Slice, left, right int, f func(a, pivot float64) bool) (float64, bool) { +func calculatePivotF(values floats.Slice, left, right int, f func(a, pivot float64) bool) (float64, bool) { length := len(values) if right == 0 { @@ -91,13 +92,13 @@ func calculatePivotF(values types.Float64Slice, left, right int, f func(a, pivot return val, true } -func calculatePivotHigh(highs types.Float64Slice, left, right int) (float64, bool) { +func calculatePivotHigh(highs floats.Slice, left, right int) (float64, bool) { return calculatePivotF(highs, left, right, func(a, pivot float64) bool { return a < pivot }) } -func calculatePivotLow(lows types.Float64Slice, left, right int) (float64, bool) { +func calculatePivotLow(lows floats.Slice, left, right int) (float64, bool) { return calculatePivotF(lows, left, right, func(a, pivot float64) bool { return a > pivot }) diff --git a/pkg/indicator/rma.go b/pkg/indicator/rma.go index 413c51bd9..fa47d94d9 100644 --- a/pkg/indicator/rma.go +++ b/pkg/indicator/rma.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +15,7 @@ type RMA struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice EndTime time.Time counter int diff --git a/pkg/indicator/rsi.go b/pkg/indicator/rsi.go index 286b7b16e..92060f455 100644 --- a/pkg/indicator/rsi.go +++ b/pkg/indicator/rsi.go @@ -4,6 +4,7 @@ import ( "math" "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -16,8 +17,8 @@ https://www.investopedia.com/terms/r/rsi.asp type RSI struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice - Prices types.Float64Slice + Values floats.Slice + Prices floats.Slice PreviousAvgLoss float64 PreviousAvgGain float64 diff --git a/pkg/indicator/rsi_test.go b/pkg/indicator/rsi_test.go index 3b96fd433..36322c9e1 100644 --- a/pkg/indicator/rsi_test.go +++ b/pkg/indicator/rsi_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) @@ -26,13 +27,13 @@ func Test_calculateRSI(t *testing.T) { name string kLines []types.KLine window int - want types.Float64Slice + want floats.Slice }{ { name: "RSI", kLines: buildKLines(values), window: 14, - want: types.Float64Slice{ + want: floats.Slice{ 70.46413502109704, 66.24961855355505, 66.48094183471265, diff --git a/pkg/indicator/sma.go b/pkg/indicator/sma.go index a6a93089c..279e11280 100644 --- a/pkg/indicator/sma.go +++ b/pkg/indicator/sma.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +15,7 @@ const MaxNumOfSMATruncateSize = 100 type SMA struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice rawValues *types.Queue EndTime time.Time diff --git a/pkg/indicator/ssf.go b/pkg/indicator/ssf.go index a055dd059..9458e16e8 100644 --- a/pkg/indicator/ssf.go +++ b/pkg/indicator/ssf.go @@ -3,6 +3,7 @@ package indicator import ( "math" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -27,7 +28,7 @@ type SSF struct { c2 float64 c3 float64 c4 float64 - Values types.Float64Slice + Values floats.Slice UpdateCallbacks []func(value float64) } @@ -45,7 +46,7 @@ func (inc *SSF) Update(value float64) { inc.c3 = -c0 * (1. + b0) inc.c2 = c0 + b0 inc.c1 = 1. - inc.c2 - inc.c3 - inc.c4 - inc.Values = types.Float64Slice{} + inc.Values = floats.Slice{} } result := inc.c1*value + @@ -61,7 +62,7 @@ func (inc *SSF) Update(value float64) { inc.c3 = -a0 * a0 inc.c2 = 2. * a0 * math.Cos(x) inc.c1 = 1. - inc.c2 - inc.c3 - inc.Values = types.Float64Slice{} + inc.Values = floats.Slice{} } result := inc.c1*value + inc.c2*inc.Values.Index(0) + diff --git a/pkg/indicator/stddev.go b/pkg/indicator/stddev.go index 3c6a5bdca..8811fb208 100644 --- a/pkg/indicator/stddev.go +++ b/pkg/indicator/stddev.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -10,7 +11,7 @@ import ( type StdDev struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice rawValues *types.Queue EndTime time.Time diff --git a/pkg/indicator/stoch.go b/pkg/indicator/stoch.go index 2066bbf6b..aa86fea8b 100644 --- a/pkg/indicator/stoch.go +++ b/pkg/indicator/stoch.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -17,11 +18,11 @@ Stochastic Oscillator //go:generate callbackgen -type STOCH type STOCH struct { types.IntervalWindow - K types.Float64Slice - D types.Float64Slice + K floats.Slice + D floats.Slice - HighValues types.Float64Slice - LowValues types.Float64Slice + HighValues floats.Slice + LowValues floats.Slice EndTime time.Time UpdateCallbacks []func(k float64, d float64) diff --git a/pkg/indicator/supertrend.go b/pkg/indicator/supertrend.go index 66dd3bcd9..6d15e19a2 100644 --- a/pkg/indicator/supertrend.go +++ b/pkg/indicator/supertrend.go @@ -6,6 +6,7 @@ import ( "github.com/sirupsen/logrus" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -19,7 +20,7 @@ type Supertrend struct { AverageTrueRange *ATR - trendPrices types.Float64Slice + trendPrices floats.Slice closePrice float64 previousClosePrice float64 diff --git a/pkg/indicator/tema.go b/pkg/indicator/tema.go index 60affd0e5..348177524 100644 --- a/pkg/indicator/tema.go +++ b/pkg/indicator/tema.go @@ -1,6 +1,7 @@ package indicator import ( + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +12,7 @@ import ( type TEMA struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice A1 *EWMA A2 *EWMA A3 *EWMA diff --git a/pkg/indicator/vidya.go b/pkg/indicator/vidya.go index f29769c49..023e39a66 100644 --- a/pkg/indicator/vidya.go +++ b/pkg/indicator/vidya.go @@ -3,6 +3,7 @@ package indicator import ( "math" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -12,8 +13,8 @@ import ( type VIDYA struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice - input types.Float64Slice + Values floats.Slice + input floats.Slice updateCallbacks []func(value float64) } diff --git a/pkg/indicator/volatility.go b/pkg/indicator/volatility.go index a87cc022a..6b3dcd7cb 100644 --- a/pkg/indicator/volatility.go +++ b/pkg/indicator/volatility.go @@ -7,6 +7,7 @@ import ( log "github.com/sirupsen/logrus" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -19,7 +20,7 @@ const MaxNumOfVOLTruncateSize = 100 type Volatility struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice EndTime time.Time UpdateCallbacks []func(value float64) diff --git a/pkg/indicator/vwap.go b/pkg/indicator/vwap.go index c040e866c..5cb36c847 100644 --- a/pkg/indicator/vwap.go +++ b/pkg/indicator/vwap.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -19,9 +20,9 @@ Volume-Weighted Average Price (VWAP) Explained type VWAP struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice - Prices types.Float64Slice - Volumes types.Float64Slice + Values floats.Slice + Prices floats.Slice + Volumes floats.Slice WeightedSum float64 VolumeSum float64 diff --git a/pkg/indicator/vwma.go b/pkg/indicator/vwma.go index 263c5fb5a..9998bbc49 100644 --- a/pkg/indicator/vwma.go +++ b/pkg/indicator/vwma.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -21,7 +22,7 @@ type VWMA struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice PriceVolumeSMA *SMA VolumeSMA *SMA diff --git a/pkg/indicator/wdrift.go b/pkg/indicator/wdrift.go index 01a3ca753..7618f2c7c 100644 --- a/pkg/indicator/wdrift.go +++ b/pkg/indicator/wdrift.go @@ -3,6 +3,7 @@ package indicator import ( "math" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -13,9 +14,9 @@ import ( type WeightedDrift struct { types.SeriesBase types.IntervalWindow - chng *types.Queue - Values types.Float64Slice - MA types.UpdatableSeriesExtend + chng *types.Queue + Values floats.Slice + MA types.UpdatableSeriesExtend Weight *types.Queue LastValue float64 UpdateCallbacks []func(value float64) diff --git a/pkg/indicator/wwma.go b/pkg/indicator/wwma.go index bc5ab5a67..0dbc67ca1 100644 --- a/pkg/indicator/wwma.go +++ b/pkg/indicator/wwma.go @@ -3,6 +3,7 @@ package indicator import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -17,7 +18,7 @@ const MaxNumOfWWMATruncateSize = 100 type WWMA struct { types.SeriesBase types.IntervalWindow - Values types.Float64Slice + Values floats.Slice LastOpenTime time.Time UpdateCallbacks []func(value float64) diff --git a/pkg/indicator/zlema.go b/pkg/indicator/zlema.go index 482ecd09d..3f6f4b08f 100644 --- a/pkg/indicator/zlema.go +++ b/pkg/indicator/zlema.go @@ -1,6 +1,7 @@ package indicator import ( + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +13,7 @@ type ZLEMA struct { types.SeriesBase types.IntervalWindow - data types.Float64Slice + data floats.Slice zlema *EWMA lag int diff --git a/pkg/strategy/drift/strategy.go b/pkg/strategy/drift/strategy.go index 73600240d..899044b46 100644 --- a/pkg/strategy/drift/strategy.go +++ b/pkg/strategy/drift/strategy.go @@ -15,6 +15,7 @@ import ( "github.com/wcharczuk/go-chart/v2" "github.com/c9s/bbgo/pkg/bbgo" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/interact" @@ -647,10 +648,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se method.Bind(session, s.GeneralOrderExecutor) } - profit := types.Float64Slice{1., 1.} + profit := floats.Slice{1., 1.} price, _ := s.Session.LastPrice(s.Symbol) initAsset := s.CalcAssetValue(price).Float64() - cumProfit := types.Float64Slice{initAsset, initAsset} + cumProfit := floats.Slice{initAsset, initAsset} modify := func(p float64) float64 { return p } diff --git a/pkg/strategy/factorzoo/factors/momentum.go b/pkg/strategy/factorzoo/factors/momentum.go index 55d6e94d8..c9dc34877 100644 --- a/pkg/strategy/factorzoo/factors/momentum.go +++ b/pkg/strategy/factorzoo/factors/momentum.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" ) @@ -18,7 +19,7 @@ type MOM struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice LastValue float64 opens *types.Queue diff --git a/pkg/strategy/factorzoo/factors/price_mean_reversion.go b/pkg/strategy/factorzoo/factors/price_mean_reversion.go index 9b1ad8846..2d2bd5ce8 100644 --- a/pkg/strategy/factorzoo/factors/price_mean_reversion.go +++ b/pkg/strategy/factorzoo/factors/price_mean_reversion.go @@ -3,9 +3,11 @@ package factorzoo import ( "time" + "gonum.org/v1/gonum/stat" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "gonum.org/v1/gonum/stat" ) // price mean reversion @@ -17,8 +19,8 @@ type PMR struct { types.IntervalWindow types.SeriesBase - Values types.Float64Slice - SMA *indicator.SMA + Values floats.Slice + SMA *indicator.SMA EndTime time.Time updateCallbacks []func(value float64) diff --git a/pkg/strategy/factorzoo/factors/price_volume_divergence.go b/pkg/strategy/factorzoo/factors/price_volume_divergence.go index 033123b5f..54b07a265 100644 --- a/pkg/strategy/factorzoo/factors/price_volume_divergence.go +++ b/pkg/strategy/factorzoo/factors/price_volume_divergence.go @@ -3,9 +3,11 @@ package factorzoo import ( "time" + "gonum.org/v1/gonum/stat" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "gonum.org/v1/gonum/stat" ) // price volume divergence @@ -21,8 +23,8 @@ type PVD struct { types.IntervalWindow types.SeriesBase - Values types.Float64Slice - Prices *types.Queue + Values floats.Slice + Prices *types.Queue Volumes *types.Queue EndTime time.Time diff --git a/pkg/strategy/factorzoo/factors/return_rate.go b/pkg/strategy/factorzoo/factors/return_rate.go index 29efc9d5e..057f2ac5c 100644 --- a/pkg/strategy/factorzoo/factors/return_rate.go +++ b/pkg/strategy/factorzoo/factors/return_rate.go @@ -3,6 +3,7 @@ package factorzoo import ( "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +16,7 @@ type RR struct { types.SeriesBase prices *types.Queue - Values types.Float64Slice + Values floats.Slice EndTime time.Time updateCallbacks []func(value float64) diff --git a/pkg/strategy/factorzoo/factors/volume_momentum.go b/pkg/strategy/factorzoo/factors/volume_momentum.go index ac2c65819..602065273 100644 --- a/pkg/strategy/factorzoo/factors/volume_momentum.go +++ b/pkg/strategy/factorzoo/factors/volume_momentum.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" ) @@ -18,7 +19,7 @@ type VMOM struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice LastValue float64 volumes *types.Queue diff --git a/pkg/strategy/factorzoo/linear_regression.go b/pkg/strategy/factorzoo/linear_regression.go index d3986a34e..80c84e687 100644 --- a/pkg/strategy/factorzoo/linear_regression.go +++ b/pkg/strategy/factorzoo/linear_regression.go @@ -4,6 +4,7 @@ import ( "context" "github.com/c9s/bbgo/pkg/bbgo" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/strategy/factorzoo/factors" @@ -76,7 +77,7 @@ func (s *Linear) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.General // take past window days' values to predict future return // (e.g., 5 here in default configuration file) - a := []types.Float64Slice{ + a := []floats.Slice{ s.divergence.Values[len(s.divergence.Values)-s.Window-2 : len(s.divergence.Values)-2], s.reversion.Values[len(s.reversion.Values)-s.Window-2 : len(s.reversion.Values)-2], s.drift.Values[len(s.drift.Values)-s.Window-2 : len(s.drift.Values)-2], @@ -87,7 +88,7 @@ func (s *Linear) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.General // factors array from day -4 to day 0, [[0.1, 0.2, 0.35, 0.3 , 0.25], [1.1, -0.2, 1.35, -0.3 , -0.25], ...] // the binary(+/-) daily return rate from day -3 to day 1, [0, 1, 1, 0, 0] // then we take the latest available factors array into linear regression model - b := []types.Float64Slice{filter(s.irr.Values[len(s.irr.Values)-s.Window-1:len(s.irr.Values)-1], binary)} + b := []floats.Slice{filter(s.irr.Values[len(s.irr.Values)-s.Window-1:len(s.irr.Values)-1], binary)} var x []types.Series var y []types.Series diff --git a/pkg/strategy/fmaker/A18.go b/pkg/strategy/fmaker/A18.go index 71a671bbb..6e7e603a0 100644 --- a/pkg/strategy/fmaker/A18.go +++ b/pkg/strategy/fmaker/A18.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type A18 @@ -12,7 +14,7 @@ type A18 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -76,7 +78,7 @@ func calculateA18(klines []types.KLine, valClose KLineValueMapper) (float64, err if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var closes types.Float64Slice + var closes floats.Slice for _, k := range klines { closes.Push(valClose(k)) diff --git a/pkg/strategy/fmaker/A2.go b/pkg/strategy/fmaker/A2.go index 4946bc28d..0c9cc4b3b 100644 --- a/pkg/strategy/fmaker/A2.go +++ b/pkg/strategy/fmaker/A2.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type A2 @@ -12,7 +14,7 @@ type A2 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -76,9 +78,9 @@ func calculateA2(klines []types.KLine, valLow KLineValueMapper, valHigh KLineVal if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var lows types.Float64Slice - var highs types.Float64Slice - var closes types.Float64Slice + var lows floats.Slice + var highs floats.Slice + var closes floats.Slice for _, k := range klines { lows.Push(valLow(k)) diff --git a/pkg/strategy/fmaker/A3.go b/pkg/strategy/fmaker/A3.go index e08b6bf60..945b06b67 100644 --- a/pkg/strategy/fmaker/A3.go +++ b/pkg/strategy/fmaker/A3.go @@ -2,10 +2,12 @@ package fmaker import ( "fmt" - "github.com/c9s/bbgo/pkg/indicator" - "github.com/c9s/bbgo/pkg/types" "math" "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" + "github.com/c9s/bbgo/pkg/indicator" + "github.com/c9s/bbgo/pkg/types" ) //go:generate callbackgen -type A3 @@ -13,7 +15,7 @@ type A3 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -77,9 +79,9 @@ func calculateA3(klines []types.KLine, valLow KLineValueMapper, valHigh KLineVal if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var lows types.Float64Slice - var highs types.Float64Slice - var closes types.Float64Slice + var lows floats.Slice + var highs floats.Slice + var closes floats.Slice for _, k := range klines { lows.Push(valLow(k)) diff --git a/pkg/strategy/fmaker/A34.go b/pkg/strategy/fmaker/A34.go index ba5484485..eb01799e3 100644 --- a/pkg/strategy/fmaker/A34.go +++ b/pkg/strategy/fmaker/A34.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type A34 @@ -12,7 +14,7 @@ type A34 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -75,7 +77,7 @@ func calculateA34(klines []types.KLine, valClose KLineValueMapper) (float64, err if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var closes types.Float64Slice + var closes floats.Slice for _, k := range klines { closes.Push(valClose(k)) diff --git a/pkg/strategy/fmaker/R.go b/pkg/strategy/fmaker/R.go index 4647ab153..d3aa0eca2 100644 --- a/pkg/strategy/fmaker/R.go +++ b/pkg/strategy/fmaker/R.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) var zeroTime time.Time @@ -16,7 +18,7 @@ type R struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -79,8 +81,8 @@ func calculateR(klines []types.KLine, valOpen KLineValueMapper, valClose KLineVa if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var opens types.Float64Slice - var closes types.Float64Slice + var opens floats.Slice + var closes floats.Slice for _, k := range klines { opens.Push(valOpen(k)) diff --git a/pkg/strategy/fmaker/S0.go b/pkg/strategy/fmaker/S0.go index 2f1c943bb..9c934ccd2 100644 --- a/pkg/strategy/fmaker/S0.go +++ b/pkg/strategy/fmaker/S0.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type S0 @@ -12,7 +14,7 @@ type S0 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -75,13 +77,13 @@ func calculateS0(klines []types.KLine, valClose KLineValueMapper) (float64, erro if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var closes types.Float64Slice + var closes floats.Slice for _, k := range klines { closes.Push(valClose(k)) } - sma := types.Float64Slice.Sum(closes[len(closes)-window:len(closes)-1]) / float64(window) + sma := floats.Slice.Sum(closes[len(closes)-window:len(closes)-1]) / float64(window) alpha := sma / closes.Last() return alpha, nil diff --git a/pkg/strategy/fmaker/S1.go b/pkg/strategy/fmaker/S1.go index 75d0888d5..498efec63 100644 --- a/pkg/strategy/fmaker/S1.go +++ b/pkg/strategy/fmaker/S1.go @@ -5,6 +5,7 @@ import ( "math" "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +13,7 @@ import ( //go:generate callbackgen -type S1 type S1 struct { types.IntervalWindow - Values types.Float64Slice + Values floats.Slice EndTime time.Time UpdateCallbacks []func(value float64) diff --git a/pkg/strategy/fmaker/S2.go b/pkg/strategy/fmaker/S2.go index 7d21fea7f..960b3c5a8 100644 --- a/pkg/strategy/fmaker/S2.go +++ b/pkg/strategy/fmaker/S2.go @@ -5,6 +5,7 @@ import ( "math" "time" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +13,7 @@ import ( //go:generate callbackgen -type S2 type S2 struct { types.IntervalWindow - Values types.Float64Slice + Values floats.Slice EndTime time.Time UpdateCallbacks []func(value float64) diff --git a/pkg/strategy/fmaker/S3.go b/pkg/strategy/fmaker/S3.go index 195db9bc4..238cc62ea 100644 --- a/pkg/strategy/fmaker/S3.go +++ b/pkg/strategy/fmaker/S3.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type S3 @@ -12,7 +14,7 @@ type S3 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -75,8 +77,8 @@ func calculateS3(klines []types.KLine, valClose KLineValueMapper, valOpen KLineV if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var closes types.Float64Slice - var opens types.Float64Slice + var closes floats.Slice + var opens floats.Slice for _, k := range klines { closes.Push(valClose(k)) diff --git a/pkg/strategy/fmaker/S4.go b/pkg/strategy/fmaker/S4.go index d2953304f..9d122c473 100644 --- a/pkg/strategy/fmaker/S4.go +++ b/pkg/strategy/fmaker/S4.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type S4 @@ -12,7 +14,7 @@ type S4 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -75,7 +77,7 @@ func calculateS4(klines []types.KLine, valClose KLineValueMapper) (float64, erro if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var closes types.Float64Slice + var closes floats.Slice for _, k := range klines { closes.Push(valClose(k)) diff --git a/pkg/strategy/fmaker/S5.go b/pkg/strategy/fmaker/S5.go index 82c117e64..046733b4f 100644 --- a/pkg/strategy/fmaker/S5.go +++ b/pkg/strategy/fmaker/S5.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type S5 @@ -12,7 +14,7 @@ type S5 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -75,7 +77,7 @@ func calculateS5(klines []types.KLine, valVolume KLineValueMapper) (float64, err if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var volumes types.Float64Slice + var volumes floats.Slice for _, k := range klines { volumes.Push(valVolume(k)) diff --git a/pkg/strategy/fmaker/S6.go b/pkg/strategy/fmaker/S6.go index 2b6ab4ead..4bb20b158 100644 --- a/pkg/strategy/fmaker/S6.go +++ b/pkg/strategy/fmaker/S6.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type S6 @@ -12,7 +14,7 @@ type S6 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -75,10 +77,10 @@ func calculateS6(klines []types.KLine, valHigh KLineValueMapper, valLow KLineVal if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var highs types.Float64Slice - var lows types.Float64Slice - var closes types.Float64Slice - var volumes types.Float64Slice + var highs floats.Slice + var lows floats.Slice + var closes floats.Slice + var volumes floats.Slice for _, k := range klines { highs.Push(valHigh(k)) diff --git a/pkg/strategy/fmaker/S7.go b/pkg/strategy/fmaker/S7.go index 2431f7edc..7000e6897 100644 --- a/pkg/strategy/fmaker/S7.go +++ b/pkg/strategy/fmaker/S7.go @@ -2,9 +2,11 @@ package fmaker import ( "fmt" + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) //go:generate callbackgen -type S7 @@ -12,7 +14,7 @@ type S7 struct { types.IntervalWindow // Values - Values types.Float64Slice + Values floats.Slice EndTime time.Time @@ -75,8 +77,8 @@ func calculateS7(klines []types.KLine, valOpen KLineValueMapper, valClose KLineV if length == 0 || length < window { return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window) } - var opens types.Float64Slice - var closes types.Float64Slice + var opens floats.Slice + var closes floats.Slice for _, k := range klines { opens.Push(valOpen(k)) diff --git a/pkg/strategy/fmaker/strategy.go b/pkg/strategy/fmaker/strategy.go index c6f7068be..9a1c1c5c4 100644 --- a/pkg/strategy/fmaker/strategy.go +++ b/pkg/strategy/fmaker/strategy.go @@ -10,6 +10,7 @@ import ( "gonum.org/v1/gonum/floats" "github.com/c9s/bbgo/pkg/bbgo" + floats2 "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) @@ -322,7 +323,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se a34 := s.A34.Values[len(s.A34.Values)-i-outlook] ret := s.R.Values[len(s.R.Values)-i] - rdps = append(rdps, regression.DataPoint(ret, types.Float64Slice{s0, s1, s2, s4, s5, s6, s7, a2, a3, a18, a34})) + rdps = append(rdps, regression.DataPoint(ret, floats2.Slice{s0, s1, s2, s4, s5, s6, s7, a2, a3, a18, a34})) } // for i := 40; i > 20; i-- { // s0 := preprocessing(s.S0.Values[len(s.S0.Values)-i : len(s.S0.Values)-i+20-outlook]) @@ -341,7 +342,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se // } r.Train(rdps...) r.Run() - er, _ := r.Predict(types.Float64Slice{s.S0.Last(), s.S1.Last(), s.S2.Last(), s.S4.Last(), s.S5.Last(), s.S6.Last(), s.S7.Last(), s.A2.Last(), s.A3.Last(), s.A18.Last(), s.A34.Last()}) + er, _ := r.Predict(floats2.Slice{s.S0.Last(), s.S1.Last(), s.S2.Last(), s.S4.Last(), s.S5.Last(), s.S6.Last(), s.S7.Last(), s.A2.Last(), s.A3.Last(), s.A18.Last(), s.A34.Last()}) log.Infof("Expected Return Rate: %f", er) q := new(regression.Regression) @@ -377,7 +378,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se ret := s.R.Values[len(s.R.Values)-i] qty := math.Abs(ret) - qdps = append(qdps, regression.DataPoint(qty, types.Float64Slice{s0, s1, s2, s4, s5, s6, s7, a2, a3, a18, a34})) + qdps = append(qdps, regression.DataPoint(qty, floats2.Slice{s0, s1, s2, s4, s5, s6, s7, a2, a3, a18, a34})) } // for i := 40; i > 20; i-- { // s0 := preprocessing(s.S0.Values[len(s.S0.Values)-i : len(s.S0.Values)-i+20-outlook]) @@ -416,7 +417,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se // a34 := preprocessing(s.A18.Values[len(s.A18.Values)-20 : len(s.A18.Values)-1-outlook]) // er, _ := r.Predict(types.Float64Slice{s0, s1, s2, s4, s5, a2, a3, a18, a34}) // eq, _ := q.Predict(types.Float64Slice{s0, s1, s2, s4, s5, a2, a3, a18, a34}) - eq, _ := q.Predict(types.Float64Slice{s.S0.Last(), s.S1.Last(), s.S2.Last(), s.S4.Last(), s.S5.Last(), s.S6.Last(), s.S7.Last(), s.A2.Last(), s.A3.Last(), s.A18.Last(), s.A34.Last(), er}) + eq, _ := q.Predict(floats2.Slice{s.S0.Last(), s.S1.Last(), s.S2.Last(), s.S4.Last(), s.S5.Last(), s.S6.Last(), s.S7.Last(), s.A2.Last(), s.A3.Last(), s.A18.Last(), s.A34.Last(), er}) log.Infof("Expected Order Quantity: %f", eq) // if float64(s.Position.GetBase().Sign())*er < 0 { // s.ClosePosition(ctx, fixedpoint.One, kline.Close) diff --git a/pkg/strategy/marketcap/strategy.go b/pkg/strategy/marketcap/strategy.go index bf809e98b..587dc48b5 100644 --- a/pkg/strategy/marketcap/strategy.go +++ b/pkg/strategy/marketcap/strategy.go @@ -9,6 +9,7 @@ import ( "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/datasource/glassnode" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) @@ -171,7 +172,7 @@ func (s *Strategy) generateSubmitOrders(ctx context.Context, session *bbgo.Excha } func (s *Strategy) getTargetWeights(ctx context.Context) types.ValueMap { - m := types.FloatMap{} + m := floats.Map{} // get market cap values for _, currency := range s.TargetCurrencies { diff --git a/pkg/strategy/supertrend/linreg.go b/pkg/strategy/supertrend/linreg.go index 22541c1bb..0ead276e1 100644 --- a/pkg/strategy/supertrend/linreg.go +++ b/pkg/strategy/supertrend/linreg.go @@ -1,9 +1,11 @@ package supertrend import ( + "time" + + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "time" ) // LinReg is Linear Regression baseline @@ -11,8 +13,8 @@ type LinReg struct { types.SeriesBase types.IntervalWindow // Values are the slopes of linear regression baseline - Values types.Float64Slice - klines types.KLineWindow + Values floats.Slice + klines types.KLineWindow EndTime time.Time } diff --git a/pkg/strategy/supertrend/strategy.go b/pkg/strategy/supertrend/strategy.go index 88a88822b..bc4f632dc 100644 --- a/pkg/strategy/supertrend/strategy.go +++ b/pkg/strategy/supertrend/strategy.go @@ -3,11 +3,13 @@ package supertrend import ( "context" "fmt" - "github.com/c9s/bbgo/pkg/data/tsv" - "github.com/c9s/bbgo/pkg/risk" "os" "sync" + "github.com/c9s/bbgo/pkg/data/tsv" + "github.com/c9s/bbgo/pkg/datatype/floats" + "github.com/c9s/bbgo/pkg/risk" + "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -48,25 +50,25 @@ type AccumulatedProfitReport struct { // Accumulated profit accumulatedProfit fixedpoint.Value - accumulatedProfitPerDay types.Float64Slice + accumulatedProfitPerDay floats.Slice previousAccumulatedProfit fixedpoint.Value // Accumulated profit MA accumulatedProfitMA *indicator.SMA - accumulatedProfitMAPerDay types.Float64Slice + accumulatedProfitMAPerDay floats.Slice // Daily profit - dailyProfit types.Float64Slice + dailyProfit floats.Slice // Accumulated fee accumulatedFee fixedpoint.Value - accumulatedFeePerDay types.Float64Slice + accumulatedFeePerDay floats.Slice // Win ratio - winRatioPerDay types.Float64Slice + winRatioPerDay floats.Slice // Profit factor - profitFactorPerDay types.Float64Slice + profitFactorPerDay floats.Slice } func (r *AccumulatedProfitReport) Initialize() { diff --git a/pkg/types/float_map.go b/pkg/types/float_map.go index 749126073..8a05391c9 100644 --- a/pkg/types/float_map.go +++ b/pkg/types/float_map.go @@ -1,42 +1,5 @@ package types -type FloatMap map[string]float64 +import "github.com/c9s/bbgo/pkg/datatype/floats" -func (m FloatMap) Sum() float64 { - sum := 0.0 - for _, v := range m { - sum += v - } - return sum -} - -func (m FloatMap) MulScalar(x float64) FloatMap { - o := FloatMap{} - for k, v := range m { - o[k] = v * x - } - - return o -} -func (m FloatMap) DivScalar(x float64) FloatMap { - o := FloatMap{} - for k, v := range m { - o[k] = v / x - } - - return o -} - -func (m FloatMap) Normalize() FloatMap { - sum := m.Sum() - if sum == 0 { - panic("zero sum") - } - - o := FloatMap{} - for k, v := range m { - o[k] = v / sum - } - - return o -} +var _ Series = floats.Slice([]float64{}).Addr() diff --git a/pkg/types/float_slice.go b/pkg/types/float_slice.go deleted file mode 100644 index 3632d77b8..000000000 --- a/pkg/types/float_slice.go +++ /dev/null @@ -1,148 +0,0 @@ -package types - -import ( - "math" - - "gonum.org/v1/gonum/floats" -) - -type Float64Slice []float64 - -func (s *Float64Slice) Push(v float64) { - *s = append(*s, v) -} - -func (s *Float64Slice) Update(v float64) { - *s = append(*s, v) -} - -func (s *Float64Slice) Pop(i int64) (v float64) { - v = (*s)[i] - *s = append((*s)[:i], (*s)[i+1:]...) - return v -} - -func (s Float64Slice) Max() float64 { - return floats.Max(s) -} - -func (s Float64Slice) Min() float64 { - return floats.Min(s) -} - -func (s Float64Slice) Sum() (sum float64) { - return floats.Sum(s) -} - -func (s Float64Slice) Mean() (mean float64) { - length := len(s) - if length == 0 { - panic("zero length slice") - } - return s.Sum() / float64(length) -} - -func (s Float64Slice) Tail(size int) Float64Slice { - length := len(s) - if length <= size { - win := make(Float64Slice, length) - copy(win, s) - return win - } - - win := make(Float64Slice, size) - copy(win, s[length-size:]) - return win -} - -func (s Float64Slice) Diff() (values Float64Slice) { - for i, v := range s { - if i == 0 { - values.Push(0) - continue - } - values.Push(v - s[i-1]) - } - return values -} - -func (s Float64Slice) PositiveValuesOrZero() (values Float64Slice) { - for _, v := range s { - values.Push(math.Max(v, 0)) - } - return values -} - -func (s Float64Slice) NegativeValuesOrZero() (values Float64Slice) { - for _, v := range s { - values.Push(math.Min(v, 0)) - } - return values -} - -func (s Float64Slice) Abs() (values Float64Slice) { - for _, v := range s { - values.Push(math.Abs(v)) - } - return values -} - -func (s Float64Slice) MulScalar(x float64) (values Float64Slice) { - for _, v := range s { - values.Push(v * x) - } - return values -} - -func (s Float64Slice) DivScalar(x float64) (values Float64Slice) { - for _, v := range s { - values.Push(v / x) - } - return values -} - -func (s Float64Slice) Mul(other Float64Slice) (values Float64Slice) { - if len(s) != len(other) { - panic("slice lengths do not match") - } - - for i, v := range s { - values.Push(v * other[i]) - } - - return values -} - -func (s Float64Slice) Dot(other Float64Slice) float64 { - return floats.Dot(s, other) -} - -func (s Float64Slice) Normalize() Float64Slice { - return s.DivScalar(s.Sum()) -} - -func (a *Float64Slice) Last() float64 { - length := len(*a) - if length > 0 { - return (*a)[length-1] - } - return 0.0 -} - -func (a *Float64Slice) Index(i int) float64 { - length := len(*a) - if length-i <= 0 || i < 0 { - return 0.0 - } - return (*a)[length-i-1] -} - -func (a *Float64Slice) Length() int { - return len(*a) -} - -func (a Float64Slice) Addr() *Float64Slice { - return &a -} - -var _ Series = Float64Slice([]float64{}).Addr() diff --git a/pkg/types/indicator.go b/pkg/types/indicator.go index ca1822135..f7d3e1f63 100644 --- a/pkg/types/indicator.go +++ b/pkg/types/indicator.go @@ -8,6 +8,8 @@ import ( "github.com/wcharczuk/go-chart/v2" "gonum.org/v1/gonum/stat" + + "github.com/c9s/bbgo/pkg/datatype/floats" ) // Super basic Series type that simply holds the float64 data @@ -94,7 +96,7 @@ type SeriesExtend interface { Mul(b interface{}) SeriesExtend Dot(b interface{}, limit ...int) float64 Array(limit ...int) (result []float64) - Reverse(limit ...int) (result Float64Slice) + Reverse(limit ...int) (result floats.Slice) Change(offset ...int) SeriesExtend PercentageChange(offset ...int) SeriesExtend Stdev(params ...int) float64 @@ -649,7 +651,7 @@ func Array(a Series, limit ...int) (result []float64) { // the then reuse the result in multiple places (so that no recalculation will be triggered) // // notice that the return type is a Float64Slice, which implements the Series interface -func Reverse(a Series, limit ...int) (result Float64Slice) { +func Reverse(a Series, limit ...int) (result floats.Slice) { l := a.Length() if len(limit) > 0 && l > limit[0] { l = limit[0] diff --git a/pkg/types/indicator_test.go b/pkg/types/indicator_test.go index 5f103114d..d14de03c6 100644 --- a/pkg/types/indicator_test.go +++ b/pkg/types/indicator_test.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/wcharczuk/go-chart/v2" "gonum.org/v1/gonum/stat" + + "github.com/c9s/bbgo/pkg/datatype/floats" ) func TestFloat(t *testing.T) { @@ -19,7 +21,7 @@ func TestFloat(t *testing.T) { func TestNextCross(t *testing.T) { var a Series = NumberSeries(1.2) - var b Series = &Float64Slice{100., 80., 60.} + var b Series = &floats.Slice{100., 80., 60.} // index 2 1 0 // predicted 40 20 0 // offset 1 2 3 @@ -31,8 +33,8 @@ func TestNextCross(t *testing.T) { } func TestFloat64Slice(t *testing.T) { - var a = Float64Slice{1.0, 2.0, 3.0} - var b = Float64Slice{1.0, 2.0, 3.0} + var a = floats.Slice{1.0, 2.0, 3.0} + var b = floats.Slice{1.0, 2.0, 3.0} var c Series = Minus(&a, &b) a = append(a, 4.0) b = append(b, 3.0) @@ -51,8 +53,8 @@ print(s1.corr(s2, method='kendall')) print(s1.rank()) */ func TestCorr(t *testing.T) { - var a = Float64Slice{.2, .0, .6, .2} - var b = Float64Slice{.3, .6, .0, .1} + var a = floats.Slice{.2, .0, .6, .2} + var b = floats.Slice{.3, .6, .0, .1} corr := Correlation(&a, &b, 4, Pearson) assert.InDelta(t, corr, -0.8510644, 0.001) out := Rank(&a, 4) @@ -71,8 +73,8 @@ s2 = pd.Series([.3, .6, .0, .1]) print(s1.cov(s2, ddof=0)) */ func TestCov(t *testing.T) { - var a = Float64Slice{.2, .0, .6, .2} - var b = Float64Slice{.3, .6, .0, .1} + var a = floats.Slice{.2, .0, .6, .2} + var b = floats.Slice{.3, .6, .0, .1} cov := Covariance(&a, &b, 4) assert.InDelta(t, cov, -0.042499, 0.001) } @@ -85,37 +87,37 @@ s1 = pd.Series([.2, 0., .6, .2, .2]) print(s1.skew()) */ func TestSkew(t *testing.T) { - var a = Float64Slice{.2, .0, .6, .2} + var a = floats.Slice{.2, .0, .6, .2} sk := Skew(&a, 4) assert.InDelta(t, sk, 1.129338, 0.001) } func TestEntropy(t *testing.T) { - var a = Float64Slice{.2, .0, .6, .2} + var a = floats.Slice{.2, .0, .6, .2} e := stat.Entropy(a) assert.InDelta(t, e, Entropy(&a, a.Length()), 0.0001) } func TestCrossEntropy(t *testing.T) { - var a = Float64Slice{.2, .0, .6, .2} - var b = Float64Slice{.3, .6, .0, .1} + var a = floats.Slice{.2, .0, .6, .2} + var b = floats.Slice{.3, .6, .0, .1} e := stat.CrossEntropy(a, b) assert.InDelta(t, e, CrossEntropy(&a, &b, a.Length()), 0.0001) } func TestSoftmax(t *testing.T) { - var a = Float64Slice{3.0, 1.0, 0.2} + var a = floats.Slice{3.0, 1.0, 0.2} out := Softmax(&a, a.Length()) - r := Float64Slice{0.8360188027814407, 0.11314284146556013, 0.05083835575299916} + 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) } } func TestSigmoid(t *testing.T) { - a := Float64Slice{3.0, 1.0, 2.1} + a := floats.Slice{3.0, 1.0, 2.1} out := Sigmoid(&a) - r := Float64Slice{0.9525741268224334, 0.7310585786300049, 0.8909031788043871} + 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) } @@ -123,8 +125,8 @@ func TestSigmoid(t *testing.T) { // from https://en.wikipedia.org/wiki/Logistic_regression func TestLogisticRegression(t *testing.T) { - a := []Float64Slice{{0.5, 0.75, 1., 1.25, 1.5, 1.75, 1.75, 2.0, 2.25, 2.5, 2.75, 3., 3.25, 3.5, 4., 4.25, 4.5, 4.75, 5., 5.5}} - b := Float64Slice{0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1} + a := []floats.Slice{{0.5, 0.75, 1., 1.25, 1.5, 1.75, 1.75, 2.0, 2.25, 2.5, 2.75, 3., 3.25, 3.5, 4., 4.25, 4.5, 4.75, 5., 5.5}} + b := floats.Slice{0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1} var x []Series x = append(x, &a[0]) @@ -139,8 +141,8 @@ func TestLogisticRegression(t *testing.T) { } func TestDot(t *testing.T) { - a := Float64Slice{7, 6, 5, 4, 3, 2, 1, 0} - b := Float64Slice{200., 201., 203., 204., 203., 199.} + a := floats.Slice{7, 6, 5, 4, 3, 2, 1, 0} + b := floats.Slice{200., 201., 203., 204., 203., 199.} out1 := Dot(&a, &b, 3) assert.InDelta(t, out1, 611., 0.001) out2 := Dot(&a, 3., 2) @@ -160,7 +162,7 @@ func TestClone(t *testing.T) { func TestPlot(t *testing.T) { ct := NewCanvas("test", Interval5m) - a := Float64Slice{200., 205., 230., 236} + a := floats.Slice{200., 205., 230., 236} ct.Plot("test", &a, Time(time.Now()), 4) assert.Equal(t, ct.Interval, Interval5m) assert.Equal(t, ct.Series[0].(chart.TimeSeries).Len(), 4) diff --git a/pkg/types/omega_test.go b/pkg/types/omega_test.go index 5a8fcce03..6c6c6dabd 100644 --- a/pkg/types/omega_test.go +++ b/pkg/types/omega_test.go @@ -1,12 +1,15 @@ package types import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/datatype/floats" ) func TestOmega(t *testing.T) { - var a Series = &Float64Slice{0.08, 0.09, 0.07, 0.15, 0.02, 0.03, 0.04, 0.05, 0.06, 0.01} + var a Series = &floats.Slice{0.08, 0.09, 0.07, 0.15, 0.02, 0.03, 0.04, 0.05, 0.06, 0.01} output := Omega(a) assert.InDelta(t, output, 1, 0.0001) } diff --git a/pkg/types/seriesbase_imp.go b/pkg/types/seriesbase_imp.go index 41675f262..b952f7e5c 100644 --- a/pkg/types/seriesbase_imp.go +++ b/pkg/types/seriesbase_imp.go @@ -1,5 +1,7 @@ package types +import "github.com/c9s/bbgo/pkg/datatype/floats" + func (s *SeriesBase) Index(i int) float64 { if s.Series == nil { return 0 @@ -81,7 +83,7 @@ func (s *SeriesBase) Array(limit ...int) (result []float64) { return Array(s, limit...) } -func (s *SeriesBase) Reverse(limit ...int) (result Float64Slice) { +func (s *SeriesBase) Reverse(limit ...int) (result floats.Slice) { return Reverse(s, limit...) } diff --git a/pkg/types/sharpe_test.go b/pkg/types/sharpe_test.go index e6f90d1c9..6d41a3c72 100644 --- a/pkg/types/sharpe_test.go +++ b/pkg/types/sharpe_test.go @@ -1,8 +1,11 @@ package types import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/datatype/floats" ) /* @@ -16,7 +19,7 @@ print(qx.stats.sharpe(pd.Series([0.01, 0.1, 0.001]), 0, 252, False, False)) print(qx.stats.sharpe(pd.Series([0.01, 0.1, 0.001]), 0, 252, True, False)) */ func TestSharpe(t *testing.T) { - var a Series = &Float64Slice{0.01, 0.1, 0.001} + var a Series = &floats.Slice{0.01, 0.1, 0.001} output := Sharpe(a, 0, false, false) assert.InDelta(t, output, 0.67586, 0.0001) output = Sharpe(a, 252, false, false) diff --git a/pkg/types/sortino_test.go b/pkg/types/sortino_test.go index aa58b218a..bb8052757 100644 --- a/pkg/types/sortino_test.go +++ b/pkg/types/sortino_test.go @@ -1,8 +1,11 @@ package types import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/datatype/floats" ) /* @@ -16,7 +19,7 @@ print(qx.stats.sortino(pd.Series([0.01, -0.03, 0.1, -0.02, 0.001]), 0.03, 252, F print(qx.stats.sortino(pd.Series([0.01, -0.03, 0.1, -0.02, 0.001]), 0.03, 252, True, False)) */ func TestSortino(t *testing.T) { - var a Series = &Float64Slice{0.01, -0.03, 0.1, -0.02, 0.001} + var a Series = &floats.Slice{0.01, -0.03, 0.1, -0.02, 0.001} output := Sortino(a, 0.03, 0, false, false) assert.InDelta(t, output, 0.75661, 0.0001) output = Sortino(a, 0.03, 252, false, false) diff --git a/pkg/types/trade_stats.go b/pkg/types/trade_stats.go index 72b07a65f..7d8e1f356 100644 --- a/pkg/types/trade_stats.go +++ b/pkg/types/trade_stats.go @@ -8,18 +8,19 @@ import ( "gopkg.in/yaml.v3" + "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" ) type IntervalProfitCollector struct { Interval Interval `json:"interval"` - Profits *Float64Slice `json:"profits"` - Timestamp *Float64Slice `json:"timestamp"` + Profits *floats.Slice `json:"profits"` + Timestamp *floats.Slice `json:"timestamp"` tmpTime time.Time `json:"tmpTime"` } func NewIntervalProfitCollector(i Interval, startTime time.Time) *IntervalProfitCollector { - return &IntervalProfitCollector{Interval: i, tmpTime: startTime, Profits: &Float64Slice{1.}, Timestamp: &Float64Slice{float64(startTime.Unix())}} + return &IntervalProfitCollector{Interval: i, tmpTime: startTime, Profits: &floats.Slice{1.}, Timestamp: &floats.Slice{float64(startTime.Unix())}} } // Update the collector by every traded profit