bollmaker: add position stack

This commit is contained in:
austin362667 2022-05-30 15:20:07 +08:00
parent a3ca8326f2
commit 54d60b9890
2 changed files with 61 additions and 33 deletions

View File

@ -16,8 +16,8 @@ backtest:
# 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-01-01"
endTime: "2022-05-12"
startTime: "2022-05-01"
endTime: "2022-05-31"
sessions:
- binance
symbols:
@ -26,7 +26,7 @@ backtest:
binance:
balances:
ETH: 0.0
USDT: 10_000.0
USDT: 100_000.0
exchangeStrategies:
@ -38,7 +38,14 @@ exchangeStrategies:
interval: 1m
# quantity is the base order quantity for your buy/sell order.
quantity: 0.05
# quantity: 0.05
amount: 20
# Position Stack, with longer stack length, may need more capital.
# Push position in stack is initiating a position to calculate base, average cost, etc.
# Pop position in stack is loading a previous position back.
pushThreshold: 10%
# popThreshold : 1%
# useTickerPrice use the ticker api to get the mid price instead of the closed kline price.
# The back-test engine is kline-based, so the ticker price api is not supported.
@ -103,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: [10.0, 1.0 ]
# DisableShort means you can don't want short position during the market making
# THe short here means you might sell some of your existing inventory.
@ -136,25 +143,25 @@ exchangeStrategies:
# Set up your stop order, this is optional
# sometimes the stop order might decrease your total profit.
# you can setup multiple stop,
stops:
# stops:
# use trailing stop order
- trailingStop:
# callbackRate: when the price reaches -1% from the previous highest, we trigger the stop
callbackRate: 5.1%
# closePosition is how much position do you want to close
closePosition: 20%
# minProfit is how much profit you want to take.
# if you set this option, your stop will only be triggered above the average cost.
minProfit: 5%
# interval is the time interval for checking your stop
interval: 1m
# virtual means we don't place a a REAL stop order
# when virtual is on
# the strategy won't place a REAL stop order, instead if watches the close price,
# and if the condition matches, it submits a market order to close your position.
virtual: true
# - trailingStop:
# # callbackRate: when the price reaches -1% from the previous highest, we trigger the stop
# callbackRate: 5.1%
#
# # closePosition is how much position do you want to close
# closePosition: 20%
#
# # minProfit is how much profit you want to take.
# # if you set this option, your stop will only be triggered above the average cost.
# minProfit: 5%
#
# # interval is the time interval for checking your stop
# interval: 1m
#
# # virtual means we don't place a a REAL stop order
# # when virtual is on
# # the strategy won't place a REAL stop order, instead if watches the close price,
# # and if the condition matches, it submits a market order to close your position.
# virtual: true

View File

@ -228,8 +228,11 @@ type Strategy struct {
state *State
// persistence fields
Position *types.Position `json:"position,omitempty" persistence:"position"`
ProfitStats *types.ProfitStats `json:"profitStats,omitempty" persistence:"profit_stats"`
Position *types.PositionStack `json:"position,omitempty" persistence:"position"`
ProfitStats *types.ProfitStats `json:"profitStats,omitempty" persistence:"profit_stats"`
PushThreshold fixedpoint.Value `json:"pushThreshold,omitempty"`
PopThreshold fixedpoint.Value `json:"popThreshold,omitempty"`
activeMakerOrders *bbgo.LocalActiveOrderBook
orderStore *bbgo.OrderStore
@ -289,7 +292,7 @@ func (s *Strategy) Validate() error {
return nil
}
func (s *Strategy) CurrentPosition() *types.Position {
func (s *Strategy) CurrentPosition() *types.PositionStack {
return s.Position
}
@ -652,9 +655,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
if s.Position == nil {
// fallback to the legacy position struct in the state
if s.state != nil && s.state.Position != nil {
s.Position = s.state.Position
s.Position.Position = s.state.Position
} else {
s.Position = types.NewPositionFromMarket(s.Market)
s.Position = types.NewPositionStackFromMarket(s.Market)
}
}
@ -699,7 +702,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.ProfitStats.AddTrade(trade)
if profit.Compare(fixedpoint.Zero) == 0 {
s.Environment.RecordPosition(s.Position, trade, nil)
s.Environment.RecordPosition(s.Position.Position, trade, nil)
} else {
log.Infof("%s generated profit: %v", s.Symbol, profit)
p := s.Position.NewProfit(trade, profit, netProfit)
@ -710,11 +713,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.ProfitStats.AddProfit(p)
s.Notify(&s.ProfitStats)
s.Environment.RecordPosition(s.Position, trade, &p)
s.Environment.RecordPosition(s.Position.Position, trade, &p)
}
})
s.tradeCollector.OnPositionUpdate(func(position *types.Position) {
s.tradeCollector.OnPositionUpdate(func(position types.PositionInterface) {
log.Infof("position changed: %s", s.Position)
s.Notify(s.Position)
})
@ -772,7 +775,25 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
if err := s.activeMakerOrders.GracefulCancel(ctx, s.session.Exchange); err != nil {
log.WithError(err).Errorf("graceful cancel order error")
}
//log.Error(len(s.Position.Stack), s.Position.AverageCost, kline.Close)
if s.Position.Position.AverageCost.Div(kline.Close).Compare(fixedpoint.One.Add(s.PushThreshold)) > 0 {
log.Errorf("push")
log.Error(s.Position)
s.Position = s.Position.Push(types.NewPositionFromMarket(s.Market))
}
// &&
if len(s.Position.Stack) > 1 && s.Position.Stack[len(s.Position.Stack)-2].AverageCost.Compare(kline.Close) < 0 && s.Market.IsDustQuantity(s.Position.Position.GetBase(), kline.Close) {
log.Errorf("pop")
log.Error(s.Position)
s.Position = s.Position.Pop()
}
//if s.Position.AverageCost.Div(kline.Close).Compare(fixedpoint.One.Sub(s.PopThreshold)) < 0 && && !s.Position.AverageCost.IsZero() {
// //log.Error(len(s.Position.Stack), s.Position.AverageCost, kline.Close)
// log.Errorf("pop")
// s.ClosePosition(ctx, fixedpoint.One)
// s.Position = s.Position.Pop()
//}
// check if there is a canceled order had partially filled.
s.tradeCollector.Process()