mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
strategy/linregmaker: add dynamic quantity
This commit is contained in:
parent
9be9ea2a47
commit
8a81e68e27
|
@ -49,7 +49,7 @@ type DynamicExposureBollBand struct {
|
|||
dynamicExposureBollBand *indicator.BOLL
|
||||
}
|
||||
|
||||
// Initialize DynamicExposureBollBand
|
||||
// initialize dynamic exposure with Bollinger Band
|
||||
func (d *DynamicExposureBollBand) initialize(symbol string, session *bbgo.ExchangeSession) {
|
||||
d.dynamicExposureBollBand = d.StandardIndicatorSet.BOLL(d.IntervalWindow, d.BandWidth)
|
||||
|
||||
|
|
93
pkg/dynamicmetric/dynamic_quantity.go
Normal file
93
pkg/dynamicmetric/dynamic_quantity.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
package dynamicmetric
|
||||
|
||||
import (
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/indicator"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// DynamicQuantitySet uses multiple dynamic quantity rules to calculate the total quantity
|
||||
type DynamicQuantitySet []DynamicQuantity
|
||||
|
||||
// Initialize dynamic quantity set
|
||||
func (d *DynamicQuantitySet) Initialize(symbol string, session *bbgo.ExchangeSession) {
|
||||
for i := range *d {
|
||||
(*d)[i].Initialize(symbol, session)
|
||||
}
|
||||
}
|
||||
|
||||
// GetQuantity returns the quantity
|
||||
func (d *DynamicQuantitySet) GetQuantity() (fixedpoint.Value, error) {
|
||||
quantity := fixedpoint.Zero
|
||||
for i := range *d {
|
||||
v, err := (*d)[i].getQuantity()
|
||||
if err != nil {
|
||||
return fixedpoint.Zero, err
|
||||
}
|
||||
quantity = quantity.Add(v)
|
||||
}
|
||||
|
||||
return quantity, nil
|
||||
}
|
||||
|
||||
type DynamicQuantity struct {
|
||||
// LinRegQty calculates quantity based on LinReg slope
|
||||
LinRegDynamicQuantity *DynamicQuantityLinReg `json:"linRegDynamicQuantity"`
|
||||
}
|
||||
|
||||
// Initialize dynamic quantity
|
||||
func (d *DynamicQuantity) Initialize(symbol string, session *bbgo.ExchangeSession) {
|
||||
switch {
|
||||
case d.LinRegDynamicQuantity != nil:
|
||||
d.LinRegDynamicQuantity.initialize(symbol, session)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DynamicQuantity) IsEnabled() bool {
|
||||
return d.LinRegDynamicQuantity != nil
|
||||
}
|
||||
|
||||
// getQuantity returns quantity
|
||||
func (d *DynamicQuantity) getQuantity() (fixedpoint.Value, error) {
|
||||
switch {
|
||||
case d.LinRegDynamicQuantity != nil:
|
||||
return d.LinRegDynamicQuantity.getQuantity()
|
||||
default:
|
||||
return fixedpoint.Zero, errors.New("dynamic quantity is not enabled")
|
||||
}
|
||||
}
|
||||
|
||||
// DynamicQuantityLinReg uses LinReg slope to calculate quantity
|
||||
type DynamicQuantityLinReg struct {
|
||||
// DynamicQuantityLinRegScale is used to define the quantity range with the given parameters.
|
||||
DynamicQuantityLinRegScale *bbgo.PercentageScale `json:"dynamicQuantityLinRegScale"`
|
||||
|
||||
// QuantityLinReg to define the interval and window of the LinReg
|
||||
QuantityLinReg *indicator.LinReg `json:"quantityLinReg"`
|
||||
}
|
||||
|
||||
// initialize LinReg dynamic quantity
|
||||
func (d *DynamicQuantityLinReg) initialize(symbol string, session *bbgo.ExchangeSession) {
|
||||
// Subscribe for LinReg
|
||||
session.Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{
|
||||
Interval: d.QuantityLinReg.Interval,
|
||||
})
|
||||
|
||||
// Initialize LinReg
|
||||
kLineStore, _ := session.MarketDataStore(symbol)
|
||||
d.QuantityLinReg.BindK(session.MarketDataStream, symbol, d.QuantityLinReg.Interval)
|
||||
if klines, ok := kLineStore.KLinesOfInterval(d.QuantityLinReg.Interval); ok {
|
||||
d.QuantityLinReg.LoadK((*klines)[0:])
|
||||
}
|
||||
}
|
||||
|
||||
// getQuantity returns quantity
|
||||
func (d *DynamicQuantityLinReg) getQuantity() (fixedpoint.Value, error) {
|
||||
v, err := d.DynamicQuantityLinRegScale.Scale(d.QuantityLinReg.Last())
|
||||
if err != nil {
|
||||
return fixedpoint.Zero, err
|
||||
}
|
||||
return fixedpoint.NewFromFloat(v), nil
|
||||
}
|
|
@ -48,8 +48,6 @@ type Strategy struct {
|
|||
|
||||
types.IntervalWindow
|
||||
|
||||
bbgo.QuantityOrAmount
|
||||
|
||||
// ReverseEMA is used to determine the long-term trend.
|
||||
// Above the ReverseEMA is the long trend and vise versa.
|
||||
// All the opposite trend position will be closed upon the trend change
|
||||
|
@ -109,15 +107,21 @@ type Strategy struct {
|
|||
DynamicSpread dynamicmetric.DynamicSpread `json:"dynamicSpread,omitempty"`
|
||||
|
||||
// MaxExposurePosition is the maximum position you can hold
|
||||
// +10 means you can hold 10 ETH long position by maximum
|
||||
// -10 means you can hold -10 ETH short position by maximum
|
||||
// 10 means you can hold 10 ETH long/short position by maximum
|
||||
MaxExposurePosition fixedpoint.Value `json:"maxExposurePosition"`
|
||||
|
||||
// DynamicExposure is used to define the exposure position range with the given percentage.
|
||||
// When DynamicExposure is set, your MaxExposurePosition will be calculated dynamically according to the bollinger
|
||||
// band you set.
|
||||
// When DynamicExposure is set, your MaxExposurePosition will be calculated dynamically
|
||||
DynamicExposure dynamicmetric.DynamicExposure `json:"dynamicExposure"`
|
||||
|
||||
bbgo.QuantityOrAmount
|
||||
|
||||
// DynamicQuantityIncrease calculates the increase position order quantity dynamically
|
||||
DynamicQuantityIncrease dynamicmetric.DynamicQuantitySet `json:"dynamicQuantityIncrease"`
|
||||
|
||||
// DynamicQuantityDecrease calculates the decrease position order quantity dynamically
|
||||
DynamicQuantityDecrease dynamicmetric.DynamicQuantitySet `json:"dynamicQuantityDecrease"`
|
||||
|
||||
session *bbgo.ExchangeSession
|
||||
|
||||
// ExitMethods are various TP/SL methods
|
||||
|
@ -197,6 +201,14 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
|||
if s.DynamicExposure.IsEnabled() {
|
||||
s.DynamicExposure.Initialize(s.Symbol, session)
|
||||
}
|
||||
|
||||
// Setup dynamic quantities
|
||||
if len(s.DynamicQuantityIncrease) > 0 {
|
||||
s.DynamicQuantityIncrease.Initialize(s.Symbol, session)
|
||||
}
|
||||
if len(s.DynamicQuantityDecrease) > 0 {
|
||||
s.DynamicQuantityDecrease.Initialize(s.Symbol, session)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Strategy) Validate() error {
|
||||
|
@ -266,10 +278,42 @@ func (s *Strategy) getOrderPrices(midPrice fixedpoint.Value) (askPrice fixedpoin
|
|||
|
||||
// getOrderQuantities returns sell and buy qty
|
||||
func (s *Strategy) getOrderQuantities(askPrice fixedpoint.Value, bidPrice fixedpoint.Value) (sellQuantity fixedpoint.Value, buyQuantity fixedpoint.Value) {
|
||||
// TODO: dynamic qty to determine qty
|
||||
// TODO: spot, margin, and futures
|
||||
sellQuantity = s.QuantityOrAmount.CalculateQuantity(askPrice)
|
||||
buyQuantity = s.QuantityOrAmount.CalculateQuantity(bidPrice)
|
||||
|
||||
// Dynamic qty
|
||||
switch {
|
||||
case s.mainTrendCurrent == types.DirectionUp:
|
||||
var err error
|
||||
if len(s.DynamicQuantityIncrease) > 0 {
|
||||
buyQuantity, err = s.DynamicQuantityIncrease.GetQuantity()
|
||||
if err != nil {
|
||||
buyQuantity = s.QuantityOrAmount.CalculateQuantity(bidPrice)
|
||||
}
|
||||
}
|
||||
if len(s.DynamicQuantityDecrease) > 0 {
|
||||
sellQuantity, err = s.DynamicQuantityDecrease.GetQuantity()
|
||||
if err != nil {
|
||||
sellQuantity = s.QuantityOrAmount.CalculateQuantity(askPrice)
|
||||
}
|
||||
}
|
||||
case s.mainTrendCurrent == types.DirectionDown:
|
||||
var err error
|
||||
if len(s.DynamicQuantityIncrease) > 0 {
|
||||
sellQuantity, err = s.DynamicQuantityIncrease.GetQuantity()
|
||||
if err != nil {
|
||||
sellQuantity = s.QuantityOrAmount.CalculateQuantity(bidPrice)
|
||||
}
|
||||
}
|
||||
if len(s.DynamicQuantityDecrease) > 0 {
|
||||
buyQuantity, err = s.DynamicQuantityDecrease.GetQuantity()
|
||||
if err != nil {
|
||||
buyQuantity = s.QuantityOrAmount.CalculateQuantity(askPrice)
|
||||
}
|
||||
}
|
||||
default:
|
||||
sellQuantity = s.QuantityOrAmount.CalculateQuantity(askPrice)
|
||||
buyQuantity = s.QuantityOrAmount.CalculateQuantity(bidPrice)
|
||||
}
|
||||
|
||||
// Faster position decrease
|
||||
if s.mainTrendCurrent == types.DirectionUp && s.FastLinReg.Last() < 0 && s.SlowLinReg.Last() < 0 {
|
||||
|
|
Loading…
Reference in New Issue
Block a user