mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
Merge pull request #947 from c9s/fix/acc-vol-stop
improve: accumulated volume stop method
This commit is contained in:
commit
54782e763b
|
@ -38,6 +38,7 @@ func (s *CumulatedVolumeTakeProfit) Bind(session *ExchangeSession, orderExecutor
|
||||||
|
|
||||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.Interval, func(kline types.KLine) {
|
session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.Interval, func(kline types.KLine) {
|
||||||
closePrice := kline.Close
|
closePrice := kline.Close
|
||||||
|
openPrice := kline.Open
|
||||||
if position.IsClosed() || position.IsDust(closePrice) {
|
if position.IsClosed() || position.IsDust(closePrice) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -65,17 +66,31 @@ func (s *CumulatedVolumeTakeProfit) Bind(session *ExchangeSession, orderExecutor
|
||||||
cbv = cbv.Add(last.Volume)
|
cbv = cbv.Add(last.Volume)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cqv.Compare(s.MinQuoteVolume) > 0 {
|
if cqv.Compare(s.MinQuoteVolume) < 0 {
|
||||||
Notify("[CumulatedVolumeTakeProfit] %s TakeProfit triggered by cumulated volume (window: %d) %f > %f, price = %f",
|
|
||||||
position.Symbol,
|
|
||||||
s.Window,
|
|
||||||
cqv.Float64(),
|
|
||||||
s.MinQuoteVolume.Float64(), kline.Close.Float64())
|
|
||||||
|
|
||||||
if err := orderExecutor.ClosePosition(context.Background(), fixedpoint.One, "cumulatedVolumeTakeProfit"); err != nil {
|
|
||||||
log.WithError(err).Errorf("close position error")
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the closed price is below the open price, it means the sell taker is still strong.
|
||||||
|
if closePrice.Compare(openPrice) < 0 {
|
||||||
|
log.Infof("[CumulatedVolumeTakeProfit] closePrice %f is below openPrice %f, skip taking profit", closePrice.Float64(), openPrice.Float64())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
upperShadow := kline.GetUpperShadowHeight()
|
||||||
|
lowerShadow := kline.GetLowerShadowHeight()
|
||||||
|
if upperShadow.Compare(lowerShadow) > 0 {
|
||||||
|
log.Infof("[CumulatedVolumeTakeProfit] upper shadow is longer than the lower shadow, skip taking profit")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Notify("[CumulatedVolumeTakeProfit] %s TakeProfit triggered by cumulated volume (window: %d) %f > %f, price = %f",
|
||||||
|
position.Symbol,
|
||||||
|
s.Window,
|
||||||
|
cqv.Float64(),
|
||||||
|
s.MinQuoteVolume.Float64(), kline.Close.Float64())
|
||||||
|
|
||||||
|
if err := orderExecutor.ClosePosition(context.Background(), fixedpoint.One, "cumulatedVolumeTakeProfit"); err != nil {
|
||||||
|
log.WithError(err).Errorf("close position error")
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,37 +105,37 @@ func (k *KLine) Merge(o *KLine) {
|
||||||
k.Closed = o.Closed
|
k.Closed = o.Closed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetStartTime() Time {
|
func (k *KLine) GetStartTime() Time {
|
||||||
return k.StartTime
|
return k.StartTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetEndTime() Time {
|
func (k *KLine) GetEndTime() Time {
|
||||||
return k.EndTime
|
return k.EndTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetInterval() Interval {
|
func (k *KLine) GetInterval() Interval {
|
||||||
return k.Interval
|
return k.Interval
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) Mid() fixedpoint.Value {
|
func (k *KLine) Mid() fixedpoint.Value {
|
||||||
return k.High.Add(k.Low).Div(Two)
|
return k.High.Add(k.Low).Div(Two)
|
||||||
}
|
}
|
||||||
|
|
||||||
// green candle with open and close near high price
|
// green candle with open and close near high price
|
||||||
func (k KLine) BounceUp() bool {
|
func (k *KLine) BounceUp() bool {
|
||||||
mid := k.Mid()
|
mid := k.Mid()
|
||||||
trend := k.Direction()
|
trend := k.Direction()
|
||||||
return trend > 0 && k.Open.Compare(mid) > 0 && k.Close.Compare(mid) > 0
|
return trend > 0 && k.Open.Compare(mid) > 0 && k.Close.Compare(mid) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// red candle with open and close near low price
|
// red candle with open and close near low price
|
||||||
func (k KLine) BounceDown() bool {
|
func (k *KLine) BounceDown() bool {
|
||||||
mid := k.Mid()
|
mid := k.Mid()
|
||||||
trend := k.Direction()
|
trend := k.Direction()
|
||||||
return trend > 0 && k.Open.Compare(mid) < 0 && k.Close.Compare(mid) < 0
|
return trend > 0 && k.Open.Compare(mid) < 0 && k.Close.Compare(mid) < 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) Direction() Direction {
|
func (k *KLine) Direction() Direction {
|
||||||
o := k.GetOpen()
|
o := k.GetOpen()
|
||||||
c := k.GetClose()
|
c := k.GetClose()
|
||||||
|
|
||||||
|
@ -147,32 +147,32 @@ func (k KLine) Direction() Direction {
|
||||||
return DirectionNone
|
return DirectionNone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetHigh() fixedpoint.Value {
|
func (k *KLine) GetHigh() fixedpoint.Value {
|
||||||
return k.High
|
return k.High
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetLow() fixedpoint.Value {
|
func (k *KLine) GetLow() fixedpoint.Value {
|
||||||
return k.Low
|
return k.Low
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetOpen() fixedpoint.Value {
|
func (k *KLine) GetOpen() fixedpoint.Value {
|
||||||
return k.Open
|
return k.Open
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetClose() fixedpoint.Value {
|
func (k *KLine) GetClose() fixedpoint.Value {
|
||||||
return k.Close
|
return k.Close
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetMaxChange() fixedpoint.Value {
|
func (k *KLine) GetMaxChange() fixedpoint.Value {
|
||||||
return k.GetHigh().Sub(k.GetLow())
|
return k.GetHigh().Sub(k.GetLow())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetAmplification() fixedpoint.Value {
|
func (k *KLine) GetAmplification() fixedpoint.Value {
|
||||||
return k.GetMaxChange().Div(k.GetLow())
|
return k.GetMaxChange().Div(k.GetLow())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetThickness returns the thickness of the kline. 1 => thick, 0.1 => thin
|
// GetThickness returns the thickness of the kline. 1 => thick, 0.1 => thin
|
||||||
func (k KLine) GetThickness() fixedpoint.Value {
|
func (k *KLine) GetThickness() fixedpoint.Value {
|
||||||
out := k.GetChange().Div(k.GetMaxChange())
|
out := k.GetChange().Div(k.GetMaxChange())
|
||||||
if out.Sign() < 0 {
|
if out.Sign() < 0 {
|
||||||
return out.Neg()
|
return out.Neg()
|
||||||
|
@ -180,7 +180,7 @@ func (k KLine) GetThickness() fixedpoint.Value {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetUpperShadowRatio() fixedpoint.Value {
|
func (k *KLine) GetUpperShadowRatio() fixedpoint.Value {
|
||||||
out := k.GetUpperShadowHeight().Div(k.GetMaxChange())
|
out := k.GetUpperShadowHeight().Div(k.GetMaxChange())
|
||||||
if out.Sign() < 0 {
|
if out.Sign() < 0 {
|
||||||
return out.Neg()
|
return out.Neg()
|
||||||
|
@ -188,7 +188,7 @@ func (k KLine) GetUpperShadowRatio() fixedpoint.Value {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetUpperShadowHeight() fixedpoint.Value {
|
func (k *KLine) GetUpperShadowHeight() fixedpoint.Value {
|
||||||
high := k.GetHigh()
|
high := k.GetHigh()
|
||||||
open := k.GetOpen()
|
open := k.GetOpen()
|
||||||
clos := k.GetClose()
|
clos := k.GetClose()
|
||||||
|
@ -198,7 +198,7 @@ func (k KLine) GetUpperShadowHeight() fixedpoint.Value {
|
||||||
return high.Sub(clos)
|
return high.Sub(clos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetLowerShadowRatio() fixedpoint.Value {
|
func (k *KLine) GetLowerShadowRatio() fixedpoint.Value {
|
||||||
out := k.GetLowerShadowHeight().Div(k.GetMaxChange())
|
out := k.GetLowerShadowHeight().Div(k.GetMaxChange())
|
||||||
if out.Sign() < 0 {
|
if out.Sign() < 0 {
|
||||||
return out.Neg()
|
return out.Neg()
|
||||||
|
@ -206,7 +206,7 @@ func (k KLine) GetLowerShadowRatio() fixedpoint.Value {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) GetLowerShadowHeight() fixedpoint.Value {
|
func (k *KLine) GetLowerShadowHeight() fixedpoint.Value {
|
||||||
low := k.Low
|
low := k.Low
|
||||||
if k.Open.Compare(k.Close) < 0 { // uptrend
|
if k.Open.Compare(k.Close) < 0 { // uptrend
|
||||||
return k.Open.Sub(low)
|
return k.Open.Sub(low)
|
||||||
|
@ -217,16 +217,16 @@ func (k KLine) GetLowerShadowHeight() fixedpoint.Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBody returns the height of the candle real body
|
// GetBody returns the height of the candle real body
|
||||||
func (k KLine) GetBody() fixedpoint.Value {
|
func (k *KLine) GetBody() fixedpoint.Value {
|
||||||
return k.GetChange()
|
return k.GetChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChange returns Close price - Open price.
|
// GetChange returns Close price - Open price.
|
||||||
func (k KLine) GetChange() fixedpoint.Value {
|
func (k *KLine) GetChange() fixedpoint.Value {
|
||||||
return k.Close.Sub(k.Open)
|
return k.Close.Sub(k.Open)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) Color() string {
|
func (k *KLine) Color() string {
|
||||||
if k.Direction() > 0 {
|
if k.Direction() > 0 {
|
||||||
return style.GreenColor
|
return style.GreenColor
|
||||||
} else if k.Direction() < 0 {
|
} else if k.Direction() < 0 {
|
||||||
|
@ -235,18 +235,18 @@ func (k KLine) Color() string {
|
||||||
return style.GrayColor
|
return style.GrayColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) String() string {
|
func (k *KLine) String() string {
|
||||||
return fmt.Sprintf("%s %s %s %s O: %.4f H: %.4f L: %.4f C: %.4f CHG: %.4f MAXCHG: %.4f V: %.4f QV: %.2f TBBV: %.2f",
|
return fmt.Sprintf("%s %s %s %s O: %.4f H: %.4f L: %.4f C: %.4f CHG: %.4f MAXCHG: %.4f V: %.4f QV: %.2f TBBV: %.2f",
|
||||||
k.Exchange.String(),
|
k.Exchange.String(),
|
||||||
k.StartTime.Time().Format("2006-01-02 15:04"),
|
k.StartTime.Time().Format("2006-01-02 15:04"),
|
||||||
k.Symbol, k.Interval, k.Open.Float64(), k.High.Float64(), k.Low.Float64(), k.Close.Float64(), k.GetChange().Float64(), k.GetMaxChange().Float64(), k.Volume.Float64(), k.QuoteVolume.Float64(), k.TakerBuyBaseAssetVolume.Float64())
|
k.Symbol, k.Interval, k.Open.Float64(), k.High.Float64(), k.Low.Float64(), k.Close.Float64(), k.GetChange().Float64(), k.GetMaxChange().Float64(), k.Volume.Float64(), k.QuoteVolume.Float64(), k.TakerBuyBaseAssetVolume.Float64())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) PlainText() string {
|
func (k *KLine) PlainText() string {
|
||||||
return k.String()
|
return k.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLine) SlackAttachment() slack.Attachment {
|
func (k *KLine) SlackAttachment() slack.Attachment {
|
||||||
return slack.Attachment{
|
return slack.Attachment{
|
||||||
Text: fmt.Sprintf("*%s* KLine %s", k.Symbol, k.Interval),
|
Text: fmt.Sprintf("*%s* KLine %s", k.Symbol, k.Interval),
|
||||||
Color: k.Color(),
|
Color: k.Color(),
|
||||||
|
@ -312,7 +312,8 @@ func (k KLineWindow) GetInterval() Interval {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLineWindow) GetOpen() fixedpoint.Value {
|
func (k KLineWindow) GetOpen() fixedpoint.Value {
|
||||||
return k.First().GetOpen()
|
first := k.First()
|
||||||
|
return first.GetOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLineWindow) GetClose() fixedpoint.Value {
|
func (k KLineWindow) GetClose() fixedpoint.Value {
|
||||||
|
@ -321,7 +322,8 @@ func (k KLineWindow) GetClose() fixedpoint.Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLineWindow) GetHigh() fixedpoint.Value {
|
func (k KLineWindow) GetHigh() fixedpoint.Value {
|
||||||
high := k.First().GetHigh()
|
first := k.First()
|
||||||
|
high := first.GetHigh()
|
||||||
for _, line := range k {
|
for _, line := range k {
|
||||||
high = fixedpoint.Max(high, line.GetHigh())
|
high = fixedpoint.Max(high, line.GetHigh())
|
||||||
}
|
}
|
||||||
|
@ -330,7 +332,8 @@ func (k KLineWindow) GetHigh() fixedpoint.Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k KLineWindow) GetLow() fixedpoint.Value {
|
func (k KLineWindow) GetLow() fixedpoint.Value {
|
||||||
low := k.First().GetLow()
|
first := k.First()
|
||||||
|
low := first.GetLow()
|
||||||
for _, line := range k {
|
for _, line := range k {
|
||||||
low = fixedpoint.Min(low, line.GetLow())
|
low = fixedpoint.Min(low, line.GetLow())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user