From a1fa23121d27a281c41fc6f0e832ba555363d288 Mon Sep 17 00:00:00 2001 From: austin362667 Date: Mon, 18 Apr 2022 20:53:38 +0800 Subject: [PATCH 1/7] factorzoo: add correlation indicator --- pkg/strategy/factorzoo/correlation.go | 103 ++++++++++++++++++ .../factorzoo/correlation_callbacks.go | 15 +++ 2 files changed, 118 insertions(+) create mode 100644 pkg/strategy/factorzoo/correlation.go create mode 100644 pkg/strategy/factorzoo/correlation_callbacks.go diff --git a/pkg/strategy/factorzoo/correlation.go b/pkg/strategy/factorzoo/correlation.go new file mode 100644 index 000000000..0c47de9ee --- /dev/null +++ b/pkg/strategy/factorzoo/correlation.go @@ -0,0 +1,103 @@ +package factorzoo + +import ( + "fmt" + "github.com/c9s/bbgo/pkg/indicator" + "github.com/c9s/bbgo/pkg/types" + "math" + "time" +) + +var zeroTime time.Time + +//var zeroTime time.Time +type KLineValueMapper func(k types.KLine) float64 + +//go:generate callbackgen -type CORRELATION +type CORRELATION struct { + types.IntervalWindow + Values types.Float64Slice + EndTime time.Time + + UpdateCallbacks []func(value float64) +} + +func (inc *CORRELATION) Last() float64 { + if len(inc.Values) == 0 { + return 0.0 + } + return inc.Values[len(inc.Values)-1] +} + +func (inc *CORRELATION) calculateAndUpdate(klines []types.KLine) { + if len(klines) < inc.Window { + return + } + + var end = len(klines) - 1 + var lastKLine = klines[end] + + if inc.EndTime != zeroTime && lastKLine.GetEndTime().Before(inc.EndTime) { + return + } + + var recentT = klines[end-(inc.Window-1) : end+1] + + correlation, err := calculateCORRELATION(recentT, inc.Window, KLineAmplitudeMapper, indicator.KLineVolumeMapper) + if err != nil { + log.WithError(err).Error("can not calculate correlation") + return + } + inc.Values.Push(correlation) + + if len(inc.Values) > indicator.MaxNumOfVOL { + inc.Values = inc.Values[indicator.MaxNumOfVOLTruncateSize-1:] + } + + inc.EndTime = klines[end].GetEndTime().Time() + + inc.EmitUpdate(correlation) +} + +func (inc *CORRELATION) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) { + if inc.Interval != interval { + return + } + + inc.calculateAndUpdate(window) +} + +func (inc *CORRELATION) Bind(updater indicator.KLineWindowUpdater) { + updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate) +} + +func calculateCORRELATION(klines []types.KLine, window int, valA KLineValueMapper, valB 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) + } + + sumA, sumB, sumAB, squareSumA, squareSumB := 0., 0., 0., 0., 0. + for _, k := range klines { + // sum of elements of array A + sumA += valA(k) + // sum of elements of array B + sumB += valA(k) + + // sum of A[i] * B[i]. + sumAB = sumAB + valA(k)*valB(k) + + // sum of square of array elements. + squareSumA = squareSumA + valA(k)*valA(k) + squareSumB = squareSumB + valB(k)*valB(k) + } + // use formula for calculating correlation coefficient. + corr := (float64(window)*sumAB - sumA*sumB) / + math.Sqrt((float64(window)*squareSumA-sumA*sumA)*(float64(window)*squareSumB-sumB*sumB)) + + return corr, nil +} + +func KLineAmplitudeMapper(k types.KLine) float64 { + return k.High.Div(k.Low).Float64() +} diff --git a/pkg/strategy/factorzoo/correlation_callbacks.go b/pkg/strategy/factorzoo/correlation_callbacks.go new file mode 100644 index 000000000..829426e86 --- /dev/null +++ b/pkg/strategy/factorzoo/correlation_callbacks.go @@ -0,0 +1,15 @@ +// Code generated by "callbackgen -type CORRELATION"; DO NOT EDIT. + +package factorzoo + +import () + +func (inc *CORRELATION) OnUpdate(cb func(value float64)) { + inc.UpdateCallbacks = append(inc.UpdateCallbacks, cb) +} + +func (inc *CORRELATION) EmitUpdate(value float64) { + for _, cb := range inc.UpdateCallbacks { + cb(value) + } +} From fdbb2be45caad7e90f3f541d296bf81a478ef6bd Mon Sep 17 00:00:00 2001 From: austin362667 Date: Mon, 18 Apr 2022 20:54:58 +0800 Subject: [PATCH 2/7] factorzoo: add cross-sectional factors model strategy --- pkg/strategy/factorzoo/strategy.go | 248 +++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 pkg/strategy/factorzoo/strategy.go diff --git a/pkg/strategy/factorzoo/strategy.go b/pkg/strategy/factorzoo/strategy.go new file mode 100644 index 000000000..4f2afbc3f --- /dev/null +++ b/pkg/strategy/factorzoo/strategy.go @@ -0,0 +1,248 @@ +package factorzoo + +import ( + "context" + "fmt" + "github.com/c9s/bbgo/pkg/bbgo" + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" + "github.com/sajari/regression" + "github.com/sirupsen/logrus" +) + +const ID = "factorzoo" + +const One = fixedpoint.Value(1e8) +const Two = fixedpoint.Value(2e8) + +var log = logrus.WithField("strategy", ID) + +func init() { + bbgo.RegisterStrategy(ID, &Strategy{}) +} + +type IntervalWindowSetting struct { + types.IntervalWindow +} + +type Strategy struct { + Symbol string `json:"symbol"` + Market types.Market + Interval types.Interval `json:"interval"` + Quantity fixedpoint.Value `json:"quantity"` + + Position *types.Position `json:"position,omitempty"` + + activeMakerOrders *bbgo.LocalActiveOrderBook + orderStore *bbgo.OrderStore + tradeCollector *bbgo.TradeCollector + + session *bbgo.ExchangeSession + book *types.StreamOrderBook + + prevClose fixedpoint.Value + + pvDivergenceSetting *IntervalWindowSetting `json:"pvDivergence"` + pvDivergence *CORRELATION + + Ret []float64 + Alpha [][]float64 + + T int64 + prevER fixedpoint.Value +} + +func (s *Strategy) ID() string { + return ID +} + +func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) { + log.Infof("subscribe %s", s.Symbol) + session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.Interval.String()}) +} + +func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Value) error { + base := s.Position.GetBase() + if base.IsZero() { + return fmt.Errorf("no opened %s position", s.Position.Symbol) + } + + // make it negative + quantity := base.Mul(percentage).Abs() + side := types.SideTypeBuy + if base.Sign() > 0 { + side = types.SideTypeSell + } + + if quantity.Compare(s.Market.MinQuantity) < 0 { + return fmt.Errorf("order quantity %v is too small, less than %v", quantity, s.Market.MinQuantity) + } + + submitOrder := types.SubmitOrder{ + Symbol: s.Symbol, + Side: side, + Type: types.OrderTypeMarket, + Quantity: quantity, + Market: s.Market, + } + + //s.Notify("Submitting %s %s order to close position by %v", s.Symbol, side.String(), percentage, submitOrder) + + createdOrders, err := s.session.Exchange.SubmitOrders(ctx, submitOrder) + if err != nil { + log.WithError(err).Errorf("can not place position close order") + } + + s.orderStore.Add(createdOrders...) + s.activeMakerOrders.Add(createdOrders...) + return err +} + +func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExecutor, er fixedpoint.Value) { + + //if s.prevER.Sign() < 0 && er.Sign() > 0 { + if er.Compare(fixedpoint.Zero) >= 0 { + submitOrder := types.SubmitOrder{ + Symbol: s.Symbol, + Side: types.SideTypeBuy, + Type: types.OrderTypeMarket, + Quantity: s.Quantity, //er.Abs().Mul(fixedpoint.NewFromInt(20)), + } + createdOrders, err := orderExecutor.SubmitOrders(ctx, submitOrder) + if err != nil { + log.WithError(err).Errorf("can not place orders") + } + s.orderStore.Add(createdOrders...) + s.activeMakerOrders.Add(createdOrders...) + //} else if s.prevER.Sign() > 0 && er.Sign() < 0 { + } else { + submitOrder := types.SubmitOrder{ + Symbol: s.Symbol, + Side: types.SideTypeSell, + Type: types.OrderTypeMarket, + Quantity: s.Quantity, //er.Abs().Mul(fixedpoint.NewFromInt(20)), + } + createdOrders, err := orderExecutor.SubmitOrders(ctx, submitOrder) + if err != nil { + log.WithError(err).Errorf("can not place orders") + } + s.orderStore.Add(createdOrders...) + s.activeMakerOrders.Add(createdOrders...) + } + s.prevER = er +} + +func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error { + // initial required information + s.session = session + s.prevClose = fixedpoint.Zero + + // first we need to get market data store(cached market data) from the exchange session + st, _ := session.MarketDataStore(s.Symbol) + // setup the time frame size + iw := types.IntervalWindow{Window: 50, Interval: s.Interval} + // construct CORR indicator + s.pvDivergence = &CORRELATION{IntervalWindow: iw} + // bind indicator to the data store, so that our callback could be triggered + s.pvDivergence.Bind(st) + //s.pvDivergence.OnUpdate(func(corr float64) { + // //fmt.Printf("now we've got corr: %f\n", corr) + //}) + + s.Alpha = [][]float64{{}, {}, {}, {}, {}} + s.Ret = []float64{} + //thetas := []float64{0, 0, 0, 0} + preCompute := 0 + + s.activeMakerOrders = bbgo.NewLocalActiveOrderBook(s.Symbol) + s.activeMakerOrders.BindStream(session.UserDataStream) + + s.orderStore = bbgo.NewOrderStore(s.Symbol) + s.orderStore.BindStream(session.UserDataStream) + + if s.Position == nil { + s.Position = types.NewPositionFromMarket(s.Market) + } + + s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.Position, s.orderStore) + s.tradeCollector.BindStream(session.UserDataStream) + + session.UserDataStream.OnStart(func() { + log.Infof("connected") + }) + + session.MarketDataStream.OnKLineClosed(func(kline types.KLine) { + + if kline.Symbol != s.Symbol || kline.Interval != s.Interval { + return + } + + if err := s.activeMakerOrders.GracefulCancel(ctx, s.session.Exchange); err != nil { + log.WithError(err).Errorf("graceful cancel order error") + } + + // amplitude volume divergence + corr := fixedpoint.NewFromFloat(s.pvDivergence.Last()).Neg() + // price mean reversion + rev := fixedpoint.NewFromInt(1).Div(kline.Close) + // alpha150 from GTJA's 191 paper + a150 := kline.High.Add(kline.Low).Add(kline.Close).Div(fixedpoint.NewFromInt(3)).Mul(kline.Volume) + // momentum from world quant's paper + mom := One.Sub(kline.Open.Div(kline.Close)).Mul(fixedpoint.NegOne) + // oprning gap + ogap := kline.Open.Div(s.prevClose) + + log.Infof("corr: %f, rev: %f, a150: %f, mom: %f, ogap: %f", corr.Float64(), rev.Float64(), a150.Float64(), mom.Float64(), ogap.Float64()) + s.Alpha[0] = append(s.Alpha[0], corr.Float64()) + s.Alpha[1] = append(s.Alpha[1], rev.Float64()) + s.Alpha[2] = append(s.Alpha[2], a150.Float64()) + s.Alpha[3] = append(s.Alpha[3], mom.Float64()) + s.Alpha[4] = append(s.Alpha[4], ogap.Float64()) + + //s.Alpha[5] = append(s.Alpha[4], 1.0) // constant + + ret := kline.Close.Sub(s.prevClose).Div(s.prevClose).Float64() + s.Ret = append(s.Ret, ret) + log.Infof("Current Return: %f", s.Ret[len(s.Ret)-1]) + + // accumulate enough data for cross-sectional regression, not time-series regression + s.T = 20 + if preCompute < int(s.T)+1 { + preCompute++ + } else { + s.ClosePosition(ctx, fixedpoint.One) + s.tradeCollector.Process() + // rolling regression for last 20 interval alphas + r := new(regression.Regression) + r.SetObserved("Return Rate Per Timeframe") + r.SetVar(0, "Corr") + r.SetVar(1, "Rev") + r.SetVar(2, "A150") + r.SetVar(3, "Mom") + r.SetVar(4, "OGap") + var rdp regression.DataPoints + for i := 1; i <= int(s.T); i++ { + // alphas[t-1], previous alphas, dot not take current alpha into account, will cause look-ahead bias + as := []float64{s.Alpha[0][len(s.Alpha[0])-(i+2)], s.Alpha[1][len(s.Alpha[1])-(i+2)], s.Alpha[2][len(s.Alpha[2])-(i+2)], s.Alpha[3][len(s.Alpha[3])-(i+2)], s.Alpha[4][len(s.Alpha[4])-(i+2)]} + // alphas[t], current return rate + rt := s.Ret[len(s.Ret)-(i+1)] + rdp = append(rdp, regression.DataPoint(rt, as)) + + } + r.Train(rdp...) + r.Run() + fmt.Printf("Regression formula:\n%v\n", r.Formula) + //prediction := r.Coeff(0)*corr.Float64() + r.Coeff(1)*rev.Float64() + r.Coeff(2)*factorzoo.Float64() + r.Coeff(3)*mom.Float64() + r.Coeff(4) + prediction, _ := r.Predict([]float64{corr.Float64(), rev.Float64(), a150.Float64(), mom.Float64(), ogap.Float64()}) + log.Infof("Predicted Return: %f", prediction) + + s.placeOrders(ctx, orderExecutor, fixedpoint.NewFromFloat(prediction)) + s.tradeCollector.Process() + } + + s.prevClose = kline.Close + + }) + + return nil +} From da51d566249dbf9d46454bb649364713a865d5c1 Mon Sep 17 00:00:00 2001 From: austin362667 Date: Mon, 18 Apr 2022 20:56:15 +0800 Subject: [PATCH 3/7] cmd: add built-in factorzoo strategy --- pkg/cmd/builtin.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/builtin.go b/pkg/cmd/builtin.go index 670cbc963..860379982 100644 --- a/pkg/cmd/builtin.go +++ b/pkg/cmd/builtin.go @@ -6,6 +6,8 @@ import ( _ "github.com/c9s/bbgo/pkg/strategy/bollmaker" _ "github.com/c9s/bbgo/pkg/strategy/emastop" _ "github.com/c9s/bbgo/pkg/strategy/etf" + _ "github.com/c9s/bbgo/pkg/strategy/ewoDgtrd" + _ "github.com/c9s/bbgo/pkg/strategy/factorzoo" _ "github.com/c9s/bbgo/pkg/strategy/flashcrash" _ "github.com/c9s/bbgo/pkg/strategy/funding" _ "github.com/c9s/bbgo/pkg/strategy/grid" @@ -23,5 +25,4 @@ import ( _ "github.com/c9s/bbgo/pkg/strategy/xmaker" _ "github.com/c9s/bbgo/pkg/strategy/xnav" _ "github.com/c9s/bbgo/pkg/strategy/xpuremaker" - _ "github.com/c9s/bbgo/pkg/strategy/ewoDgtrd" ) From 7f63938a50aa3f9da166ac6426ad55b8fd003d3f Mon Sep 17 00:00:00 2001 From: austin362667 Date: Mon, 18 Apr 2022 20:59:53 +0800 Subject: [PATCH 4/7] config: add factorzoo yaml --- config/factorzoo.yaml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 config/factorzoo.yaml diff --git a/config/factorzoo.yaml b/config/factorzoo.yaml new file mode 100644 index 000000000..40647e74d --- /dev/null +++ b/config/factorzoo.yaml @@ -0,0 +1,30 @@ +sessions: + binance: + exchange: binance + envVarPrefix: binance +# futures: true + + +exchangeStrategies: +- on: binance + factorzoo: + symbol: BTCUSDT + interval: 12h # T:20/12h + quantity: 0.95 + + +backtest: + sessions: + - binance + # for testing max draw down (MDD) at 03-12 + # see here for more details + # https://www.investopedia.com/terms/m/maximum-drawdown-mdd.asp + startTime: "2022-03-15" + endTime: "2022-04-13" + symbols: + - BTCUSDT + account: + binance: + balances: + BTC: 1.0 + USDT: 45_000.0 From 9eefcb8c4ef7cd2416ea3d9454a62a1aa2f25311 Mon Sep 17 00:00:00 2001 From: austin362667 Date: Mon, 18 Apr 2022 21:20:07 +0800 Subject: [PATCH 5/7] go: add regression package --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index 66f994f20..63f509adc 100644 --- a/go.mod +++ b/go.mod @@ -88,6 +88,7 @@ require ( github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/sajari/regression v1.0.1 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spf13/afero v1.5.1 // indirect diff --git a/go.sum b/go.sum index f4e0811c1..b5f52f531 100644 --- a/go.sum +++ b/go.sum @@ -412,6 +412,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sajari/regression v1.0.1 h1:iTVc6ZACGCkoXC+8NdqH5tIreslDTT/bXxT6OmHR5PE= +github.com/sajari/regression v1.0.1/go.mod h1:NeG/XTW1lYfGY7YV/Z0nYDV/RGh3wxwd1yW46835flM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= From 71a032a29bf9382f10668df6a8f6465ca74753a1 Mon Sep 17 00:00:00 2001 From: austin362667 Date: Mon, 18 Apr 2022 21:25:46 +0800 Subject: [PATCH 6/7] factorzoo: clean up factorzoo: clean up factorzoo: clean up --- pkg/strategy/factorzoo/correlation.go | 12 ++++++------ pkg/strategy/factorzoo/correlation_callbacks.go | 6 +++--- pkg/strategy/factorzoo/strategy.go | 17 ++++++++--------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/pkg/strategy/factorzoo/correlation.go b/pkg/strategy/factorzoo/correlation.go index 0c47de9ee..99735fd8c 100644 --- a/pkg/strategy/factorzoo/correlation.go +++ b/pkg/strategy/factorzoo/correlation.go @@ -13,8 +13,8 @@ var zeroTime time.Time //var zeroTime time.Time type KLineValueMapper func(k types.KLine) float64 -//go:generate callbackgen -type CORRELATION -type CORRELATION struct { +//go:generate callbackgen -type Correlation +type Correlation struct { types.IntervalWindow Values types.Float64Slice EndTime time.Time @@ -22,14 +22,14 @@ type CORRELATION struct { UpdateCallbacks []func(value float64) } -func (inc *CORRELATION) Last() float64 { +func (inc *Correlation) Last() float64 { if len(inc.Values) == 0 { return 0.0 } return inc.Values[len(inc.Values)-1] } -func (inc *CORRELATION) calculateAndUpdate(klines []types.KLine) { +func (inc *Correlation) calculateAndUpdate(klines []types.KLine) { if len(klines) < inc.Window { return } @@ -59,7 +59,7 @@ func (inc *CORRELATION) calculateAndUpdate(klines []types.KLine) { inc.EmitUpdate(correlation) } -func (inc *CORRELATION) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) { +func (inc *Correlation) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) { if inc.Interval != interval { return } @@ -67,7 +67,7 @@ func (inc *CORRELATION) handleKLineWindowUpdate(interval types.Interval, window inc.calculateAndUpdate(window) } -func (inc *CORRELATION) Bind(updater indicator.KLineWindowUpdater) { +func (inc *Correlation) Bind(updater indicator.KLineWindowUpdater) { updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate) } diff --git a/pkg/strategy/factorzoo/correlation_callbacks.go b/pkg/strategy/factorzoo/correlation_callbacks.go index 829426e86..2ef6323ea 100644 --- a/pkg/strategy/factorzoo/correlation_callbacks.go +++ b/pkg/strategy/factorzoo/correlation_callbacks.go @@ -1,14 +1,14 @@ -// Code generated by "callbackgen -type CORRELATION"; DO NOT EDIT. +// Code generated by "callbackgen -type Correlation"; DO NOT EDIT. package factorzoo import () -func (inc *CORRELATION) OnUpdate(cb func(value float64)) { +func (inc *Correlation) OnUpdate(cb func(value float64)) { inc.UpdateCallbacks = append(inc.UpdateCallbacks, cb) } -func (inc *CORRELATION) EmitUpdate(value float64) { +func (inc *Correlation) EmitUpdate(value float64) { for _, cb := range inc.UpdateCallbacks { cb(value) } diff --git a/pkg/strategy/factorzoo/strategy.go b/pkg/strategy/factorzoo/strategy.go index 4f2afbc3f..acc67c5ac 100644 --- a/pkg/strategy/factorzoo/strategy.go +++ b/pkg/strategy/factorzoo/strategy.go @@ -12,8 +12,7 @@ import ( const ID = "factorzoo" -const One = fixedpoint.Value(1e8) -const Two = fixedpoint.Value(2e8) +var three = fixedpoint.NewFromInt(3) var log = logrus.WithField("strategy", ID) @@ -43,7 +42,7 @@ type Strategy struct { prevClose fixedpoint.Value pvDivergenceSetting *IntervalWindowSetting `json:"pvDivergence"` - pvDivergence *CORRELATION + pvDivergence *Correlation Ret []float64 Alpha [][]float64 @@ -101,7 +100,7 @@ func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Valu func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExecutor, er fixedpoint.Value) { //if s.prevER.Sign() < 0 && er.Sign() > 0 { - if er.Compare(fixedpoint.Zero) >= 0 { + if er.Sign() >= 0 { submitOrder := types.SubmitOrder{ Symbol: s.Symbol, Side: types.SideTypeBuy, @@ -142,7 +141,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se // setup the time frame size iw := types.IntervalWindow{Window: 50, Interval: s.Interval} // construct CORR indicator - s.pvDivergence = &CORRELATION{IntervalWindow: iw} + s.pvDivergence = &Correlation{IntervalWindow: iw} // bind indicator to the data store, so that our callback could be triggered s.pvDivergence.Bind(st) //s.pvDivergence.OnUpdate(func(corr float64) { @@ -186,10 +185,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se // price mean reversion rev := fixedpoint.NewFromInt(1).Div(kline.Close) // alpha150 from GTJA's 191 paper - a150 := kline.High.Add(kline.Low).Add(kline.Close).Div(fixedpoint.NewFromInt(3)).Mul(kline.Volume) - // momentum from world quant's paper - mom := One.Sub(kline.Open.Div(kline.Close)).Mul(fixedpoint.NegOne) - // oprning gap + a150 := kline.High.Add(kline.Low).Add(kline.Close).Div(three).Mul(kline.Volume) + // momentum from WQ's 101 paper + mom := fixedpoint.One.Sub(kline.Open.Div(kline.Close)).Mul(fixedpoint.NegOne) + // opening gap ogap := kline.Open.Div(s.prevClose) log.Infof("corr: %f, rev: %f, a150: %f, mom: %f, ogap: %f", corr.Float64(), rev.Float64(), a150.Float64(), mom.Float64(), ogap.Float64()) From 1163b898079831129d17ead4363d2571ae0cf505 Mon Sep 17 00:00:00 2001 From: austin362667 Date: Wed, 20 Apr 2022 18:10:15 +0800 Subject: [PATCH 7/7] factorzoo: fix correlation --- pkg/strategy/factorzoo/correlation.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/strategy/factorzoo/correlation.go b/pkg/strategy/factorzoo/correlation.go index 99735fd8c..6e666d8fa 100644 --- a/pkg/strategy/factorzoo/correlation.go +++ b/pkg/strategy/factorzoo/correlation.go @@ -2,15 +2,15 @@ package factorzoo import ( "fmt" - "github.com/c9s/bbgo/pkg/indicator" - "github.com/c9s/bbgo/pkg/types" "math" "time" + + "github.com/c9s/bbgo/pkg/indicator" + "github.com/c9s/bbgo/pkg/types" ) var zeroTime time.Time -//var zeroTime time.Time type KLineValueMapper func(k types.KLine) float64 //go:generate callbackgen -type Correlation @@ -82,7 +82,7 @@ func calculateCORRELATION(klines []types.KLine, window int, valA KLineValueMappe // sum of elements of array A sumA += valA(k) // sum of elements of array B - sumB += valA(k) + sumB += valB(k) // sum of A[i] * B[i]. sumAB = sumAB + valA(k)*valB(k)