implement SupportTakeProfit method

This commit is contained in:
c9s 2022-07-02 13:21:27 +08:00
parent ac1b5e4df4
commit f940bb8e0a
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
3 changed files with 109 additions and 9 deletions

View File

@ -38,6 +38,10 @@ type BreakLow struct {
session *bbgo.ExchangeSession
}
func (s *BreakLow) Subscribe(session *bbgo.ExchangeSession) {
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.Interval})
}
func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
s.session = session
s.orderExecutor = orderExecutor

View File

@ -150,26 +150,51 @@ func (s *ResistanceShort) placeResistanceOrders(ctx context.Context, resistanceP
s.activeOrders.Add(createdOrders...)
}
func findPossibleSupportPrices(closePrice float64, minDistance float64, lows []float64) []float64 {
// sort float64 in increasing order
// lower to higher prices
sort.Float64s(lows)
var supportPrices []float64
var last = closePrice
for i := len(lows) - 1; i >= 0; i-- {
price := lows[i]
// filter prices that are lower than the current closed price
if price > closePrice {
continue
}
if (price / last) < (1.0 - minDistance) {
continue
}
supportPrices = append(supportPrices, price)
last = price
}
return supportPrices
}
func findPossibleResistancePrices(closePrice float64, minDistance float64, lows []float64) []float64 {
// sort float64 in increasing order
// lower to higher prices
sort.Float64s(lows)
var resistancePrices []float64
for _, low := range lows {
if low < closePrice {
var last = closePrice
for _, price := range lows {
// filter prices that are lower than the current closed price
if price < closePrice {
continue
}
last := closePrice
if len(resistancePrices) > 0 {
last = resistancePrices[len(resistancePrices)-1]
}
if (low / last) < (1.0 + minDistance) {
if (price / last) < (1.0 + minDistance) {
continue
}
resistancePrices = append(resistancePrices, low)
resistancePrices = append(resistancePrices, price)
last = price
}
return resistancePrices

View File

@ -30,6 +30,69 @@ type IntervalWindowSetting struct {
types.IntervalWindow
}
type SupportTakeProfit struct {
Symbol string
types.IntervalWindow
Ratio fixedpoint.Value `json:"ratio"`
pivot *indicator.Pivot
orderExecutor *bbgo.GeneralOrderExecutor
session *bbgo.ExchangeSession
activeOrders *bbgo.ActiveOrderBook
}
func (s *SupportTakeProfit) Subscribe(session *bbgo.ExchangeSession) {
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.Interval})
}
func (s *SupportTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
s.session = session
s.orderExecutor = orderExecutor
s.activeOrders = bbgo.NewActiveOrderBook(s.Symbol)
position := orderExecutor.Position()
symbol := position.Symbol
store, _ := session.MarketDataStore(symbol)
s.pivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow}
s.pivot.Bind(store)
preloadPivot(s.pivot, store)
session.UserDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.Interval, func(kline types.KLine) {
supportPrices := findPossibleSupportPrices(kline.Close.Float64(), 0.1, s.pivot.Lows)
// supportPrices are sorted in decreasing order
if len(supportPrices) == 0 {
log.Infof("support prices not found")
return
}
if !position.IsOpened(kline.Close) {
return
}
nextSupport := fixedpoint.NewFromFloat(supportPrices[0])
buyPrice := nextSupport.Mul(one.Add(s.Ratio))
quantity := position.GetQuantity()
ctx := context.Background()
if err := orderExecutor.GracefulCancelActiveOrderBook(ctx, s.activeOrders); err != nil {
log.WithError(err).Errorf("cancel order failed")
}
createdOrders, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
Symbol: symbol,
Type: types.OrderTypeLimitMaker,
Price: buyPrice,
Quantity: quantity,
})
if err != nil {
log.WithError(err).Errorf("can not submit orders: %+v", createdOrders)
}
s.activeOrders.Add(createdOrders...)
}))
}
type Strategy struct {
Environment *bbgo.Environment
Symbol string `json:"symbol"`
@ -49,6 +112,8 @@ type Strategy struct {
// ResistanceShort is one of the entry method
ResistanceShort *ResistanceShort `json:"resistanceShort"`
SupportTakeProfit *SupportTakeProfit `json:"supportTakeProfit"`
ExitMethods bbgo.ExitMethodSet `json:"exits"`
session *bbgo.ExchangeSession
@ -73,6 +138,12 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
if s.BreakLow != nil {
dynamic.InheritStructValues(s.BreakLow, s)
s.BreakLow.Subscribe(session)
}
if s.SupportTakeProfit != nil {
dynamic.InheritStructValues(s.SupportTakeProfit, s)
s.SupportTakeProfit.Subscribe(session)
}
if !bbgo.IsBackTesting {