mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
Rebalance on kline closed
This commit is contained in:
parent
ae4a3d81fb
commit
83e37f52a8
|
@ -7,7 +7,7 @@ notifications:
|
||||||
exchangeStrategies:
|
exchangeStrategies:
|
||||||
- on: max
|
- on: max
|
||||||
rebalance:
|
rebalance:
|
||||||
interval: 24h
|
interval: 1d
|
||||||
baseCurrency: TWD
|
baseCurrency: TWD
|
||||||
ignoreLocked: true
|
ignoreLocked: true
|
||||||
targetWeights:
|
targetWeights:
|
||||||
|
@ -20,3 +20,4 @@ exchangeStrategies:
|
||||||
# max amount to buy or sell per order
|
# max amount to buy or sell per order
|
||||||
maxAmount: 10_000
|
maxAmount: 10_000
|
||||||
verbose: true
|
verbose: true
|
||||||
|
dryRun: false
|
||||||
|
|
|
@ -3,14 +3,12 @@ package kline
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const ID = "rebalance"
|
const ID = "rebalance"
|
||||||
|
@ -53,13 +51,13 @@ func ElementwiseProduct(m1, m2 map[string]fixedpoint.Value) map[string]fixedpoin
|
||||||
type Strategy struct {
|
type Strategy struct {
|
||||||
Notifiability *bbgo.Notifiability
|
Notifiability *bbgo.Notifiability
|
||||||
|
|
||||||
Interval types.Duration `json:"interval"`
|
Interval types.Interval `json:"interval"`
|
||||||
BaseCurrency string `json:"baseCurrency"`
|
BaseCurrency string `json:"baseCurrency"`
|
||||||
TargetWeights map[string]fixedpoint.Value `json:"targetWeights"`
|
TargetWeights map[string]fixedpoint.Value `json:"targetWeights"`
|
||||||
Threshold fixedpoint.Value `json:"threshold"`
|
Threshold fixedpoint.Value `json:"threshold"`
|
||||||
IgnoreLocked bool `json:"ignoreLocked"`
|
IgnoreLocked bool `json:"ignoreLocked"`
|
||||||
Verbose bool `json:"verbose"`
|
Verbose bool `json:"verbose"`
|
||||||
|
DryRun bool `json:"dryRun"`
|
||||||
// max amount to buy or sell per order
|
// max amount to buy or sell per order
|
||||||
MaxAmount fixedpoint.Value `json:"maxAmount"`
|
MaxAmount fixedpoint.Value `json:"maxAmount"`
|
||||||
}
|
}
|
||||||
|
@ -69,10 +67,6 @@ func (s *Strategy) ID() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) Validate() error {
|
func (s *Strategy) Validate() error {
|
||||||
if s.Interval == 0 {
|
|
||||||
return fmt.Errorf("interval shoud not be 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.TargetWeights) == 0 {
|
if len(s.TargetWeights) == 0 {
|
||||||
return fmt.Errorf("targetWeights should not be empty")
|
return fmt.Errorf("targetWeights should not be empty")
|
||||||
}
|
}
|
||||||
|
@ -94,26 +88,17 @@ func (s *Strategy) Validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {}
|
func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
||||||
|
for _, symbol := range s.getSymbols() {
|
||||||
|
session.Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{Interval: s.Interval.String()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
||||||
s.TargetWeights = Normalize(s.TargetWeights)
|
s.TargetWeights = Normalize(s.TargetWeights)
|
||||||
|
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
||||||
go func() {
|
s.rebalance(ctx, orderExecutor, session)
|
||||||
ticker := time.NewTicker(util.MillisecondsJitter(s.Interval.Duration(), 1000))
|
})
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
|
|
||||||
case <-ticker.C:
|
|
||||||
s.rebalance(ctx, orderExecutor, session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +113,14 @@ func (s *Strategy) rebalance(ctx context.Context, orderExecutor bbgo.OrderExecut
|
||||||
marketValues := ElementwiseProduct(prices, quantities)
|
marketValues := ElementwiseProduct(prices, quantities)
|
||||||
|
|
||||||
orders := s.generateSubmitOrders(prices, marketValues)
|
orders := s.generateSubmitOrders(prices, marketValues)
|
||||||
|
for _, order := range orders {
|
||||||
|
log.Infof("generated submit order: %s", order.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.DryRun {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
_, err = orderExecutor.SubmitOrders(ctx, orders...)
|
_, err = orderExecutor.SubmitOrders(ctx, orders...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("submit order error")
|
log.WithError(err).Error("submit order error")
|
||||||
|
@ -231,3 +224,15 @@ func (s *Strategy) generateSubmitOrders(prices, marketValues map[string]fixedpoi
|
||||||
}
|
}
|
||||||
return submitOrders
|
return submitOrders
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) getSymbols() []string {
|
||||||
|
var symbols []string
|
||||||
|
for currency := range s.TargetWeights {
|
||||||
|
if currency == s.BaseCurrency {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
symbol := currency + s.BaseCurrency
|
||||||
|
symbols = append(symbols, symbol)
|
||||||
|
}
|
||||||
|
return symbols
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user