mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 14:55:16 +00:00
pivotshort: refactor exit methods
Signed-off-by: c9s <yoanlin93@gmail.com>
This commit is contained in:
parent
47677e303f
commit
e9b87f6f1e
64
pkg/strategy/pivotshort/cumulated_volume_take_profit.go
Normal file
64
pkg/strategy/pivotshort/cumulated_volume_take_profit.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package pivotshort
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
type CumulatedVolumeTakeProfit struct {
|
||||
types.IntervalWindow
|
||||
Ratio fixedpoint.Value `json:"ratio"`
|
||||
MinQuoteVolume fixedpoint.Value `json:"minQuoteVolume"`
|
||||
|
||||
session *bbgo.ExchangeSession
|
||||
orderExecutor *bbgo.GeneralOrderExecutor
|
||||
}
|
||||
|
||||
func (s *CumulatedVolumeTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
|
||||
s.session = session
|
||||
s.orderExecutor = orderExecutor
|
||||
|
||||
position := orderExecutor.Position()
|
||||
|
||||
store, _ := session.MarketDataStore(position.Symbol)
|
||||
|
||||
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
||||
if kline.Symbol != position.Symbol || kline.Interval != types.Interval1m {
|
||||
return
|
||||
}
|
||||
|
||||
closePrice := kline.Close
|
||||
if position.IsClosed() || position.IsDust(closePrice) {
|
||||
return
|
||||
}
|
||||
|
||||
roi := position.ROI(closePrice)
|
||||
if roi.Sign() < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if klines, ok := store.KLinesOfInterval(s.Interval); ok {
|
||||
var cbv = fixedpoint.Zero
|
||||
var cqv = fixedpoint.Zero
|
||||
for i := 0; i < s.Window; i++ {
|
||||
last := (*klines)[len(*klines)-1-i]
|
||||
cqv = cqv.Add(last.QuoteVolume)
|
||||
cbv = cbv.Add(last.Volume)
|
||||
}
|
||||
|
||||
if cqv.Compare(s.MinQuoteVolume) > 0 {
|
||||
bbgo.Notify("%s TakeProfit triggered by cumulated volume (window: %d) %f > %f, price = %f",
|
||||
position.Symbol,
|
||||
s.Window,
|
||||
cqv.Float64(),
|
||||
s.MinQuoteVolume.Float64(), kline.Close.Float64())
|
||||
|
||||
_ = orderExecutor.ClosePosition(context.Background(), fixedpoint.One)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
28
pkg/strategy/pivotshort/exit.go
Normal file
28
pkg/strategy/pivotshort/exit.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package pivotshort
|
||||
|
||||
import "github.com/c9s/bbgo/pkg/bbgo"
|
||||
|
||||
type ExitMethod struct {
|
||||
RoiStopLoss *RoiStopLoss `json:"roiStopLoss"`
|
||||
ProtectionStopLoss *ProtectionStopLoss `json:"protectionStopLoss"`
|
||||
|
||||
RoiTakeProfit *RoiTakeProfit `json:"roiTakeProfit"`
|
||||
LowerShadowTakeProfit *LowerShadowTakeProfit `json:"lowerShadowTakeProfit"`
|
||||
|
||||
CumulatedVolumeTakeProfit *CumulatedVolumeTakeProfit `json:"cumulatedVolumeTakeProfit"`
|
||||
// MarginSideEffect types.MarginOrderSideEffectType `json:"marginOrderSideEffect"`
|
||||
}
|
||||
|
||||
func (m *ExitMethod) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
|
||||
if m.ProtectionStopLoss != nil {
|
||||
m.ProtectionStopLoss.Bind(session, orderExecutor)
|
||||
} else if m.RoiStopLoss != nil {
|
||||
m.RoiStopLoss.Bind(session, orderExecutor)
|
||||
} else if m.RoiTakeProfit != nil {
|
||||
m.RoiTakeProfit.Bind(session, orderExecutor)
|
||||
} else if m.LowerShadowTakeProfit != nil {
|
||||
m.LowerShadowTakeProfit.Bind(session, orderExecutor)
|
||||
} else if m.CumulatedVolumeTakeProfit != nil {
|
||||
m.CumulatedVolumeTakeProfit.Bind(session, orderExecutor)
|
||||
}
|
||||
}
|
53
pkg/strategy/pivotshort/lower_shadow_take_profit.go
Normal file
53
pkg/strategy/pivotshort/lower_shadow_take_profit.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package pivotshort
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
type LowerShadowTakeProfit struct {
|
||||
Ratio fixedpoint.Value `json:"ratio"`
|
||||
|
||||
session *bbgo.ExchangeSession
|
||||
orderExecutor *bbgo.GeneralOrderExecutor
|
||||
}
|
||||
|
||||
func (s *LowerShadowTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
|
||||
s.session = session
|
||||
s.orderExecutor = orderExecutor
|
||||
|
||||
position := orderExecutor.Position()
|
||||
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
||||
if kline.Symbol != position.Symbol || kline.Interval != types.Interval1m {
|
||||
return
|
||||
}
|
||||
|
||||
closePrice := kline.Close
|
||||
if position.IsClosed() || position.IsDust(closePrice) {
|
||||
return
|
||||
}
|
||||
|
||||
roi := position.ROI(closePrice)
|
||||
if roi.Sign() < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if s.Ratio.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
if kline.GetLowerShadowHeight().Div(kline.Close).Compare(s.Ratio) > 0 {
|
||||
bbgo.Notify("%s TakeProfit triggered by shadow ratio %f, price = %f",
|
||||
position.Symbol,
|
||||
kline.GetLowerShadowRatio().Float64(),
|
||||
kline.Close.Float64(),
|
||||
kline)
|
||||
|
||||
_ = orderExecutor.ClosePosition(context.Background(), fixedpoint.One)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
|
@ -74,20 +74,6 @@ type CumulatedVolume struct {
|
|||
Window int `json:"window"`
|
||||
}
|
||||
|
||||
type Exit struct {
|
||||
RoiMinTakeProfitPercentage fixedpoint.Value `json:"roiMinTakeProfitPercentage"`
|
||||
|
||||
RoiTakeProfit *RoiTakeProfit `json:"roiTakeProfit"`
|
||||
RoiStopLoss *RoiStopLoss `json:"roiStopLoss"`
|
||||
ProtectionStopLoss *ProtectionStopLoss `json:"protectionStopLoss"`
|
||||
|
||||
LowerShadowRatio fixedpoint.Value `json:"lowerShadowRatio"`
|
||||
|
||||
CumulatedVolume *CumulatedVolume `json:"cumulatedVolume"`
|
||||
|
||||
MarginSideEffect types.MarginOrderSideEffectType `json:"marginOrderSideEffect"`
|
||||
}
|
||||
|
||||
type Strategy struct {
|
||||
*bbgo.Graceful
|
||||
|
||||
|
@ -107,8 +93,8 @@ type Strategy struct {
|
|||
|
||||
BounceShort *BounceShort `json:"bounceShort"`
|
||||
|
||||
Entry Entry `json:"entry"`
|
||||
Exit Exit `json:"exit"`
|
||||
Entry Entry `json:"entry"`
|
||||
ExitMethods []ExitMethod `json:"exits"`
|
||||
|
||||
session *bbgo.ExchangeSession
|
||||
orderExecutor *bbgo.GeneralOrderExecutor
|
||||
|
@ -278,16 +264,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
}
|
||||
})
|
||||
|
||||
if s.Exit.ProtectionStopLoss != nil {
|
||||
s.Exit.ProtectionStopLoss.Bind(session, s.orderExecutor)
|
||||
}
|
||||
|
||||
if s.Exit.RoiStopLoss != nil {
|
||||
s.Exit.RoiStopLoss.Bind(session, s.orderExecutor)
|
||||
}
|
||||
|
||||
if s.Exit.RoiTakeProfit != nil {
|
||||
s.Exit.RoiTakeProfit.Bind(session, s.orderExecutor)
|
||||
for _, method := range s.ExitMethods {
|
||||
method.Bind(session, s.orderExecutor)
|
||||
}
|
||||
|
||||
// Always check whether you can open a short position or not
|
||||
|
@ -301,42 +279,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
}
|
||||
|
||||
isPositionOpened := !s.Position.IsClosed() && !s.Position.IsDust(kline.Close)
|
||||
|
||||
if isPositionOpened && s.Position.IsShort() {
|
||||
roi := s.Position.ROI(kline.Close)
|
||||
if !s.Exit.RoiMinTakeProfitPercentage.IsZero() {
|
||||
if roi.Compare(s.Exit.RoiMinTakeProfitPercentage) > 0 {
|
||||
if !s.Exit.LowerShadowRatio.IsZero() && kline.GetLowerShadowHeight().Div(kline.Close).Compare(s.Exit.LowerShadowRatio) > 0 {
|
||||
bbgo.Notify("%s TakeProfit triggered at price %f: by shadow ratio %f",
|
||||
s.Symbol,
|
||||
kline.Close.Float64(),
|
||||
kline.GetLowerShadowRatio().Float64(), kline)
|
||||
_ = s.ClosePosition(ctx, fixedpoint.One)
|
||||
return
|
||||
} else if s.Exit.CumulatedVolume != nil && s.Exit.CumulatedVolume.Enabled {
|
||||
if klines, ok := store.KLinesOfInterval(s.Interval); ok {
|
||||
var cbv = fixedpoint.Zero
|
||||
var cqv = fixedpoint.Zero
|
||||
for i := 0; i < s.Exit.CumulatedVolume.Window; i++ {
|
||||
last := (*klines)[len(*klines)-1-i]
|
||||
cqv = cqv.Add(last.QuoteVolume)
|
||||
cbv = cbv.Add(last.Volume)
|
||||
}
|
||||
|
||||
if cqv.Compare(s.Exit.CumulatedVolume.MinQuoteVolume) > 0 {
|
||||
bbgo.Notify("%s TakeProfit triggered at price %f: by cumulated volume (window: %d) %f > %f",
|
||||
s.Symbol,
|
||||
kline.Close.Float64(),
|
||||
s.Exit.CumulatedVolume.Window,
|
||||
cqv.Float64(),
|
||||
s.Exit.CumulatedVolume.MinQuoteVolume.Float64())
|
||||
_ = s.ClosePosition(ctx, fixedpoint.One)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if len(s.pivotLowPrices) == 0 {
|
||||
|
|
Loading…
Reference in New Issue
Block a user