mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
fix: series not been updated
This commit is contained in:
parent
be0755d755
commit
af61952e40
|
@ -11,9 +11,9 @@ type MarketDataStore struct {
|
|||
Symbol string
|
||||
|
||||
// KLineWindows stores all loaded klines per interval
|
||||
KLineWindows map[types.Interval]types.KLineWindow `json:"-"`
|
||||
KLineWindows map[types.Interval]*types.KLineWindow `json:"-"`
|
||||
|
||||
kLineWindowUpdateCallbacks []func(interval types.Interval, kline types.KLineWindow)
|
||||
kLineWindowUpdateCallbacks []func(interval types.Interval, klines types.KLineWindow)
|
||||
}
|
||||
|
||||
func NewMarketDataStore(symbol string) *MarketDataStore {
|
||||
|
@ -21,16 +21,16 @@ func NewMarketDataStore(symbol string) *MarketDataStore {
|
|||
Symbol: symbol,
|
||||
|
||||
// KLineWindows stores all loaded klines per interval
|
||||
KLineWindows: make(map[types.Interval]types.KLineWindow, len(types.SupportedIntervals)), // 12 interval, 1m,5m,15m,30m,1h,2h,4h,6h,12h,1d,3d,1w
|
||||
KLineWindows: make(map[types.Interval]*types.KLineWindow, len(types.SupportedIntervals)), // 12 interval, 1m,5m,15m,30m,1h,2h,4h,6h,12h,1d,3d,1w
|
||||
}
|
||||
}
|
||||
|
||||
func (store *MarketDataStore) SetKLineWindows(windows map[types.Interval]types.KLineWindow) {
|
||||
func (store *MarketDataStore) SetKLineWindows(windows map[types.Interval]*types.KLineWindow) {
|
||||
store.KLineWindows = windows
|
||||
}
|
||||
|
||||
// KLinesOfInterval returns the kline window of the given interval
|
||||
func (store *MarketDataStore) KLinesOfInterval(interval types.Interval) (kLines types.KLineWindow, ok bool) {
|
||||
func (store *MarketDataStore) KLinesOfInterval(interval types.Interval) (kLines *types.KLineWindow, ok bool) {
|
||||
kLines, ok = store.KLineWindows[interval]
|
||||
return kLines, ok
|
||||
}
|
||||
|
@ -50,14 +50,15 @@ func (store *MarketDataStore) handleKLineClosed(kline types.KLine) {
|
|||
func (store *MarketDataStore) AddKLine(kline types.KLine) {
|
||||
window, ok := store.KLineWindows[kline.Interval]
|
||||
if !ok {
|
||||
window = make(types.KLineWindow, 0, 1000)
|
||||
var tmp = make(types.KLineWindow, 0, 1000)
|
||||
store.KLineWindows[kline.Interval] = &tmp
|
||||
window = &tmp
|
||||
}
|
||||
window.Add(kline)
|
||||
|
||||
if len(window) > MaxNumOfKLines {
|
||||
window = window[MaxNumOfKLinesTruncate-1:]
|
||||
if len(*window) > MaxNumOfKLines {
|
||||
*window = (*window)[MaxNumOfKLinesTruncate-1:]
|
||||
}
|
||||
|
||||
store.KLineWindows[kline.Interval] = window
|
||||
store.EmitKLineWindowUpdate(kline.Interval, window)
|
||||
store.EmitKLineWindowUpdate(kline.Interval, *window)
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
func (store *MarketDataStore) OnKLineWindowUpdate(cb func(interval types.Interval, kline types.KLineWindow)) {
|
||||
func (store *MarketDataStore) OnKLineWindowUpdate(cb func(interval types.Interval, klines types.KLineWindow)) {
|
||||
store.kLineWindowUpdateCallbacks = append(store.kLineWindowUpdateCallbacks, cb)
|
||||
}
|
||||
|
||||
func (store *MarketDataStore) EmitKLineWindowUpdate(interval types.Interval, kline types.KLineWindow) {
|
||||
func (store *MarketDataStore) EmitKLineWindowUpdate(interval types.Interval, klines types.KLineWindow) {
|
||||
for _, cb := range store.kLineWindowUpdateCallbacks {
|
||||
cb(interval, kline)
|
||||
cb(interval, klines)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,19 +42,19 @@ type BOLL struct {
|
|||
type BandType int
|
||||
|
||||
func (inc *BOLL) GetUpBand() types.Series {
|
||||
return inc.UpBand
|
||||
return &inc.UpBand
|
||||
}
|
||||
|
||||
func (inc *BOLL) GetDownBand() types.Series {
|
||||
return inc.DownBand
|
||||
return &inc.DownBand
|
||||
}
|
||||
|
||||
func (inc *BOLL) GetSMA() types.Series {
|
||||
return inc.SMA
|
||||
return &inc.SMA
|
||||
}
|
||||
|
||||
func (inc *BOLL) GetStdDev() types.Series {
|
||||
return inc.StdDev
|
||||
return &inc.StdDev
|
||||
}
|
||||
|
||||
func (inc *BOLL) LastUpBand() float64 {
|
||||
|
|
|
@ -45,6 +45,16 @@ func (inc *SMA) Length() int {
|
|||
|
||||
var _ types.Series = &SMA{}
|
||||
|
||||
func (inc *SMA) Update(value float64) {
|
||||
length := len(inc.Values)
|
||||
if length == 0 {
|
||||
inc.Values = append(inc.Values, value)
|
||||
return
|
||||
}
|
||||
newVal := (inc.Values[length-1]*float64(inc.Window-1) + value) / float64(inc.Window)
|
||||
inc.Values = append(inc.Values, newVal)
|
||||
}
|
||||
|
||||
func (inc *SMA) calculateAndUpdate(kLines []types.KLine) {
|
||||
if len(kLines) < inc.Window {
|
||||
return
|
||||
|
|
|
@ -84,9 +84,9 @@ func (inc *STOCH) Bind(updater KLineWindowUpdater) {
|
|||
}
|
||||
|
||||
func (inc *STOCH) GetD() types.Series {
|
||||
return inc.D
|
||||
return &inc.D
|
||||
}
|
||||
|
||||
func (inc *STOCH) GetK() types.Series {
|
||||
return inc.K
|
||||
return &inc.K
|
||||
}
|
||||
|
|
|
@ -118,22 +118,28 @@ func (s Float64Slice) Dot(other Float64Slice) float64 {
|
|||
return s.ElementwiseProduct(other).Sum()
|
||||
}
|
||||
|
||||
func (a Float64Slice) Last() float64 {
|
||||
if len(a) > 0 {
|
||||
return a[len(a)-1]
|
||||
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 {
|
||||
if len(a)-i < 0 || i < 0 {
|
||||
func (a *Float64Slice) Index(i int) float64 {
|
||||
length := len(*a)
|
||||
if length-i < 0 || i < 0 {
|
||||
return 0.0
|
||||
}
|
||||
return a[len(a)-i-1]
|
||||
return (*a)[length-i-1]
|
||||
}
|
||||
|
||||
func (a Float64Slice) Length() int {
|
||||
return len(a)
|
||||
func (a *Float64Slice) Length() int {
|
||||
return len(*a)
|
||||
}
|
||||
|
||||
var _ Series = Float64Slice([]float64{})
|
||||
func (a Float64Slice) Addr() *Float64Slice {
|
||||
return &a
|
||||
}
|
||||
|
||||
var _ Series = Float64Slice([]float64{}).Addr()
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"gonum.org/v1/gonum/stat"
|
||||
)
|
||||
|
@ -83,6 +85,25 @@ func Abs(a Series) Series {
|
|||
|
||||
var _ Series = &AbsResult{}
|
||||
|
||||
func Predict(a Series, lookback int, offset ...int) float64 {
|
||||
if a.Length() < lookback {
|
||||
lookback = a.Length()
|
||||
}
|
||||
x := make([]float64, lookback, lookback)
|
||||
y := make([]float64, lookback, lookback)
|
||||
var weights []float64
|
||||
for i := 0; i < lookback; i++ {
|
||||
x[i] = float64(i)
|
||||
y[i] = a.Index(i)
|
||||
}
|
||||
alpha, beta := stat.LinearRegression(x, y, weights, false)
|
||||
o := -1.0
|
||||
if len(offset) > 0 {
|
||||
o = -float64(offset[0])
|
||||
}
|
||||
return alpha + beta*o
|
||||
}
|
||||
|
||||
// This will make prediction using Linear Regression to get the next cross point
|
||||
// Return (offset from latest, crossed value, could cross)
|
||||
// offset from latest should always be positive
|
||||
|
@ -96,14 +117,14 @@ func NextCross(a Series, b Series, lookback int) (int, float64, bool) {
|
|||
if b.Length() < lookback {
|
||||
lookback = b.Length()
|
||||
}
|
||||
x := make([]float64, 0, lookback)
|
||||
y1 := make([]float64, 0, lookback)
|
||||
y2 := make([]float64, 0, lookback)
|
||||
x := make([]float64, lookback, lookback)
|
||||
y1 := make([]float64, lookback, lookback)
|
||||
y2 := make([]float64, lookback, lookback)
|
||||
var weights []float64
|
||||
for i := 0; i < lookback; i++ {
|
||||
x = append(x, float64(i))
|
||||
y1 = append(y1, a.Index(i))
|
||||
y2 = append(y2, b.Index(i))
|
||||
x[i] = float64(i)
|
||||
y1[i] = a.Index(i)
|
||||
y2[i] = b.Index(i)
|
||||
}
|
||||
alpha1, beta1 := stat.LinearRegression(x, y1, weights, false)
|
||||
alpha2, beta2 := stat.LinearRegression(x, y2, weights, false)
|
||||
|
@ -233,12 +254,18 @@ func Add(a interface{}, b interface{}) Series {
|
|||
aa = NumberSeries(a.(float64))
|
||||
case Series:
|
||||
aa = a.(Series)
|
||||
default:
|
||||
panic("input should be either *Series or float64")
|
||||
|
||||
}
|
||||
switch b.(type) {
|
||||
case float64:
|
||||
bb = NumberSeries(b.(float64))
|
||||
case Series:
|
||||
bb = b.(Series)
|
||||
default:
|
||||
panic("input should be either *Series or float64")
|
||||
|
||||
}
|
||||
return &AddSeriesResult{aa, bb}
|
||||
}
|
||||
|
@ -269,21 +296,8 @@ type MinusSeriesResult struct {
|
|||
|
||||
// Minus two series, result[i] = a[i] - b[i]
|
||||
func Minus(a interface{}, b interface{}) Series {
|
||||
var aa Series
|
||||
var bb Series
|
||||
|
||||
switch a.(type) {
|
||||
case float64:
|
||||
aa = NumberSeries(a.(float64))
|
||||
case Series:
|
||||
aa = a.(Series)
|
||||
}
|
||||
switch b.(type) {
|
||||
case float64:
|
||||
bb = NumberSeries(b.(float64))
|
||||
case Series:
|
||||
bb = b.(Series)
|
||||
}
|
||||
aa := switchIface(a)
|
||||
bb := switchIface(b)
|
||||
return &MinusSeriesResult{aa, bb}
|
||||
}
|
||||
|
||||
|
@ -306,26 +320,34 @@ func (a *MinusSeriesResult) Length() int {
|
|||
|
||||
var _ Series = &MinusSeriesResult{}
|
||||
|
||||
// Divid two series, result[i] = a[i] / b[i]
|
||||
func Div(a interface{}, b interface{}) Series {
|
||||
var aa Series
|
||||
var bb Series
|
||||
|
||||
switch a.(type) {
|
||||
case float64:
|
||||
aa = NumberSeries(a.(float64))
|
||||
case Series:
|
||||
aa = a.(Series)
|
||||
}
|
||||
func switchIface(b interface{}) Series {
|
||||
switch b.(type) {
|
||||
case float64:
|
||||
bb = NumberSeries(b.(float64))
|
||||
if 0 == bb.Last() {
|
||||
panic("Divid by zero exception")
|
||||
}
|
||||
return NumberSeries(b.(float64))
|
||||
case int32:
|
||||
return NumberSeries(float64(b.(int32)))
|
||||
case int64:
|
||||
return NumberSeries(float64(b.(int64)))
|
||||
case float32:
|
||||
return NumberSeries(float64(b.(float32)))
|
||||
case int:
|
||||
return NumberSeries(float64(b.(int)))
|
||||
case Series:
|
||||
bb = b.(Series)
|
||||
return b.(Series)
|
||||
default:
|
||||
fmt.Println(reflect.TypeOf(b))
|
||||
panic("input should be either *Series or float64")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Divid two series, result[i] = a[i] / b[i]
|
||||
func Div(a interface{}, b interface{}) Series {
|
||||
aa := switchIface(a)
|
||||
if 0 == b {
|
||||
panic("Divid by zero exception")
|
||||
}
|
||||
bb := switchIface(b)
|
||||
return &DivSeriesResult{aa, bb}
|
||||
|
||||
}
|
||||
|
@ -364,12 +386,17 @@ func Mul(a interface{}, b interface{}) Series {
|
|||
aa = NumberSeries(a.(float64))
|
||||
case Series:
|
||||
aa = a.(Series)
|
||||
default:
|
||||
panic("input should be either Series or float64")
|
||||
}
|
||||
switch b.(type) {
|
||||
case float64:
|
||||
bb = NumberSeries(b.(float64))
|
||||
case Series:
|
||||
bb = b.(Series)
|
||||
default:
|
||||
panic("input should be either Series or float64")
|
||||
|
||||
}
|
||||
return &MulSeriesResult{aa, bb}
|
||||
|
||||
|
@ -443,3 +470,43 @@ func ToReverseArray(a Series, limit ...int) (result Float64Slice) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
type ChangeResult struct {
|
||||
a Series
|
||||
offset int
|
||||
}
|
||||
|
||||
func (c *ChangeResult) Last() float64 {
|
||||
if c.offset >= c.a.Length() {
|
||||
return 0
|
||||
}
|
||||
return c.a.Last() - c.a.Index(c.offset)
|
||||
}
|
||||
|
||||
func (c *ChangeResult) Index(i int) float64 {
|
||||
if i+c.offset >= c.a.Length() {
|
||||
return 0
|
||||
}
|
||||
return c.a.Index(i) - c.a.Index(i+c.offset)
|
||||
}
|
||||
|
||||
func (c *ChangeResult) Length() int {
|
||||
length := c.a.Length()
|
||||
if length >= c.offset {
|
||||
return length - c.offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Difference between current value and previous, a - a[offset]
|
||||
// offset: if not given, offset is 1.
|
||||
func Change(a Series, offset ...int) Series {
|
||||
o := 1
|
||||
if len(offset) == 0 {
|
||||
o = offset[0]
|
||||
}
|
||||
|
||||
return &ChangeResult{a, o}
|
||||
}
|
||||
|
||||
// TODO: ta.linreg
|
||||
|
|
|
@ -14,7 +14,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 = &Float64Slice{100., 80., 60.}
|
||||
// index 2 1 0
|
||||
// predicted 40 20 0
|
||||
// offset 1 2 3
|
||||
|
@ -24,3 +24,12 @@ func TestNextCross(t *testing.T) {
|
|||
assert.Equal(t, value, 1.2)
|
||||
assert.Equal(t, index, 3) // 2.94, ceil
|
||||
}
|
||||
|
||||
func TestFloat64Slice(t *testing.T) {
|
||||
var a = Float64Slice{1.0, 2.0, 3.0}
|
||||
var b = Float64Slice{1.0, 2.0, 3.0}
|
||||
var c Series = Minus(&a, &b)
|
||||
a = append(a, 4.0)
|
||||
b = append(b, 3.0)
|
||||
assert.Equal(t, c.Last(), 1.)
|
||||
}
|
||||
|
|
|
@ -516,76 +516,88 @@ const (
|
|||
kCloseValue
|
||||
kHighValue
|
||||
kLowValue
|
||||
kVolumeValue
|
||||
)
|
||||
|
||||
func (k KLineWindow) High() Series {
|
||||
func (k *KLineWindow) High() Series {
|
||||
return &KLineSeries{
|
||||
lines: k,
|
||||
kv: kHighValue,
|
||||
}
|
||||
}
|
||||
|
||||
func (k KLineWindow) Low() Series {
|
||||
func (k *KLineWindow) Low() Series {
|
||||
return &KLineSeries{
|
||||
lines: k,
|
||||
kv: kLowValue,
|
||||
}
|
||||
}
|
||||
|
||||
func (k KLineWindow) Open() Series {
|
||||
func (k *KLineWindow) Open() Series {
|
||||
return &KLineSeries{
|
||||
lines: k,
|
||||
kv: kOpenValue,
|
||||
}
|
||||
}
|
||||
|
||||
func (k KLineWindow) Close() Series {
|
||||
func (k *KLineWindow) Close() Series {
|
||||
return &KLineSeries{
|
||||
lines: k,
|
||||
kv: kCloseValue,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KLineWindow) Volume() Series {
|
||||
return &KLineSeries{
|
||||
lines: k,
|
||||
kv: kVolumeValue,
|
||||
}
|
||||
}
|
||||
|
||||
type KLineSeries struct {
|
||||
lines []KLine
|
||||
lines *KLineWindow
|
||||
kv KValueType
|
||||
}
|
||||
|
||||
func (k *KLineSeries) Last() float64 {
|
||||
length := len(k.lines)
|
||||
length := len(*k.lines)
|
||||
switch k.kv {
|
||||
case kOpenValue:
|
||||
return k.lines[length-1].GetOpen().Float64()
|
||||
return (*k.lines)[length-1].GetOpen().Float64()
|
||||
case kCloseValue:
|
||||
return k.lines[length-1].GetClose().Float64()
|
||||
return (*k.lines)[length-1].GetClose().Float64()
|
||||
case kLowValue:
|
||||
return k.lines[length-1].GetLow().Float64()
|
||||
return (*k.lines)[length-1].GetLow().Float64()
|
||||
case kHighValue:
|
||||
return k.lines[length-1].GetHigh().Float64()
|
||||
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 {
|
||||
length := len(k.lines)
|
||||
length := len(*k.lines)
|
||||
if length == 0 || length-i-1 < 0 {
|
||||
return 0
|
||||
}
|
||||
switch k.kv {
|
||||
case kOpenValue:
|
||||
return k.lines[length-i-1].GetOpen().Float64()
|
||||
return (*k.lines)[length-i-1].GetOpen().Float64()
|
||||
case kCloseValue:
|
||||
return k.lines[length-i-1].GetClose().Float64()
|
||||
return (*k.lines)[length-i-1].GetClose().Float64()
|
||||
case kLowValue:
|
||||
return k.lines[length-i-1].GetLow().Float64()
|
||||
return (*k.lines)[length-i-1].GetLow().Float64()
|
||||
case kHighValue:
|
||||
return k.lines[length-i-1].GetHigh().Float64()
|
||||
return (*k.lines)[length-i-1].GetHigh().Float64()
|
||||
case kVolumeValue:
|
||||
return (*k.lines)[length-i-1].Volume.Float64()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (k *KLineSeries) Length() int {
|
||||
return len(k.lines)
|
||||
return len(*k.lines)
|
||||
}
|
||||
|
||||
var _ Series = &KLineSeries{}
|
||||
|
|
Loading…
Reference in New Issue
Block a user