mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
pivotshort: fix position close bugs
This commit is contained in:
parent
a5e2c84434
commit
e17535e651
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user