fix: highest price and lowest price reset, condition gets crossed

This commit is contained in:
zenix 2022-08-09 13:26:02 +09:00
parent 2c4e03a102
commit 5be6e822e9

View File

@ -880,6 +880,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
bp := buyPrice bp := buyPrice
vol := Volume vol := Volume
sp := sellPrice sp := sellPrice
resetPrice := false
if tag == "close" { if tag == "close" {
if !buyPrice.IsZero() { if !buyPrice.IsZero() {
if trade.Side == types.SideTypeSell { if trade.Side == types.SideTypeSell {
@ -898,8 +899,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
if Volume.Sign() < 0 { if Volume.Sign() < 0 {
sellPrice = trade.Price sellPrice = trade.Price
buyPrice = fixedpoint.Zero buyPrice = fixedpoint.Zero
resetPrice = true
} else if Volume.Sign() == 0 { } else if Volume.Sign() == 0 {
buyPrice = fixedpoint.Zero buyPrice = fixedpoint.Zero
resetPrice = true
} }
} else { } else {
buyPrice = buyPrice.Mul(Volume).Add(trade.Price.Mul(trade.Quantity)).Div(Volume.Add(trade.Quantity)) buyPrice = buyPrice.Mul(Volume).Add(trade.Price.Mul(trade.Quantity)).Div(Volume.Add(trade.Quantity))
@ -923,8 +926,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
if Volume.Sign() > 0 { if Volume.Sign() > 0 {
buyPrice = trade.Price buyPrice = trade.Price
sellPrice = fixedpoint.Zero sellPrice = fixedpoint.Zero
resetPrice = true
} else if Volume.Sign() == 0 { } else if Volume.Sign() == 0 {
sellPrice = fixedpoint.Zero sellPrice = fixedpoint.Zero
resetPrice = true
} }
} else { } else {
sellPrice = sellPrice.Mul(Volume).Sub(trade.Price.Mul(trade.Quantity)).Div(Volume.Sub(trade.Quantity)) sellPrice = sellPrice.Mul(Volume).Sub(trade.Price.Mul(trade.Quantity)).Div(Volume.Sub(trade.Quantity))
@ -932,17 +937,27 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
} }
} else { } else {
// position changed by strategy // position changed by strategy
oldSign := Volume.Sign()
if trade.Side == types.SideTypeBuy { if trade.Side == types.SideTypeBuy {
Volume = Volume.Add(trade.Quantity) Volume = Volume.Add(trade.Quantity)
if Volume.Sign() > 0 { if Volume.Sign() > 0 {
buyPrice = trade.Price buyPrice = trade.Price
sellPrice = fixedpoint.Zero sellPrice = fixedpoint.Zero
if oldSign <= 0 {
resetPrice = true
}
} else if Volume.Sign() < 0 { } else if Volume.Sign() < 0 {
sellPrice = trade.Price sellPrice = trade.Price
buyPrice = fixedpoint.Zero buyPrice = fixedpoint.Zero
if oldSign >= 0 {
resetPrice = true
}
} else { } else {
buyPrice = fixedpoint.Zero buyPrice = fixedpoint.Zero
sellPrice = fixedpoint.Zero sellPrice = fixedpoint.Zero
if oldSign != 0 {
resetPrice = true
}
} }
} else if trade.Side == types.SideTypeSell { } else if trade.Side == types.SideTypeSell {
sellPrice = trade.Price sellPrice = trade.Price
@ -950,12 +965,21 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
if Volume.Sign() > 0 { if Volume.Sign() > 0 {
buyPrice = trade.Price buyPrice = trade.Price
sellPrice = fixedpoint.Zero sellPrice = fixedpoint.Zero
if oldSign <= 0 {
resetPrice = true
}
} else if Volume.Sign() < 0 { } else if Volume.Sign() < 0 {
sellPrice = trade.Price sellPrice = trade.Price
buyPrice = fixedpoint.Zero buyPrice = fixedpoint.Zero
if oldSign >= 0 {
resetPrice = true
}
} else { } else {
buyPrice = fixedpoint.Zero buyPrice = fixedpoint.Zero
sellPrice = fixedpoint.Zero sellPrice = fixedpoint.Zero
if oldSign != 0 {
resetPrice = true
}
} }
} }
} }
@ -974,6 +998,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
sellPrice = trade.Price sellPrice = trade.Price
} }
Volume = Volume.Sub(trade.Quantity) Volume = Volume.Sub(trade.Quantity)
resetPrice = true
} else if tag == "long" { } else if tag == "long" {
if sellPrice.IsZero() { if sellPrice.IsZero() {
if !buyPrice.IsZero() { if !buyPrice.IsZero() {
@ -989,12 +1014,14 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
Volume = fixedpoint.Zero Volume = fixedpoint.Zero
} }
Volume = Volume.Add(trade.Quantity) Volume = Volume.Add(trade.Quantity)
resetPrice = true
} else if tag == "rebalance" { } else if tag == "rebalance" {
if sellPrice.IsZero() { if sellPrice.IsZero() {
profit.Update(modify(sellPrice.Div(trade.Price)).Float64()) profit.Update(modify(sellPrice.Div(trade.Price)).Float64())
} else { } else {
profit.Update(modify(trade.Price.Div(buyPrice)).Float64()) profit.Update(modify(trade.Price.Div(buyPrice)).Float64())
} }
resetPrice = true
cumProfit.Update(cumProfit.Last() * profit.Last()) cumProfit.Update(cumProfit.Last() * profit.Last())
sellPrice = fixedpoint.Zero sellPrice = fixedpoint.Zero
buyPrice = fixedpoint.Zero buyPrice = fixedpoint.Zero
@ -1004,9 +1031,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.p.Reset() s.p.Reset()
} }
s.buyPrice = buyPrice.Float64() s.buyPrice = buyPrice.Float64()
s.highestPrice = s.buyPrice
s.sellPrice = sellPrice.Float64() s.sellPrice = sellPrice.Float64()
if resetPrice {
s.highestPrice = s.buyPrice
s.lowestPrice = s.sellPrice s.lowestPrice = s.sellPrice
}
bbgo.Notify("tag %s %v %s volafter: %v, quantity: %v, bp: %v, sp: %v, volbefore: %v, bpafter: %v, spafter: %v", tag, trade.Price, trade.Side, Volume, trade.Quantity, bp, sp, vol, s.buyPrice, s.sellPrice) bbgo.Notify("tag %s %v %s volafter: %v, quantity: %v, bp: %v, sp: %v, volbefore: %v, bpafter: %v, spafter: %v", tag, trade.Price, trade.Side, Volume, trade.Quantity, bp, sp, vol, s.buyPrice, s.sellPrice)
}) })
@ -1110,10 +1139,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
avg := s.buyPrice + s.sellPrice avg := s.buyPrice + s.sellPrice
exitShortCondition := ( /*avg*(1.+stoploss) <= pricef || (drift > 0 || ddrift > DDriftFilterPos) ||*/ avg-atr*takeProfitFactor >= pricef || exitShortCondition := ( /*avg*(1.+stoploss) <= pricef || (drift > 0 || ddrift > DDriftFilterPos) ||*/ avg-atr*takeProfitFactor >= pricef ||
s.trailingCheck(highf, "short")) && s.trailingCheck(highf, "short")) &&
(s.Position.IsShort() && !s.Position.IsDust(price)) (s.p.IsShort() && !s.p.IsDust(price))
exitLongCondition := ( /*avg*(1.-stoploss) >= pricef || (drift < 0 || ddrift < DDriftFilterNeg) ||*/ avg+atr*takeProfitFactor <= pricef || exitLongCondition := ( /*avg*(1.-stoploss) >= pricef || (drift < 0 || ddrift < DDriftFilterNeg) ||*/ avg+atr*takeProfitFactor <= pricef ||
s.trailingCheck(lowf, "long")) && s.trailingCheck(lowf, "long")) &&
(s.Position.IsLong() && !s.Position.IsDust(price)) (s.p.IsLong() && !s.p.IsDust(price))
if exitShortCondition || exitLongCondition { if exitShortCondition || exitLongCondition {
if exitLongCondition && s.highestPrice > avg { if exitLongCondition && s.highestPrice > avg {
s.takeProfitFactor.Update((s.highestPrice - avg) / atr * 1.5) s.takeProfitFactor.Update((s.highestPrice - avg) / atr * 1.5)
@ -1153,7 +1182,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
highdiff := highf - s.ma.Last() highdiff := highf - s.ma.Last()
s.stdevHigh.Update(highdiff) s.stdevHigh.Update(highdiff)
//log.Errorf("highdiff: %3.2f ma: %.2f, close: %8v, high: %8v, low: %8v, time: %v", s.stdevHigh.Last(), s.ma.Last(), kline.Close, kline.High, kline.Low, kline.StartTime) log.Errorf("highdiff: %3.2f ma: %.2f, close: %8v, high: %8v, low: %8v, time: %v", s.stdevHigh.Last(), s.ma.Last(), kline.Close, kline.High, kline.Low, kline.StartTime)
if s.lowestPrice > 0 && lowf < s.lowestPrice { if s.lowestPrice > 0 && lowf < s.lowestPrice {
s.lowestPrice = lowf s.lowestPrice = lowf
} }
@ -1180,16 +1209,23 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
shortCondition := (drift[1] >= DriftFilterNeg || ddrift[1] >= 0) && (driftPred <= DDriftFilterNeg || ddriftPred <= 0) || drift[1] < 0 && drift[0] < 0 shortCondition := (drift[1] >= DriftFilterNeg || ddrift[1] >= 0) && (driftPred <= DDriftFilterNeg || ddriftPred <= 0) || drift[1] < 0 && drift[0] < 0
longCondition := (drift[1] <= DriftFilterPos || ddrift[1] <= 0) && (driftPred >= DDriftFilterPos || ddriftPred >= 0) || drift[1] > 0 && drift[0] > 0 longCondition := (drift[1] <= DriftFilterPos || ddrift[1] <= 0) && (driftPred >= DDriftFilterPos || ddriftPred >= 0) || drift[1] > 0 && drift[0] > 0
exitShortCondition := ((drift[0] >= DDriftFilterPos || ddrift[0] >= 0) || exitShortCondition := ((drift[0] >= DDriftFilterPos && ddrift[0] >= 0) ||
avg*(1.+stoploss) <= pricef || avg*(1.+stoploss) <= pricef ||
avg-atr*takeProfitFactor >= pricef) && avg-atr*takeProfitFactor >= pricef) &&
s.Position.IsShort() s.p.IsShort()
exitLongCondition := ((drift[0] <= DDriftFilterNeg || ddrift[0] <= 0) || exitLongCondition := ((drift[0] <= DDriftFilterNeg && ddrift[0] <= 0) ||
avg*(1.-stoploss) >= pricef || avg*(1.-stoploss) >= pricef ||
avg+atr*takeProfitFactor <= pricef) && avg+atr*takeProfitFactor <= pricef) &&
s.Position.IsLong() s.p.IsLong()
if shortCondition && longCondition {
if drift[1] > drift[0] {
longCondition = false
} else {
shortCondition = false
}
}
if (exitShortCondition || exitLongCondition) && s.Position.IsOpened(price) && !shortCondition && !longCondition { if (exitShortCondition || exitLongCondition) && s.p.IsOpened(price) && !shortCondition && !longCondition {
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil { if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
log.WithError(err).Errorf("cannot cancel orders") log.WithError(err).Errorf("cannot cancel orders")
return return
@ -1205,6 +1241,46 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
_ = s.ClosePosition(ctx, fixedpoint.One) _ = s.ClosePosition(ctx, fixedpoint.One)
return return
} }
if longCondition {
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
log.WithError(err).Errorf("cannot cancel orders")
return
}
source = source.Sub(fixedpoint.NewFromFloat(s.stdevLow.Last() * s.HighLowVarianceMultiplier))
if source.Compare(price) > 0 {
source = price
}
sourcef = source.Float64()
quoteBalance, ok := s.Session.GetAccount().Balance(s.Market.QuoteCurrency)
if !ok {
log.Errorf("unable to get quoteCurrency")
return
}
if s.Market.IsDustQuantity(
quoteBalance.Available.Div(source), source) {
return
}
if avg > s.lowestPrice && s.Position.IsShort() {
s.takeProfitFactor.Update((avg - s.lowestPrice) / atr * 1.5)
}
quantity := quoteBalance.Available.Div(source)
createdOrders, err := s.GeneralOrderExecutor.SubmitOrders(ctx, types.SubmitOrder{
Symbol: s.Symbol,
Side: types.SideTypeBuy,
Type: types.OrderTypeLimit,
Price: source,
Quantity: quantity,
Tag: "long",
})
if err != nil {
log.WithError(err).Errorf("cannot place buy order")
return
}
orderTagHistory[createdOrders[0].OrderID] = "long"
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
return
}
if shortCondition { if shortCondition {
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil { if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
log.WithError(err).Errorf("cannot cancel orders") log.WithError(err).Errorf("cannot cancel orders")
@ -1243,46 +1319,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
} }
orderTagHistory[createdOrders[0].OrderID] = "short" orderTagHistory[createdOrders[0].OrderID] = "short"
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
}
if longCondition {
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
log.WithError(err).Errorf("cannot cancel orders")
return return
} }
source = source.Sub(fixedpoint.NewFromFloat(s.stdevLow.Last() * s.HighLowVarianceMultiplier))
if source.Compare(price) > 0 {
source = price
}
sourcef = source.Float64()
quoteBalance, ok := s.Session.GetAccount().Balance(s.Market.QuoteCurrency)
if !ok {
log.Errorf("unable to get quoteCurrency")
return
}
if s.Market.IsDustQuantity(
quoteBalance.Available.Div(source), source) {
return
}
if avg > s.lowestPrice && s.Position.IsShort() {
s.takeProfitFactor.Update((avg - s.lowestPrice) / atr * 1.5)
}
quantity := quoteBalance.Available.Div(source)
createdOrders, err := s.GeneralOrderExecutor.SubmitOrders(ctx, types.SubmitOrder{
Symbol: s.Symbol,
Side: types.SideTypeBuy,
Type: types.OrderTypeLimit,
Price: source,
Quantity: quantity,
Tag: "long",
})
if err != nil {
log.WithError(err).Errorf("cannot place buy order")
return
}
orderTagHistory[createdOrders[0].OrderID] = "long"
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
}
}) })
bbgo.OnShutdown(func(ctx context.Context, wg *sync.WaitGroup) { bbgo.OnShutdown(func(ctx context.Context, wg *sync.WaitGroup) {