mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 23:05:15 +00:00
Merge pull request #844 from c9s/strategy/pivotshort
strategy/pivotshort: refactor and update indicator api usage
This commit is contained in:
commit
605c66556e
|
@ -34,9 +34,3 @@ func (inc *Low) PushK(k types.KLine) {
|
||||||
inc.EndTime = k.EndTime.Time()
|
inc.EndTime = k.EndTime.Time()
|
||||||
inc.EmitUpdate(inc.Last())
|
inc.EmitUpdate(inc.Last())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inc *Low) LoadK(allKLines []types.KLine) {
|
|
||||||
for _, k := range allKLines {
|
|
||||||
inc.PushK(k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -60,42 +60,22 @@ func (inc *MACD) Last() float64 {
|
||||||
return inc.Values[len(inc.Values)-1]
|
return inc.Values[len(inc.Values)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (inc *MACD) Length() int {
|
||||||
|
return len(inc.Values)
|
||||||
|
}
|
||||||
|
|
||||||
func (inc *MACD) PushK(k types.KLine) {
|
func (inc *MACD) PushK(k types.KLine) {
|
||||||
inc.Update(k.Close.Float64())
|
inc.Update(k.Close.Float64())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inc *MACD) CalculateAndUpdate(allKLines []types.KLine) {
|
func (inc *MACD) MACD() types.SeriesExtend {
|
||||||
if len(allKLines) == 0 {
|
out := &MACDValues{MACD: inc}
|
||||||
return
|
out.SeriesBase.Series = out
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
last := allKLines[len(allKLines)-1]
|
func (inc *MACD) Singals() types.SeriesExtend {
|
||||||
if len(inc.Values) == 0 {
|
return inc.SignalLine
|
||||||
for _, k := range allKLines {
|
|
||||||
if inc.EndTime != zeroTime && !k.EndTime.After(inc.EndTime) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
inc.PushK(k)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
inc.PushK(last)
|
|
||||||
}
|
|
||||||
|
|
||||||
inc.EmitUpdate(inc.Last())
|
|
||||||
inc.EndTime = last.EndTime.Time()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (inc *MACD) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) {
|
|
||||||
if inc.Interval != interval {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
inc.CalculateAndUpdate(window)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (inc *MACD) Bind(updater KLineWindowUpdater) {
|
|
||||||
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MACDValues struct {
|
type MACDValues struct {
|
||||||
|
@ -123,13 +103,3 @@ func (inc *MACDValues) Index(i int) float64 {
|
||||||
func (inc *MACDValues) Length() int {
|
func (inc *MACDValues) Length() int {
|
||||||
return len(inc.Values)
|
return len(inc.Values)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inc *MACD) MACD() types.SeriesExtend {
|
|
||||||
out := &MACDValues{MACD: inc}
|
|
||||||
out.SeriesBase.Series = out
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func (inc *MACD) Singals() types.SeriesExtend {
|
|
||||||
return inc.SignalLine
|
|
||||||
}
|
|
||||||
|
|
|
@ -41,7 +41,9 @@ func Test_calculateMACD(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
iw := types.IntervalWindow{Window: 9}
|
iw := types.IntervalWindow{Window: 9}
|
||||||
macd := MACD{IntervalWindow: iw, ShortPeriod: 12, LongPeriod: 26}
|
macd := MACD{IntervalWindow: iw, ShortPeriod: 12, LongPeriod: 26}
|
||||||
macd.CalculateAndUpdate(tt.kLines)
|
for _, k := range tt.kLines {
|
||||||
|
macd.PushK(k)
|
||||||
|
}
|
||||||
|
|
||||||
got := macd.Last()
|
got := macd.Last()
|
||||||
diff := math.Trunc((got-tt.want)*100) / 100
|
diff := math.Trunc((got-tt.want)*100) / 100
|
||||||
|
|
|
@ -34,7 +34,7 @@ type BreakLow struct {
|
||||||
TrendEMA *types.IntervalWindow `json:"trendEMA"`
|
TrendEMA *types.IntervalWindow `json:"trendEMA"`
|
||||||
|
|
||||||
lastLow fixedpoint.Value
|
lastLow fixedpoint.Value
|
||||||
pivot *indicator.Pivot
|
pivot *indicator.PivotLow
|
||||||
stopEWMA *indicator.EWMA
|
stopEWMA *indicator.EWMA
|
||||||
|
|
||||||
trendEWMA *indicator.EWMA
|
trendEWMA *indicator.EWMA
|
||||||
|
@ -65,14 +65,11 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
|
|
||||||
position := orderExecutor.Position()
|
position := orderExecutor.Position()
|
||||||
symbol := position.Symbol
|
symbol := position.Symbol
|
||||||
store, _ := session.MarketDataStore(s.Symbol)
|
|
||||||
standardIndicator := session.StandardIndicatorSet(s.Symbol)
|
standardIndicator := session.StandardIndicatorSet(s.Symbol)
|
||||||
|
|
||||||
s.lastLow = fixedpoint.Zero
|
s.lastLow = fixedpoint.Zero
|
||||||
|
|
||||||
s.pivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow}
|
s.pivot = standardIndicator.PivotLow(s.IntervalWindow)
|
||||||
s.pivot.Bind(store)
|
|
||||||
preloadPivot(s.pivot, store)
|
|
||||||
|
|
||||||
if s.StopEMA != nil {
|
if s.StopEMA != nil {
|
||||||
s.stopEWMA = standardIndicator.EWMA(*s.StopEMA)
|
s.stopEWMA = standardIndicator.EWMA(*s.StopEMA)
|
||||||
|
@ -89,13 +86,13 @@ 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.LastLow())
|
lastLow := fixedpoint.NewFromFloat(s.pivot.Lows.Last())
|
||||||
if lastLow.IsZero() {
|
if lastLow.IsZero() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if lastLow.Compare(s.lastLow) != 0 {
|
if lastLow.Compare(s.lastLow) != 0 {
|
||||||
bbgo.Notify("%s found new pivot low: %f", s.Symbol, s.pivot.LastLow())
|
bbgo.Notify("%s found new pivot low: %f", s.Symbol, s.pivot.Lows.Last())
|
||||||
}
|
}
|
||||||
|
|
||||||
s.lastLow = lastLow
|
s.lastLow = lastLow
|
||||||
|
@ -120,8 +117,7 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
})
|
})
|
||||||
|
|
||||||
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())
|
||||||
lastLow := fixedpoint.NewFromFloat(s.pivot.LastLow())
|
|
||||||
if lastLow.IsZero() {
|
if lastLow.IsZero() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -133,13 +129,12 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
s.lastLow = lastLow
|
s.lastLow = lastLow
|
||||||
s.pivotLowPrices = append(s.pivotLowPrices, s.lastLow)
|
s.pivotLowPrices = append(s.pivotLowPrices, s.lastLow)
|
||||||
|
|
||||||
|
|
||||||
// when position is opened, do not send pivot low notify
|
// when position is opened, do not send pivot low notify
|
||||||
if position.IsOpened(kline.Close) {
|
if position.IsOpened(kline.Close) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bbgo.Notify("%s new pivot low: %f", s.Symbol, s.pivot.LastLow())
|
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) {
|
session.MarketDataStream.OnKLineClosed(types.KLineWith(symbol, types.Interval1m, func(kline types.KLine) {
|
||||||
|
@ -246,4 +241,3 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ type ResistanceShort struct {
|
||||||
session *bbgo.ExchangeSession
|
session *bbgo.ExchangeSession
|
||||||
orderExecutor *bbgo.GeneralOrderExecutor
|
orderExecutor *bbgo.GeneralOrderExecutor
|
||||||
|
|
||||||
resistancePivot *indicator.Pivot
|
resistancePivot *indicator.PivotLow
|
||||||
resistancePrices []float64
|
resistancePrices []float64
|
||||||
currentResistancePrice fixedpoint.Value
|
currentResistancePrice fixedpoint.Value
|
||||||
|
|
||||||
|
@ -47,19 +47,10 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
|
||||||
s.GroupDistance = fixedpoint.NewFromFloat(0.01)
|
s.GroupDistance = fixedpoint.NewFromFloat(0.01)
|
||||||
}
|
}
|
||||||
|
|
||||||
store, _ := session.MarketDataStore(s.Symbol)
|
s.resistancePivot = session.StandardIndicatorSet(s.Symbol).PivotLow(s.IntervalWindow)
|
||||||
|
|
||||||
s.resistancePivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow}
|
|
||||||
s.resistancePivot.Bind(store)
|
|
||||||
|
|
||||||
// preload history kline data to the resistance pivot indicator
|
|
||||||
// we use the last kline to find the higher lows
|
|
||||||
lastKLine := preloadPivot(s.resistancePivot, store)
|
|
||||||
|
|
||||||
// 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
|
||||||
if lastKLine != nil {
|
s.updateResistanceOrders(fixedpoint.NewFromFloat(s.resistancePivot.Lows.Last()))
|
||||||
s.updateResistanceOrders(lastKLine.Close)
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
||||||
|
|
|
@ -35,7 +35,7 @@ type SupportTakeProfit struct {
|
||||||
|
|
||||||
Ratio fixedpoint.Value `json:"ratio"`
|
Ratio fixedpoint.Value `json:"ratio"`
|
||||||
|
|
||||||
pivot *indicator.Pivot
|
pivot *indicator.PivotLow
|
||||||
orderExecutor *bbgo.GeneralOrderExecutor
|
orderExecutor *bbgo.GeneralOrderExecutor
|
||||||
session *bbgo.ExchangeSession
|
session *bbgo.ExchangeSession
|
||||||
activeOrders *bbgo.ActiveOrderBook
|
activeOrders *bbgo.ActiveOrderBook
|
||||||
|
@ -62,11 +62,8 @@ func (s *SupportTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *b
|
||||||
s.activeOrders.BindStream(session.UserDataStream)
|
s.activeOrders.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
position := orderExecutor.Position()
|
position := orderExecutor.Position()
|
||||||
symbol := position.Symbol
|
|
||||||
store, _ := session.MarketDataStore(symbol)
|
s.pivot = session.StandardIndicatorSet(s.Symbol).PivotLow(s.IntervalWindow)
|
||||||
s.pivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow}
|
|
||||||
s.pivot.Bind(store)
|
|
||||||
preloadPivot(s.pivot, store)
|
|
||||||
|
|
||||||
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) {
|
||||||
if !s.updateSupportPrice(kline.Close) {
|
if !s.updateSupportPrice(kline.Close) {
|
||||||
|
@ -88,7 +85,7 @@ func (s *SupportTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *b
|
||||||
|
|
||||||
bbgo.Notify("placing %s take profit order at price %f", s.Symbol, buyPrice.Float64())
|
bbgo.Notify("placing %s take profit order at price %f", s.Symbol, buyPrice.Float64())
|
||||||
createdOrders, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
createdOrders, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
||||||
Symbol: symbol,
|
Symbol: s.Symbol,
|
||||||
Type: types.OrderTypeLimitMaker,
|
Type: types.OrderTypeLimitMaker,
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
Price: buyPrice,
|
Price: buyPrice,
|
||||||
|
@ -215,7 +212,6 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
||||||
s.ExitMethods.SetAndSubscribe(session, s)
|
s.ExitMethods.SetAndSubscribe(session, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *Strategy) CurrentPosition() *types.Position {
|
func (s *Strategy) CurrentPosition() *types.Position {
|
||||||
return s.Position
|
return s.Position
|
||||||
}
|
}
|
||||||
|
@ -293,21 +289,3 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func preloadPivot(pivot *indicator.Pivot, store *bbgo.MarketDataStore) *types.KLine {
|
|
||||||
klines, ok := store.KLinesOfInterval(pivot.Interval)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
last := (*klines)[len(*klines)-1]
|
|
||||||
log.Debugf("updating pivot indicator: %d klines", len(*klines))
|
|
||||||
|
|
||||||
for i := pivot.Window; i < len(*klines); i++ {
|
|
||||||
pivot.CalculateAndUpdate((*klines)[0 : i+1])
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("found %v previous lows: %v", pivot.IntervalWindow, pivot.Lows)
|
|
||||||
log.Debugf("found %v previous highs: %v", pivot.IntervalWindow, pivot.Highs)
|
|
||||||
return &last
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user