mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 01:01:56 +00:00
factorzoo: add comments for strategy
factorzoo: add comments for strategy
This commit is contained in:
parent
d282568614
commit
bb4db871b2
|
@ -2,6 +2,7 @@ package factorzoo
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/indicator"
|
||||
|
@ -22,12 +23,11 @@ type Linear struct {
|
|||
StopEMA *types.IntervalWindow `json:"stopEMA"`
|
||||
|
||||
// Xs (input), factors & indicators
|
||||
divergence *factorzoo.AVD // amplitude volume divergence
|
||||
reversion *factorzoo.PMR // price mean reversion
|
||||
momentum *factorzoo.MOM // price momentum from WorldQuant's paper, alpha 101
|
||||
drift *indicator.Drift
|
||||
divergence *factorzoo.PVD // price volume divergence
|
||||
reversion *factorzoo.PMR // price mean reversion
|
||||
momentum *factorzoo.MOM // price momentum from paper, alpha 101
|
||||
drift *indicator.Drift // GBM
|
||||
volume *factorzoo.VMOM // quarterly volume momentum
|
||||
bars *factorzoo.LSBAR // long short bar accumulation
|
||||
|
||||
// Y (output), internal rate of return
|
||||
irr *factorzoo.RR
|
||||
|
@ -51,28 +51,22 @@ func (s *Linear) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.General
|
|||
symbol := position.Symbol
|
||||
store, _ := session.MarketDataStore(symbol)
|
||||
|
||||
s.divergence = &factorzoo.AVD{IntervalWindow: types.IntervalWindow{Window: s.Window, Interval: s.Interval}}
|
||||
// initialize factor indicators
|
||||
s.divergence = &factorzoo.PVD{IntervalWindow: types.IntervalWindow{Window: 60, Interval: s.Interval}}
|
||||
s.divergence.Bind(store)
|
||||
preloadDivergence(s.divergence, store)
|
||||
s.reversion = &factorzoo.PMR{IntervalWindow: types.IntervalWindow{Window: s.Window, Interval: s.Interval}}
|
||||
s.reversion = &factorzoo.PMR{IntervalWindow: types.IntervalWindow{Window: 60, Interval: s.Interval}}
|
||||
s.reversion.Bind(store)
|
||||
preloadReversion(s.reversion, store)
|
||||
s.drift = &indicator.Drift{IntervalWindow: types.IntervalWindow{Window: 5, Interval: s.Interval}}
|
||||
s.drift = &indicator.Drift{IntervalWindow: types.IntervalWindow{Window: 7, Interval: s.Interval}}
|
||||
s.drift.Bind(store)
|
||||
preloadDrift(s.drift, store)
|
||||
s.momentum = &factorzoo.MOM{IntervalWindow: types.IntervalWindow{Window: 1, Interval: s.Interval}}
|
||||
s.momentum.Bind(store)
|
||||
preloadMomentum(s.momentum, store)
|
||||
s.volume = &factorzoo.VMOM{IntervalWindow: types.IntervalWindow{Window: 90, Interval: s.Interval}}
|
||||
s.volume.Bind(store)
|
||||
preloadVolume(s.volume, store)
|
||||
s.bars = &factorzoo.LSBAR{IntervalWindow: types.IntervalWindow{Window: 360, Interval: s.Interval}}
|
||||
s.bars.Bind(store)
|
||||
preloadBars(s.bars, store)
|
||||
|
||||
s.irr = &factorzoo.RR{IntervalWindow: types.IntervalWindow{Window: 2, Interval: s.Interval}}
|
||||
s.irr.Bind(store)
|
||||
preloadIRR(s.irr, store)
|
||||
|
||||
predLst := types.NewQueue(s.Window)
|
||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
@ -80,14 +74,20 @@ func (s *Linear) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.General
|
|||
// graceful cancel all active orders
|
||||
_ = orderExecutor.GracefulCancel(ctx)
|
||||
|
||||
a := []types.Float64Slice{s.divergence.Values[len(s.divergence.Values)-s.Window : len(s.divergence.Values)-2],
|
||||
s.reversion.Values[len(s.reversion.Values)-s.Window : len(s.reversion.Values)-2],
|
||||
s.drift.Values[len(s.drift.Values)-s.Window : len(s.drift.Values)-2],
|
||||
s.momentum.Values[len(s.momentum.Values)-s.Window : len(s.momentum.Values)-2],
|
||||
s.volume.Values[len(s.volume.Values)-s.Window : len(s.volume.Values)-2],
|
||||
//s.bars.Values[len(s.bars.Values)-s.Window : len(s.bars.Values)-2],
|
||||
// take past window days' values to predict future return
|
||||
// (e.g., 5 here in default configuration file)
|
||||
a := []types.Float64Slice{
|
||||
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],
|
||||
s.momentum.Values[len(s.momentum.Values)-s.Window-2 : len(s.momentum.Values)-2],
|
||||
s.volume.Values[len(s.volume.Values)-s.Window-2 : len(s.volume.Values)-2],
|
||||
}
|
||||
b := []types.Float64Slice{filter(s.irr.Values[len(s.irr.Values)-(s.Window-1):len(s.irr.Values)-(2-1)], binary)}
|
||||
// e.g., s.window is 5
|
||||
// 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)}
|
||||
var x []types.Series
|
||||
var y []types.Series
|
||||
|
||||
|
@ -99,37 +99,53 @@ func (s *Linear) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.General
|
|||
//x = append(x, &a[5])
|
||||
|
||||
y = append(y, &b[0])
|
||||
//log.Infof("actual: %f", y[0])
|
||||
|
||||
model := types.LogisticRegression(x, y[0], s.Window, 8000, 0.0001)
|
||||
|
||||
// use the last value from indicators, or the SeriesExtends' predict function. (e.g., look back: 5)
|
||||
input := []float64{
|
||||
s.divergence.Predict(5, 20),
|
||||
s.reversion.Predict(5, 20),
|
||||
s.drift.Predict(5, 20),
|
||||
s.momentum.Predict(5, 20),
|
||||
s.volume.Predict(5, 20),
|
||||
//s.bars.Predict(5, 20),
|
||||
s.divergence.Last(),
|
||||
s.reversion.Last(),
|
||||
s.drift.Last(),
|
||||
s.momentum.Last(),
|
||||
s.volume.Last(),
|
||||
}
|
||||
//log.Info(input)
|
||||
pred := model.Predict(input)
|
||||
//log.Infof("prediction: %f", pred)
|
||||
//qty := s.QuantityOrAmount.CalculateQuantity(kline.Close)
|
||||
if pred > 0.5 {
|
||||
if position.IsShort() && !position.IsDust(kline.Close) {
|
||||
predLst.Update(pred)
|
||||
|
||||
qty := s.Quantity //s.QuantityOrAmount.CalculateQuantity(kline.Close)
|
||||
|
||||
// the scale of pred is from 0.0 to 1.0
|
||||
// 0.5 can be used as the threshold
|
||||
// we use the time-series rolling prediction values here
|
||||
if pred > predLst.Mean() {
|
||||
if position.IsShort() {
|
||||
s.ClosePosition(ctx, one)
|
||||
s.placeMarketOrder(ctx, types.SideTypeBuy, s.Quantity, symbol)
|
||||
} else if position.IsClosed() || position.IsDust(kline.Close) {
|
||||
s.placeMarketOrder(ctx, types.SideTypeBuy, s.Quantity, symbol)
|
||||
s.placeMarketOrder(ctx, types.SideTypeBuy, qty, symbol)
|
||||
} else if position.IsClosed() {
|
||||
s.placeMarketOrder(ctx, types.SideTypeBuy, qty, symbol)
|
||||
}
|
||||
} else if pred < 0.5 {
|
||||
if position.IsLong() && !position.IsDust(kline.Close) {
|
||||
} else if pred < predLst.Mean() {
|
||||
if position.IsLong() {
|
||||
s.ClosePosition(ctx, one)
|
||||
s.placeMarketOrder(ctx, types.SideTypeSell, s.Quantity, symbol)
|
||||
} else if position.IsClosed() || position.IsDust(kline.Close) {
|
||||
s.placeMarketOrder(ctx, types.SideTypeSell, s.Quantity, symbol)
|
||||
s.placeMarketOrder(ctx, types.SideTypeSell, qty, symbol)
|
||||
} else if position.IsClosed() {
|
||||
s.placeMarketOrder(ctx, types.SideTypeSell, qty, symbol)
|
||||
}
|
||||
}
|
||||
// pass if position is opened and not dust, and remain the same direction with alpha signal
|
||||
|
||||
// alpha-weighted inventory and cash
|
||||
//alpha := fixedpoint.NewFromFloat(s.r1.Last())
|
||||
//targetBase := s.QuantityOrAmount.CalculateQuantity(kline.Close).Mul(alpha)
|
||||
////s.ClosePosition(ctx, one)
|
||||
//diffQty := targetBase.Sub(position.Base)
|
||||
//log.Info(alpha.Float64(), position.Base, diffQty.Float64())
|
||||
//
|
||||
//if diffQty.Sign() > 0 {
|
||||
// s.placeMarketOrder(ctx, types.SideTypeBuy, diffQty.Abs(), symbol)
|
||||
//} else if diffQty.Sign() < 0 {
|
||||
// s.placeMarketOrder(ctx, types.SideTypeSell, diffQty.Abs(), symbol)
|
||||
//}
|
||||
}))
|
||||
|
||||
if !bbgo.IsBackTesting {
|
||||
|
@ -158,103 +174,6 @@ func (s *Linear) placeMarketOrder(ctx context.Context, side types.SideType, quan
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Linear) placeLimitOrder(ctx context.Context, side types.SideType, quantity fixedpoint.Value, price fixedpoint.Value, symbol string) {
|
||||
market, _ := s.session.Market(symbol)
|
||||
_, err := s.orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
||||
Symbol: symbol,
|
||||
Market: market,
|
||||
Side: side,
|
||||
Type: types.OrderTypeLimitMaker,
|
||||
Quantity: quantity,
|
||||
Price: price,
|
||||
//TimeInForce: types.TimeInForceGTC,
|
||||
Tag: "linearLimit",
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not place market order")
|
||||
}
|
||||
}
|
||||
|
||||
func preloadDivergence(divergence *factorzoo.AVD, store *bbgo.MarketDataStore) {
|
||||
klines, _ := store.KLinesOfInterval(divergence.Interval)
|
||||
|
||||
log.Debugf("updating divergence indicator: %d klines", len(*klines))
|
||||
|
||||
for i := 0; i < len(*klines); i++ {
|
||||
divergence.Update(*klines)
|
||||
}
|
||||
}
|
||||
|
||||
func preloadReversion(reversion *factorzoo.PMR, store *bbgo.MarketDataStore) {
|
||||
klines, _ := store.KLinesOfInterval(reversion.Interval)
|
||||
|
||||
log.Debugf("updating reversion indicator: %d klines", len(*klines))
|
||||
|
||||
for i := 0; i < len(*klines); i++ {
|
||||
reversion.Update(*klines)
|
||||
}
|
||||
}
|
||||
|
||||
func preloadDrift(drift *indicator.Drift, store *bbgo.MarketDataStore) {
|
||||
klines, _ := store.KLinesOfInterval(drift.Interval)
|
||||
|
||||
log.Debugf("updating drift indicator: %d klines", len(*klines))
|
||||
|
||||
for i := 0; i < len(*klines); i++ {
|
||||
drift.CalculateAndUpdate(*klines)
|
||||
}
|
||||
}
|
||||
|
||||
func preloadMomentum(momentum *factorzoo.MOM, store *bbgo.MarketDataStore) {
|
||||
klines, _ := store.KLinesOfInterval(momentum.Interval)
|
||||
|
||||
log.Debugf("updating momentum indicator: %d klines", len(*klines))
|
||||
|
||||
for i := 0; i < len(*klines); i++ {
|
||||
momentum.Update(*klines)
|
||||
}
|
||||
}
|
||||
|
||||
func preloadMomentum2(momentum *factorzoo.MOM2, store *bbgo.MarketDataStore) {
|
||||
klines, _ := store.KLinesOfInterval(momentum.Interval)
|
||||
|
||||
log.Debugf("updating momentum2 indicator: %d klines", len(*klines))
|
||||
|
||||
for i := 0; i < len(*klines); i++ {
|
||||
momentum.Update(*klines)
|
||||
}
|
||||
}
|
||||
|
||||
func preloadVolume(momentum *factorzoo.VMOM, store *bbgo.MarketDataStore) {
|
||||
klines, _ := store.KLinesOfInterval(momentum.Interval)
|
||||
|
||||
log.Debugf("updating volume momentum indicator: %d klines", len(*klines))
|
||||
|
||||
for i := 0; i < len(*klines); i++ {
|
||||
momentum.Update(*klines)
|
||||
}
|
||||
}
|
||||
|
||||
func preloadBars(bars *factorzoo.LSBAR, store *bbgo.MarketDataStore) {
|
||||
klines, _ := store.KLinesOfInterval(bars.Interval)
|
||||
|
||||
log.Debugf("updating long short bars indicator: %d klines", len(*klines))
|
||||
|
||||
for i := 0; i < len(*klines); i++ {
|
||||
bars.Update(*klines)
|
||||
}
|
||||
}
|
||||
|
||||
func preloadIRR(irr *factorzoo.RR, store *bbgo.MarketDataStore) {
|
||||
klines, _ := store.KLinesOfInterval(irr.Interval)
|
||||
|
||||
log.Debugf("updating irr indicator: %d klines", len(*klines))
|
||||
|
||||
for i := 0; i < len(*klines); i++ {
|
||||
irr.CalculateAndUpdate(*klines)
|
||||
}
|
||||
}
|
||||
|
||||
func binary(val float64) float64 {
|
||||
if val > 0. {
|
||||
return 1.
|
||||
|
|
Loading…
Reference in New Issue
Block a user