pivotshort: fix position close bugs

This commit is contained in:
c9s 2022-06-09 12:25:36 +08:00
parent a5e2c84434
commit e17535e651
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
3 changed files with 32 additions and 13 deletions

View File

@ -2,9 +2,10 @@ package indicator
import (
"fmt"
log "github.com/sirupsen/logrus"
"time"
log "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/types"
)
@ -45,17 +46,19 @@ func (inc *Pivot) calculateAndUpdate(klines []types.KLine) {
var end = len(klines) - 1
var lastKLine = klines[end]
// skip old data
if inc.EndTime != zeroTime && lastKLine.GetEndTime().Before(inc.EndTime) {
return
}
var recentT = klines[end-(inc.Window-1) : end+1]
recentT := klines[end-(inc.Window-1) : end+1]
l, h, err := calculatePivot(recentT, inc.Window, KLineLowPriceMapper, KLineHighPriceMapper)
if err != nil {
log.WithError(err).Error("can not calculate pivots")
return
}
inc.Lows.Push(l)
inc.Highs.Push(h)
@ -87,8 +90,9 @@ func (inc *Pivot) Bind(updater KLineWindowUpdater) {
func calculatePivot(klines []types.KLine, window int, valLow KLineValueMapper, valHigh KLineValueMapper) (float64, float64, error) {
length := len(klines)
if length == 0 || length < window {
return 0., 0., fmt.Errorf("insufficient elements for calculating with window = %d", window)
return 0., 0., fmt.Errorf("insufficient elements for calculating with window = %d", window)
}
var lows types.Float64Slice
var highs types.Float64Slice
for _, k := range klines {
@ -100,6 +104,7 @@ func calculatePivot(klines []types.KLine, window int, valLow KLineValueMapper, v
if lows.Min() == lows.Index(int(window/2.)-1) {
pl = lows.Min()
}
ph := 0.
if highs.Max() == highs.Index(int(window/2.)-1) {
ph = highs.Max()

View File

@ -132,6 +132,9 @@ func canClosePosition(position *types.Position, price fixedpoint.Value) bool {
func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Value) error {
submitOrder := s.Position.NewClosePositionOrder(percentage) // types.SubmitOrder{
if submitOrder == nil {
return nil
}
if s.session.Margin {
submitOrder.MarginSideEffect = s.Exit.MarginSideEffect
@ -238,27 +241,34 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
R := kline.Close.Sub(s.Position.AverageCost).Div(s.Position.AverageCost)
if R.Compare(s.Exit.StopLossPercentage) > 0 {
// SL
s.Notify("%s SL triggered", s.Symbol)
s.ClosePosition(ctx, fixedpoint.One.Div(fixedpoint.NewFromFloat(0.99)))
s.Notify("%s SL triggered at price %f", s.Symbol, kline.Close.Float64())
s.ClosePosition(ctx, fixedpoint.One)
return
} else if R.Compare(s.Exit.TakeProfitPercentage.Neg()) < 0 && kline.GetLowerShadowRatio().Compare(s.Exit.LowerShadowRatio) > 0 {
// TP
s.Notify("%s TP triggered", s.Symbol)
s.ClosePosition(ctx, fixedpoint.One.Div(fixedpoint.NewFromFloat(0.99)))
s.Notify("%s TP triggered at price %f", s.Symbol, kline.Close.Float64())
s.ClosePosition(ctx, fixedpoint.One)
return
}
}
if len(s.pivotLowPrices) > 0 {
latestPivotLow := s.pivotLowPrices[len(s.pivotLowPrices)-1]
lastLow := s.pivotLowPrices[len(s.pivotLowPrices)-1]
if kline.Close.Compare(lastLow) < 0 {
s.Notify("%s price %f breaks the previous low %f, submitting market sell to open a short position", s.Symbol, kline.Close.Float64(), lastLow.Float64())
if !s.Position.IsClosed() && !s.Position.IsDust(kline.Close) {
s.Notify("skip opening %s position, which is not closed", s.Symbol, s.Position)
return
}
if kline.Close.Compare(latestPivotLow) > 0 && (s.Position.IsClosed() || s.Position.IsDust(kline.Close)) {
if err := s.activeMakerOrders.GracefulCancel(ctx, s.session.Exchange); err != nil {
log.WithError(err).Errorf("graceful cancel order error")
}
s.Notify("price breaks the previous low, submitting market sell to open a short position")
s.placeMarketSell(ctx, orderExecutor)
}
}
})
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
@ -271,7 +281,6 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.LastLow = fixedpoint.NewFromFloat(s.pivot.LastLow())
s.pivotLowPrices = append(s.pivotLowPrices, s.LastLow)
}
})
return nil

View File

@ -122,7 +122,12 @@ func (p *Position) NewProfit(trade Trade, profit, netProfit fixedpoint.Value) Pr
func (p *Position) NewClosePositionOrder(percentage fixedpoint.Value) *SubmitOrder {
base := p.GetBase()
quantity := base.Mul(percentage).Abs()
quantity := base.Abs()
if percentage.Compare(fixedpoint.One) < 0 {
quantity = quantity.Mul(percentage)
}
if quantity.Compare(p.Market.MinQuantity) < 0 {
return nil
}