mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 14:55:16 +00:00
Merge pull request #846 from c9s/strategy/pivotshort
strategy/pivotshort: refactor breaklow + add fake break stop
This commit is contained in:
commit
3aeb6912c9
|
@ -42,13 +42,13 @@ exchangeStrategies:
|
||||||
# Notice: When marketOrder is set, bounceRatio will not be used.
|
# Notice: When marketOrder is set, bounceRatio will not be used.
|
||||||
# bounceRatio: 0.1%
|
# bounceRatio: 0.1%
|
||||||
|
|
||||||
# stopEMARange is the price range we allow short.
|
# stopEMA is the price range we allow short.
|
||||||
# Short-allowed price range = [current price] > [EMA] * (1 - [stopEMARange])
|
# Short-allowed price range = [current price] > [EMA] * (1 - [stopEMARange])
|
||||||
# Higher the stopEMARange than higher the chance to open a short
|
# Higher the stopEMARange than higher the chance to open a short
|
||||||
stopEMARange: 2%
|
|
||||||
stopEMA:
|
stopEMA:
|
||||||
interval: 1h
|
interval: 1h
|
||||||
window: 99
|
window: 99
|
||||||
|
range: 2%
|
||||||
|
|
||||||
trendEMA:
|
trendEMA:
|
||||||
interval: 1d
|
interval: 1d
|
||||||
|
|
|
@ -72,7 +72,9 @@ func (s *CumulatedVolumeTakeProfit) Bind(session *ExchangeSession, orderExecutor
|
||||||
cqv.Float64(),
|
cqv.Float64(),
|
||||||
s.MinQuoteVolume.Float64(), kline.Close.Float64())
|
s.MinQuoteVolume.Float64(), kline.Close.Float64())
|
||||||
|
|
||||||
_ = orderExecutor.ClosePosition(context.Background(), fixedpoint.One, "cumulatedVolumeTakeProfit")
|
if err := orderExecutor.ClosePosition(context.Background(), fixedpoint.One, "cumulatedVolumeTakeProfit") ; err != nil {
|
||||||
|
log.WithError(err).Errorf("close position error")
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -25,7 +25,7 @@ type StandardIndicatorSet struct {
|
||||||
// interval -> window
|
// interval -> window
|
||||||
boll map[types.IntervalWindowBandWidth]*indicator.BOLL
|
boll map[types.IntervalWindowBandWidth]*indicator.BOLL
|
||||||
stoch map[types.IntervalWindow]*indicator.STOCH
|
stoch map[types.IntervalWindow]*indicator.STOCH
|
||||||
simples map[types.IntervalWindow]indicator.Simple
|
simples map[types.IntervalWindow]indicator.KLinePusher
|
||||||
|
|
||||||
stream types.Stream
|
stream types.Stream
|
||||||
store *MarketDataStore
|
store *MarketDataStore
|
||||||
|
@ -36,7 +36,7 @@ func NewStandardIndicatorSet(symbol string, stream types.Stream, store *MarketDa
|
||||||
Symbol: symbol,
|
Symbol: symbol,
|
||||||
store: store,
|
store: store,
|
||||||
stream: stream,
|
stream: stream,
|
||||||
simples: make(map[types.IntervalWindow]indicator.Simple),
|
simples: make(map[types.IntervalWindow]indicator.KLinePusher),
|
||||||
|
|
||||||
boll: make(map[types.IntervalWindowBandWidth]*indicator.BOLL),
|
boll: make(map[types.IntervalWindowBandWidth]*indicator.BOLL),
|
||||||
stoch: make(map[types.IntervalWindow]*indicator.STOCH),
|
stoch: make(map[types.IntervalWindow]*indicator.STOCH),
|
||||||
|
@ -53,7 +53,7 @@ func (s *StandardIndicatorSet) initAndBind(inc indicator.KLinePusher, iw types.I
|
||||||
s.stream.OnKLineClosed(types.KLineWith(s.Symbol, iw.Interval, inc.PushK))
|
s.stream.OnKLineClosed(types.KLineWith(s.Symbol, iw.Interval, inc.PushK))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StandardIndicatorSet) allocateSimpleIndicator(t indicator.Simple, iw types.IntervalWindow) indicator.Simple {
|
func (s *StandardIndicatorSet) allocateSimpleIndicator(t indicator.KLinePusher, iw types.IntervalWindow) indicator.KLinePusher {
|
||||||
inc, ok := s.simples[iw]
|
inc, ok := s.simples[iw]
|
||||||
if ok {
|
if ok {
|
||||||
return inc
|
return inc
|
||||||
|
|
|
@ -11,9 +11,10 @@ import (
|
||||||
|
|
||||||
//go:generate callbackgen -type PivotLow
|
//go:generate callbackgen -type PivotLow
|
||||||
type PivotLow struct {
|
type PivotLow struct {
|
||||||
types.IntervalWindow
|
|
||||||
types.SeriesBase
|
types.SeriesBase
|
||||||
|
|
||||||
|
types.IntervalWindow
|
||||||
|
|
||||||
Lows types.Float64Slice
|
Lows types.Float64Slice
|
||||||
Values types.Float64Slice
|
Values types.Float64Slice
|
||||||
EndTime time.Time
|
EndTime time.Time
|
||||||
|
@ -71,15 +72,11 @@ func calculatePivotLow(lows types.Float64Slice, window int) (float64, error) {
|
||||||
return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window)
|
return 0., fmt.Errorf("insufficient elements for calculating with window = %d", window)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pv types.Float64Slice
|
end := length - 1
|
||||||
for _, low := range lows {
|
min := lows[end-(window-1):].Min()
|
||||||
pv.Push(low)
|
if min == lows.Index(int(window/2.)-1) {
|
||||||
|
return min, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pl := 0.
|
return 0., nil
|
||||||
if lows.Min() == lows.Index(int(window/2.)-1) {
|
|
||||||
pl = lows.Min()
|
|
||||||
}
|
|
||||||
|
|
||||||
return pl, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,7 @@ func CalculateBaseQuantity(session *bbgo.ExchangeSession, market types.Market, p
|
||||||
leverage = fixedpoint.NewFromInt(3)
|
leverage = fixedpoint.NewFromInt(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
baseBalance, _ := session.Account.Balance(market.BaseCurrency)
|
baseBalance, _ := session.Account.Balance(market.BaseCurrency)
|
||||||
quoteBalance, _ := session.Account.Balance(market.QuoteCurrency)
|
quoteBalance, _ := session.Account.Balance(market.QuoteCurrency)
|
||||||
|
|
||||||
|
@ -185,11 +186,11 @@ func CalculateBaseQuantity(session *bbgo.ExchangeSession, market types.Market, p
|
||||||
return quantity, fmt.Errorf("quantity is zero, can not submit sell order, please check your quantity settings")
|
return quantity, fmt.Errorf("quantity is zero, can not submit sell order, please check your quantity settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
// using leverage -- starts from here
|
|
||||||
if !quantity.IsZero() {
|
if !quantity.IsZero() {
|
||||||
return quantity, nil
|
return quantity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// using leverage -- starts from here
|
||||||
logrus.Infof("calculating available leveraged base quantity: base balance = %+v, quote balance = %+v", baseBalance, quoteBalance)
|
logrus.Infof("calculating available leveraged base quantity: base balance = %+v, quote balance = %+v", baseBalance, quoteBalance)
|
||||||
|
|
||||||
// calculate the quantity automatically
|
// calculate the quantity automatically
|
||||||
|
|
|
@ -10,6 +10,19 @@ import (
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type StopEMA struct {
|
||||||
|
types.IntervalWindow
|
||||||
|
Range fixedpoint.Value `json:"range"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TrendEMA struct {
|
||||||
|
types.IntervalWindow
|
||||||
|
}
|
||||||
|
|
||||||
|
type FakeBreakStop struct {
|
||||||
|
types.IntervalWindow
|
||||||
|
}
|
||||||
|
|
||||||
// BreakLow -- when price breaks the previous pivot low, we set a trade entry
|
// BreakLow -- when price breaks the previous pivot low, we set a trade entry
|
||||||
type BreakLow struct {
|
type BreakLow struct {
|
||||||
Symbol string
|
Symbol string
|
||||||
|
@ -26,22 +39,28 @@ type BreakLow struct {
|
||||||
// limit sell price = breakLowPrice * (1 + BounceRatio)
|
// limit sell price = breakLowPrice * (1 + BounceRatio)
|
||||||
BounceRatio fixedpoint.Value `json:"bounceRatio"`
|
BounceRatio fixedpoint.Value `json:"bounceRatio"`
|
||||||
|
|
||||||
Leverage fixedpoint.Value `json:"leverage"`
|
Leverage fixedpoint.Value `json:"leverage"`
|
||||||
Quantity fixedpoint.Value `json:"quantity"`
|
Quantity fixedpoint.Value `json:"quantity"`
|
||||||
StopEMARange fixedpoint.Value `json:"stopEMARange"`
|
|
||||||
StopEMA *types.IntervalWindow `json:"stopEMA"`
|
|
||||||
|
|
||||||
TrendEMA *types.IntervalWindow `json:"trendEMA"`
|
StopEMA *StopEMA `json:"stopEMA"`
|
||||||
|
|
||||||
|
TrendEMA *TrendEMA `json:"trendEMA"`
|
||||||
|
|
||||||
|
FakeBreakStop *FakeBreakStop `json:"fakeBreakStop"`
|
||||||
|
|
||||||
|
lastLow fixedpoint.Value
|
||||||
|
|
||||||
|
// lastBreakLow is the low that the price just break
|
||||||
|
lastBreakLow fixedpoint.Value
|
||||||
|
|
||||||
|
pivotLow *indicator.PivotLow
|
||||||
|
pivotLowPrices []fixedpoint.Value
|
||||||
|
|
||||||
lastLow fixedpoint.Value
|
|
||||||
pivot *indicator.PivotLow
|
|
||||||
stopEWMA *indicator.EWMA
|
stopEWMA *indicator.EWMA
|
||||||
|
|
||||||
trendEWMA *indicator.EWMA
|
trendEWMA *indicator.EWMA
|
||||||
trendEWMALast, trendEWMACurrent float64
|
trendEWMALast, trendEWMACurrent float64
|
||||||
|
|
||||||
pivotLowPrices []fixedpoint.Value
|
|
||||||
|
|
||||||
orderExecutor *bbgo.GeneralOrderExecutor
|
orderExecutor *bbgo.GeneralOrderExecutor
|
||||||
session *bbgo.ExchangeSession
|
session *bbgo.ExchangeSession
|
||||||
}
|
}
|
||||||
|
@ -57,6 +76,10 @@ func (s *BreakLow) Subscribe(session *bbgo.ExchangeSession) {
|
||||||
if s.TrendEMA != nil {
|
if s.TrendEMA != nil {
|
||||||
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.TrendEMA.Interval})
|
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.TrendEMA.Interval})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.FakeBreakStop != nil {
|
||||||
|
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.FakeBreakStop.Interval})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
|
func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
|
||||||
|
@ -69,14 +92,14 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
|
|
||||||
s.lastLow = fixedpoint.Zero
|
s.lastLow = fixedpoint.Zero
|
||||||
|
|
||||||
s.pivot = standardIndicator.PivotLow(s.IntervalWindow)
|
s.pivotLow = standardIndicator.PivotLow(s.IntervalWindow)
|
||||||
|
|
||||||
if s.StopEMA != nil {
|
if s.StopEMA != nil {
|
||||||
s.stopEWMA = standardIndicator.EWMA(*s.StopEMA)
|
s.stopEWMA = standardIndicator.EWMA(s.StopEMA.IntervalWindow)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.TrendEMA != nil {
|
if s.TrendEMA != nil {
|
||||||
s.trendEWMA = standardIndicator.EWMA(*s.TrendEMA)
|
s.trendEWMA = standardIndicator.EWMA(s.TrendEMA.IntervalWindow)
|
||||||
|
|
||||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.TrendEMA.Interval, func(kline types.KLine) {
|
session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.TrendEMA.Interval, func(kline types.KLine) {
|
||||||
s.trendEWMALast = s.trendEWMACurrent
|
s.trendEWMALast = s.trendEWMACurrent
|
||||||
|
@ -86,58 +109,52 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
|
|
||||||
// update pivot low data
|
// update pivot low data
|
||||||
session.MarketDataStream.OnStart(func() {
|
session.MarketDataStream.OnStart(func() {
|
||||||
lastLow := fixedpoint.NewFromFloat(s.pivot.Lows.Last())
|
if s.updatePivotLow() {
|
||||||
if lastLow.IsZero() {
|
bbgo.Notify("%s new pivot low: %f", s.Symbol, s.pivotLow.Last())
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if lastLow.Compare(s.lastLow) != 0 {
|
s.pilotQuantityCalculation()
|
||||||
bbgo.Notify("%s found new pivot low: %f", s.Symbol, s.pivot.Lows.Last())
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lastLow = lastLow
|
|
||||||
s.pivotLowPrices = append(s.pivotLowPrices, s.lastLow)
|
|
||||||
|
|
||||||
log.Infof("pilot calculation for max position: last low = %f, quantity = %f, leverage = %f",
|
|
||||||
s.lastLow.Float64(),
|
|
||||||
s.Quantity.Float64(),
|
|
||||||
s.Leverage.Float64())
|
|
||||||
|
|
||||||
quantity, err := risk.CalculateBaseQuantity(s.session, s.Market, s.lastLow, s.Quantity, s.Leverage)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Errorf("quantity calculation error")
|
|
||||||
}
|
|
||||||
|
|
||||||
if quantity.IsZero() {
|
|
||||||
log.WithError(err).Errorf("quantity is zero, can not submit order")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bbgo.Notify("%s %f quantity will be used for shorting", s.Symbol, quantity.Float64())
|
|
||||||
})
|
})
|
||||||
|
|
||||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) {
|
session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, s.Interval, func(kline types.KLine) {
|
||||||
lastLow := fixedpoint.NewFromFloat(s.pivot.Lows.Last())
|
if s.updatePivotLow() {
|
||||||
if lastLow.IsZero() {
|
// when position is opened, do not send pivot low notify
|
||||||
return
|
if position.IsOpened(kline.Close) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bbgo.Notify("%s new pivot low: %f", s.Symbol, s.pivotLow.Last())
|
||||||
}
|
}
|
||||||
|
|
||||||
if lastLow.Compare(s.lastLow) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lastLow = lastLow
|
|
||||||
s.pivotLowPrices = append(s.pivotLowPrices, s.lastLow)
|
|
||||||
|
|
||||||
// when position is opened, do not send pivot low notify
|
|
||||||
if position.IsOpened(kline.Close) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bbgo.Notify("%s new pivot low: %f", s.Symbol, s.pivot.Lows.Last())
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, types.Interval1m, func(kline types.KLine) {
|
if s.FakeBreakStop != nil {
|
||||||
|
// if the position is already opened, and we just break the low, this checks if the kline closed above the low,
|
||||||
|
// so that we can close the position earlier
|
||||||
|
session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, s.FakeBreakStop.Interval, func(k types.KLine) {
|
||||||
|
// make sure the position is opened, and it's a short position
|
||||||
|
if !position.IsOpened(k.Close) || !position.IsShort() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we recorded the last break low
|
||||||
|
if s.lastBreakLow.IsZero() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
log.WithError(err).Error("position close error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset to zero
|
||||||
|
s.lastBreakLow = fixedpoint.Zero
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
session.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, types.Interval1m, func(kline types.KLine) {
|
||||||
if len(s.pivotLowPrices) == 0 {
|
if len(s.pivotLowPrices) == 0 {
|
||||||
log.Infof("currently there is no pivot low prices, can not check break low...")
|
log.Infof("currently there is no pivot low prices, can not check break low...")
|
||||||
return
|
return
|
||||||
|
@ -170,6 +187,10 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
|
|
||||||
log.Infof("%s breakLow signal detected, closed price %f < breakPrice %f", kline.Symbol, closePrice.Float64(), breakPrice.Float64())
|
log.Infof("%s breakLow signal detected, closed price %f < breakPrice %f", kline.Symbol, closePrice.Float64(), breakPrice.Float64())
|
||||||
|
|
||||||
|
if s.lastBreakLow.IsZero() || previousLow.Compare(s.lastBreakLow) < 0 {
|
||||||
|
s.lastBreakLow = previousLow
|
||||||
|
}
|
||||||
|
|
||||||
if position.IsOpened(kline.Close) {
|
if position.IsOpened(kline.Close) {
|
||||||
log.Infof("position is already opened, skip short")
|
log.Infof("position is already opened, skip short")
|
||||||
return
|
return
|
||||||
|
@ -193,9 +214,9 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
emaStopShortPrice := ema.Mul(fixedpoint.One.Sub(s.StopEMARange))
|
emaStopShortPrice := ema.Mul(fixedpoint.One.Sub(s.StopEMA.Range))
|
||||||
if closePrice.Compare(emaStopShortPrice) < 0 {
|
if closePrice.Compare(emaStopShortPrice) < 0 {
|
||||||
log.Infof("stopEMA protection: close price %f < EMA(%v) = %f", closePrice.Float64(), s.StopEMA, ema.Float64())
|
log.Infof("stopEMA protection: close price %f < EMA(%v %f) * (1 - RANGE %f) = %f", closePrice.Float64(), s.StopEMA, ema.Float64(), s.StopEMA.Range.Float64(), emaStopShortPrice.Float64())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,3 +262,33 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *BreakLow) pilotQuantityCalculation() {
|
||||||
|
log.Infof("pilot calculation for max position: last low = %f, quantity = %f, leverage = %f",
|
||||||
|
s.lastLow.Float64(),
|
||||||
|
s.Quantity.Float64(),
|
||||||
|
s.Leverage.Float64())
|
||||||
|
|
||||||
|
quantity, err := risk.CalculateBaseQuantity(s.session, s.Market, s.lastLow, s.Quantity, s.Leverage)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("quantity calculation error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if quantity.IsZero() {
|
||||||
|
log.WithError(err).Errorf("quantity is zero, can not submit order")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bbgo.Notify("%s %f quantity will be used for shorting", s.Symbol, quantity.Float64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BreakLow) updatePivotLow() bool {
|
||||||
|
lastLow := fixedpoint.NewFromFloat(s.pivotLow.Last())
|
||||||
|
if lastLow.IsZero() || lastLow.Compare(s.lastLow) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
s.lastLow = lastLow
|
||||||
|
s.pivotLowPrices = append(s.pivotLowPrices, lastLow)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
|
||||||
s.resistancePivot = session.StandardIndicatorSet(s.Symbol).PivotLow(s.IntervalWindow)
|
s.resistancePivot = session.StandardIndicatorSet(s.Symbol).PivotLow(s.IntervalWindow)
|
||||||
|
|
||||||
// use the last kline from the history before we get the next closed kline
|
// use the last kline from the history before we get the next closed kline
|
||||||
s.updateResistanceOrders(fixedpoint.NewFromFloat(s.resistancePivot.Lows.Last()))
|
s.updateResistanceOrders(fixedpoint.NewFromFloat(s.resistancePivot.Last()))
|
||||||
|
|
||||||
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) {
|
||||||
position := s.orderExecutor.Position()
|
position := s.orderExecutor.Position()
|
||||||
|
@ -77,7 +77,7 @@ func tail(arr []float64, length int) []float64 {
|
||||||
func (s *ResistanceShort) updateCurrentResistancePrice(closePrice fixedpoint.Value) bool {
|
func (s *ResistanceShort) updateCurrentResistancePrice(closePrice fixedpoint.Value) bool {
|
||||||
minDistance := s.MinDistance.Float64()
|
minDistance := s.MinDistance.Float64()
|
||||||
groupDistance := s.GroupDistance.Float64()
|
groupDistance := s.GroupDistance.Float64()
|
||||||
resistancePrices := findPossibleResistancePrices(closePrice.Float64()*(1.0+minDistance), groupDistance, tail(s.resistancePivot.Lows, 6))
|
resistancePrices := findPossibleResistancePrices(closePrice.Float64()*(1.0+minDistance), groupDistance, s.resistancePivot.Values.Tail(6))
|
||||||
if len(resistancePrices) == 0 {
|
if len(resistancePrices) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user