strategy/linregmaker: works w/o dynamic qty

This commit is contained in:
Andy Cheng 2022-11-23 16:53:08 +08:00
parent e776c9e5ea
commit cc124d4264
4 changed files with 27 additions and 62 deletions

View File

@ -110,7 +110,7 @@ exchangeStrategies:
domain: [ -1, 1 ]
# when in down band, holds 1.0 by maximum
# when in up band, holds 0.05 by maximum
range: [ 10.0, 1.0 ]
range: [ 1.0, 1.0 ]
# quantity is the base order quantity for your buy/sell order.
quantity: 0.1

View File

@ -1,9 +0,0 @@
package dynamicmetric
import "github.com/c9s/bbgo/pkg/types"
// BollingerSetting is for Bollinger Band settings
type BollingerSetting struct {
types.IntervalWindow
BandWidth float64 `json:"bandWidth"`
}

View File

@ -16,18 +16,6 @@ type DynamicSpread struct {
// WeightedBollWidthRatioSpread calculates spreads based on two Bollinger Bands
WeightedBollWidthRatioSpread *DynamicSpreadBollWidthRatio `json:"weightedBollWidth"`
// deprecated
Enabled *bool `json:"enabled"`
// deprecated
types.IntervalWindow
// deprecated. AskSpreadScale is used to define the ask spread range with the given percentage.
AskSpreadScale *bbgo.PercentageScale `json:"askSpreadScale"`
// deprecated. BidSpreadScale is used to define the bid spread range with the given percentage.
BidSpreadScale *bbgo.PercentageScale `json:"bidSpreadScale"`
}
// Initialize dynamic spread
@ -37,14 +25,6 @@ func (ds *DynamicSpread) Initialize(symbol string, session *bbgo.ExchangeSession
ds.AmpSpread.initialize(symbol, session)
case ds.WeightedBollWidthRatioSpread != nil:
ds.WeightedBollWidthRatioSpread.initialize(symbol, session)
case ds.Enabled != nil && *ds.Enabled:
// backward compatibility
ds.AmpSpread = &DynamicSpreadAmp{
IntervalWindow: ds.IntervalWindow,
AskSpreadScale: ds.AskSpreadScale,
BidSpreadScale: ds.BidSpreadScale,
}
ds.AmpSpread.initialize(symbol, session)
}
}
@ -171,8 +151,8 @@ type DynamicSpreadBollWidthRatio struct {
// A positive number. The greater factor, the sharper weighting function. Default set to 1.0 .
Sensitivity float64 `json:"sensitivity"`
DefaultBollinger *BollingerSetting `json:"defaultBollinger"`
NeutralBollinger *BollingerSetting `json:"neutralBollinger"`
DefaultBollinger types.IntervalWindowBandWidth `json:"defaultBollinger"`
NeutralBollinger types.IntervalWindowBandWidth `json:"neutralBollinger"`
neutralBoll *indicator.BOLL
defaultBoll *indicator.BOLL
@ -232,7 +212,7 @@ func (ds *DynamicSpreadBollWidthRatio) getWeightedBBWidthRatio(positiveSigmoid b
// - To bid spread, the weighting density function d_weight(x) is sigmoid((default_BB_mid - x) / (w / alpha))
// - The higher sensitivity factor alpha, the sharper weighting function.
//
// Then calculate the weighted band width ratio by taking integral of d_weight(x) from neutral_BB_lower to neutral_BB_upper:
// Then calculate the weighted bandwidth ratio by taking integral of d_weight(x) from neutral_BB_lower to neutral_BB_upper:
// infinite integral of ask spread sigmoid weighting density function F(x) = (w / alpha) * ln(exp(x / (w / alpha)) + exp(default_BB_mid / (w / alpha)))
// infinite integral of bid spread sigmoid weighting density function F(x) = x - (w / alpha) * ln(exp(x / (w / alpha)) + exp(default_BB_mid / (w / alpha)))
// Note that we've rescaled the sigmoid function to fit default BB,

View File

@ -25,17 +25,12 @@ var two = fixedpoint.NewFromInt(2)
var log = logrus.WithField("strategy", ID)
//TODO: Logic for backtest
// TODO: Dynamic exposure should work on both side
func init() {
bbgo.RegisterStrategy(ID, &Strategy{})
}
// TODO: Remove BollingerSetting and bollsetting.go
type BollingerSetting struct {
types.IntervalWindow
BandWidth float64 `json:"bandWidth"`
}
type Strategy struct {
Environment *bbgo.Environment
StandardIndicatorSet *bbgo.StandardIndicatorSet
@ -77,7 +72,10 @@ type Strategy struct {
// NeutralBollinger is the smaller range of the bollinger band
// If price is in this band, it usually means the price is oscillating.
// If price goes out of this band, we tend to not place sell orders or buy orders
NeutralBollinger *BollingerSetting `json:"neutralBollinger"`
NeutralBollinger types.IntervalWindowBandWidth `json:"neutralBollinger"`
// neutralBoll is the neutral price section for TradeInBand
neutralBoll *indicator.BOLL
// TradeInBand
// When this is on, places orders only when the current price is in the bollinger band.
@ -113,7 +111,7 @@ type Strategy struct {
DynamicExposure dynamicmetric.DynamicExposure `json:"dynamicExposure"`
bbgo.QuantityOrAmount
// TODO: Should work w/o dynamic qty
// DynamicQuantityIncrease calculates the increase position order quantity dynamically
DynamicQuantityIncrease dynamicmetric.DynamicQuantitySet `json:"dynamicQuantityIncrease"`
@ -134,9 +132,6 @@ type Strategy struct {
groupID uint32
// neutralBoll is the neutral price section
neutralBoll *indicator.BOLL
// StrategyController
bbgo.StrategyController
}
@ -176,7 +171,7 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
}
// Subscribe for BBs
if s.NeutralBollinger != nil && s.NeutralBollinger.Interval != "" {
if s.NeutralBollinger.Interval != "" {
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{
Interval: s.NeutralBollinger.Interval,
})
@ -276,39 +271,38 @@ func (s *Strategy) getOrderPrices(midPrice fixedpoint.Value) (askPrice fixedpoin
func (s *Strategy) getOrderQuantities(askPrice fixedpoint.Value, bidPrice fixedpoint.Value) (sellQuantity fixedpoint.Value, buyQuantity fixedpoint.Value) {
// TODO: spot, margin, and futures
// Default
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)
qty, err := s.DynamicQuantityIncrease.GetQuantity()
if err == nil {
buyQuantity = qty
}
}
if len(s.DynamicQuantityDecrease) > 0 {
sellQuantity, err = s.DynamicQuantityDecrease.GetQuantity()
if err != nil {
sellQuantity = s.QuantityOrAmount.CalculateQuantity(askPrice)
qty, err := s.DynamicQuantityDecrease.GetQuantity()
if err == nil {
sellQuantity = qty
}
}
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)
qty, err := s.DynamicQuantityIncrease.GetQuantity()
if err == nil {
sellQuantity = qty
}
}
if len(s.DynamicQuantityDecrease) > 0 {
buyQuantity, err = s.DynamicQuantityDecrease.GetQuantity()
if err != nil {
buyQuantity = s.QuantityOrAmount.CalculateQuantity(askPrice)
qty, err := s.DynamicQuantityDecrease.GetQuantity()
if err == nil {
buyQuantity = qty
}
}
default:
sellQuantity = s.QuantityOrAmount.CalculateQuantity(askPrice)
buyQuantity = s.QuantityOrAmount.CalculateQuantity(bidPrice)
}
// Faster position decrease