mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
Merge pull request #848 from c9s/strategy/pivotshort
strategy/pivotshort: refactor trendEMA and add maxGradient config
This commit is contained in:
commit
05f6581bcd
|
@ -136,6 +136,7 @@ func (e *GeneralOrderExecutor) ClosePosition(ctx context.Context, percentage fix
|
|||
return nil
|
||||
}
|
||||
|
||||
log.Infof("closing %s position with tags: %v", e.symbol, tags)
|
||||
submitOrder.Tag = strings.Join(tags, ",")
|
||||
_, err := e.SubmitOrders(ctx, *submitOrder)
|
||||
return err
|
||||
|
|
|
@ -15,32 +15,6 @@ type StopEMA struct {
|
|||
Range fixedpoint.Value `json:"range"`
|
||||
}
|
||||
|
||||
type TrendEMA struct {
|
||||
types.IntervalWindow
|
||||
|
||||
trendEWMA *indicator.EWMA
|
||||
|
||||
trendEWMALast, trendEWMACurrent float64
|
||||
}
|
||||
|
||||
func (s *TrendEMA) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
|
||||
symbol := orderExecutor.Position().Symbol
|
||||
s.trendEWMA = session.StandardIndicatorSet(symbol).EWMA(s.IntervalWindow)
|
||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) {
|
||||
s.trendEWMALast = s.trendEWMACurrent
|
||||
s.trendEWMACurrent = s.trendEWMA.Last()
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *TrendEMA) Gradient() (float64, bool) {
|
||||
if s.trendEWMALast > 0.0 && s.trendEWMACurrent > 0.0 {
|
||||
gradient := s.trendEWMALast / s.trendEWMACurrent
|
||||
return gradient, true
|
||||
}
|
||||
|
||||
return 0.0, false
|
||||
}
|
||||
|
||||
type FakeBreakStop struct {
|
||||
types.IntervalWindow
|
||||
}
|
||||
|
@ -120,6 +94,9 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
|||
}
|
||||
|
||||
if s.TrendEMA != nil {
|
||||
if s.TrendEMA.MaxGradient == 0.0 {
|
||||
s.TrendEMA.MaxGradient = 1.0
|
||||
}
|
||||
s.TrendEMA.Bind(session, orderExecutor)
|
||||
}
|
||||
|
||||
|
@ -160,7 +137,7 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
|||
// the kline opened below the last break low, and closed above the last break low
|
||||
if k.Open.Compare(s.lastBreakLow) < 0 && k.Close.Compare(s.lastBreakLow) > 0 {
|
||||
bbgo.Notify("kLine closed above the last break low, triggering stop earlier")
|
||||
if err := s.orderExecutor.ClosePosition(context.Background(), one, "kLineClosedStop"); err != nil {
|
||||
if err := s.orderExecutor.ClosePosition(context.Background(), one, "fakeBreakStop"); err != nil {
|
||||
log.WithError(err).Error("position close error")
|
||||
}
|
||||
|
||||
|
@ -213,15 +190,10 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
|||
}
|
||||
|
||||
// trend EMA protection
|
||||
if gradient, ok := s.TrendEMA.Gradient(); ok {
|
||||
if gradient > 1.0 {
|
||||
log.Debugf("trendEMA %+v current=%f last=%f slope=%f: skip short", s.TrendEMA, s.TrendEMA.trendEWMACurrent, s.TrendEMA.trendEWMALast, gradient)
|
||||
if !s.TrendEMA.GradientAllowed() {
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("trendEMA %+v current=%f last=%f slope=%f: short is enabled", s.TrendEMA, s.TrendEMA.trendEWMACurrent, s.TrendEMA.trendEWMALast, gradient)
|
||||
}
|
||||
|
||||
// stop EMA protection
|
||||
if s.stopEWMA != nil {
|
||||
ema := fixedpoint.NewFromFloat(s.stopEWMA.Last())
|
||||
|
|
|
@ -58,6 +58,9 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
|
|||
s.activeOrders.BindStream(session.UserDataStream)
|
||||
|
||||
if s.TrendEMA != nil {
|
||||
if s.TrendEMA.MaxGradient == 0.0 {
|
||||
s.TrendEMA.MaxGradient = 1.0
|
||||
}
|
||||
s.TrendEMA.Bind(session, orderExecutor)
|
||||
}
|
||||
|
||||
|
@ -68,15 +71,10 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
|
|||
|
||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.Interval, func(kline types.KLine) {
|
||||
// trend EMA protection
|
||||
if gradient, ok := s.TrendEMA.Gradient(); ok {
|
||||
if gradient > 1.0 {
|
||||
log.Debugf("trendEMA %+v current=%f last=%f gradient=%f: skip short", s.TrendEMA, s.TrendEMA.trendEWMACurrent, s.TrendEMA.trendEWMALast, gradient)
|
||||
if !s.TrendEMA.GradientAllowed() {
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("trendEMA %+v current=%f last=%f gradient=%f: short is enabled", s.TrendEMA, s.TrendEMA.trendEWMACurrent, s.TrendEMA.trendEWMALast, gradient)
|
||||
}
|
||||
|
||||
position := s.orderExecutor.Position()
|
||||
if position.IsOpened(kline.Close) {
|
||||
return
|
||||
|
|
51
pkg/strategy/pivotshort/trendema.go
Normal file
51
pkg/strategy/pivotshort/trendema.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package pivotshort
|
||||
|
||||
import (
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/indicator"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
type TrendEMA struct {
|
||||
types.IntervalWindow
|
||||
|
||||
// MaxGradient is the maximum gradient allowed for the entry.
|
||||
MaxGradient float64 `json:"maxGradient"`
|
||||
MinGradient float64 `json:"minGradient"`
|
||||
|
||||
trendEWMA *indicator.EWMA
|
||||
|
||||
trendEWMALast, trendEWMACurrent, trendGradient float64
|
||||
}
|
||||
|
||||
func (s *TrendEMA) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
|
||||
symbol := orderExecutor.Position().Symbol
|
||||
s.trendEWMA = session.StandardIndicatorSet(symbol).EWMA(s.IntervalWindow)
|
||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) {
|
||||
s.trendEWMALast = s.trendEWMACurrent
|
||||
s.trendEWMACurrent = s.trendEWMA.Last()
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *TrendEMA) GradientAllowed() bool {
|
||||
if s.trendEWMALast > 0.0 && s.trendEWMACurrent > 0.0 {
|
||||
s.trendGradient = s.trendEWMALast / s.trendEWMACurrent
|
||||
}
|
||||
|
||||
if s.trendGradient == .0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if s.MaxGradient > 0.0 && s.trendGradient < s.MaxGradient {
|
||||
log.Debugf("trendEMA %+v current=%f last=%f gradient=%f: allowed", s, s.trendEWMACurrent, s.trendEWMALast, s.trendGradient)
|
||||
return true
|
||||
}
|
||||
|
||||
if s.MinGradient > 0.0 && s.trendGradient > s.MinGradient {
|
||||
log.Debugf("trendEMA %+v current=%f last=%f gradient=%f: allowed", s, s.trendEWMACurrent, s.trendEWMALast, s.trendGradient)
|
||||
return true
|
||||
}
|
||||
|
||||
log.Debugf("trendEMA %+v current=%f last=%f gradient=%f: disallowed", s, s.trendEWMACurrent, s.trendEWMALast, s.trendGradient)
|
||||
return false
|
||||
}
|
|
@ -207,9 +207,13 @@ func (s *TradeStats) add(pnl fixedpoint.Value) {
|
|||
}
|
||||
|
||||
s.ProfitFactor = s.GrossProfit.Div(s.GrossLoss.Abs())
|
||||
if len(s.Profits) > 0 {
|
||||
s.AverageProfitTrade = fixedpoint.Avg(s.Profits)
|
||||
}
|
||||
if len(s.Losses) > 0 {
|
||||
s.AverageLossTrade = fixedpoint.Avg(s.Losses)
|
||||
}
|
||||
}
|
||||
|
||||
// Output TradeStats without Profits and Losses
|
||||
func (s *TradeStats) BriefString() string {
|
||||
|
|
Loading…
Reference in New Issue
Block a user