all: refactor standard indicator helper and fix tests

This commit is contained in:
c9s 2022-07-26 18:35:50 +08:00
parent 0456cdc7a9
commit 3959e288fd
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
14 changed files with 41 additions and 79 deletions

View File

@ -27,7 +27,7 @@ func (s *LowerShadowTakeProfit) Bind(session *ExchangeSession, orderExecutor *Ge
s.session = session s.session = session
s.orderExecutor = orderExecutor s.orderExecutor = orderExecutor
stdIndicatorSet, _ := session.StandardIndicatorSet(s.Symbol) stdIndicatorSet := session.StandardIndicatorSet(s.Symbol)
ewma := stdIndicatorSet.EWMA(s.IntervalWindow) ewma := stdIndicatorSet.EWMA(s.IntervalWindow)

View File

@ -438,17 +438,16 @@ func (session *ExchangeSession) initSymbol(ctx context.Context, environ *Environ
return nil return nil
} }
func (session *ExchangeSession) StandardIndicatorSet(symbol string) (*StandardIndicatorSet, bool) { func (session *ExchangeSession) StandardIndicatorSet(symbol string) *StandardIndicatorSet {
set, ok := session.standardIndicatorSets[symbol] set, ok := session.standardIndicatorSets[symbol]
if !ok { if ok {
if store, ok2 := session.MarketDataStore(symbol); ok2 { return set
set = NewStandardIndicatorSet(symbol, session.MarketDataStream, store)
session.standardIndicatorSets[symbol] = set
return set, true
}
} }
return set, ok store, _ := session.MarketDataStore(symbol)
set = NewStandardIndicatorSet(symbol, session.MarketDataStream, store)
session.standardIndicatorSets[symbol] = set
return set
} }
func (session *ExchangeSession) Position(symbol string) (pos *types.Position, ok bool) { func (session *ExchangeSession) Position(symbol string) (pos *types.Position, ok bool) {

View File

@ -292,7 +292,7 @@ func (trader *Trader) injectFields() error {
return fmt.Errorf("market of symbol %s not found", symbol) return fmt.Errorf("market of symbol %s not found", symbol)
} }
indicatorSet, ok := session.StandardIndicatorSet(symbol) indicatorSet := session.StandardIndicatorSet(symbol)
if !ok { if !ok {
return fmt.Errorf("standardIndicatorSet of symbol %s not found", symbol) return fmt.Errorf("standardIndicatorSet of symbol %s not found", symbol)
} }

View File

@ -61,7 +61,10 @@ func Test_calculateATR(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
atr := &ATR{IntervalWindow: types.IntervalWindow{Window: tt.window}} atr := &ATR{IntervalWindow: types.IntervalWindow{Window: tt.window}}
atr.CalculateAndUpdate(tt.kLines) for _, k := range tt.kLines {
atr.PushK(k)
}
got := atr.Last() got := atr.Last()
diff := math.Trunc((got-tt.want)*100) / 100 diff := math.Trunc((got-tt.want)*100) / 100
if diff != 0 { if diff != 0 {

View File

@ -55,7 +55,7 @@ func (inc *HULL) Length() int {
} }
func (inc *HULL) PushK(k types.KLine) { func (inc *HULL) PushK(k types.KLine) {
if k.EndTime.Before(inc.ma1.EndTime) { if inc.ma1 != nil && inc.ma1.Length() > 0 && k.EndTime.Before(inc.ma1.EndTime) {
return return
} }

View File

@ -4,9 +4,10 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
"github.com/stretchr/testify/assert"
) )
/* /*
@ -26,6 +27,7 @@ func Test_HULL(t *testing.T) {
if err := json.Unmarshal(randomPrices, &input); err != nil { if err := json.Unmarshal(randomPrices, &input); err != nil {
panic(err) panic(err)
} }
tests := []struct { tests := []struct {
name string name string
kLines []types.KLine kLines []types.KLine
@ -44,8 +46,11 @@ func Test_HULL(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
hull := HULL{IntervalWindow: types.IntervalWindow{Window: 16}} hull := &HULL{IntervalWindow: types.IntervalWindow{Window: 16}}
hull.CalculateAndUpdate(tt.kLines) for _, k := range tt.kLines {
hull.PushK(k)
}
last := hull.Last() last := hull.Last()
assert.InDelta(t, tt.want, last, Delta) assert.InDelta(t, tt.want, last, Delta)
assert.InDelta(t, tt.next, hull.Index(1), Delta) assert.InDelta(t, tt.next, hull.Index(1), Delta)

View File

@ -25,7 +25,6 @@ func init() {
} }
type Strategy struct { type Strategy struct {
SourceExchangeName string `json:"sourceExchange"` SourceExchangeName string `json:"sourceExchange"`
TargetExchangeName string `json:"targetExchange"` TargetExchangeName string `json:"targetExchange"`
@ -175,11 +174,7 @@ func (s *Strategy) handleOrderUpdate(order types.Order) {
} }
func (s *Strategy) loadIndicator(sourceSession *bbgo.ExchangeSession) (types.Float64Indicator, error) { func (s *Strategy) loadIndicator(sourceSession *bbgo.ExchangeSession) (types.Float64Indicator, error) {
var standardIndicatorSet, ok = sourceSession.StandardIndicatorSet(s.Symbol) var standardIndicatorSet = sourceSession.StandardIndicatorSet(s.Symbol)
if !ok {
return nil, fmt.Errorf("standardIndicatorSet is nil, symbol %s", s.Symbol)
}
var iw = types.IntervalWindow{Interval: s.MovingAverageInterval, Window: s.MovingAverageWindow} var iw = types.IntervalWindow{Interval: s.MovingAverageInterval, Window: s.MovingAverageWindow}
switch strings.ToUpper(s.MovingAverageType) { switch strings.ToUpper(s.MovingAverageType) {

View File

@ -3,7 +3,6 @@ package funding
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"strings" "strings"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -32,7 +31,7 @@ type Strategy struct {
Market types.Market `json:"-"` Market types.Market `json:"-"`
Quantity fixedpoint.Value `json:"quantity,omitempty"` Quantity fixedpoint.Value `json:"quantity,omitempty"`
MaxExposurePosition fixedpoint.Value `json:"maxExposurePosition"` MaxExposurePosition fixedpoint.Value `json:"maxExposurePosition"`
//Interval types.Interval `json:"interval"` // Interval types.Interval `json:"interval"`
FundingRate *struct { FundingRate *struct {
High fixedpoint.Value `json:"high"` High fixedpoint.Value `json:"high"`
@ -49,11 +48,11 @@ type Strategy struct {
// MovingAverageInterval is the interval of k-lines for the moving average indicator to calculate, // MovingAverageInterval is the interval of k-lines for the moving average indicator to calculate,
// it could be "1m", "5m", "1h" and so on. note that, the moving averages are calculated from // it could be "1m", "5m", "1h" and so on. note that, the moving averages are calculated from
// the k-line data we subscribed // the k-line data we subscribed
//MovingAverageInterval types.Interval `json:"movingAverageInterval"` // MovingAverageInterval types.Interval `json:"movingAverageInterval"`
// //
//// MovingAverageWindow is the number of the window size of the moving average indicator. // // MovingAverageWindow is the number of the window size of the moving average indicator.
//// The number of k-lines in the window. generally used window sizes are 7, 25 and 99 in the TradingView. // // The number of k-lines in the window. generally used window sizes are 7, 25 and 99 in the TradingView.
//MovingAverageWindow int `json:"movingAverageWindow"` // MovingAverageWindow int `json:"movingAverageWindow"`
MovingAverageIntervalWindow types.IntervalWindow `json:"movingAverageIntervalWindow"` MovingAverageIntervalWindow types.IntervalWindow `json:"movingAverageIntervalWindow"`
@ -70,9 +69,9 @@ func (s *Strategy) ID() string {
func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) { func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
// session.Subscribe(types.BookChannel, s.Symbol, types.SubscribeOptions{}) // session.Subscribe(types.BookChannel, s.Symbol, types.SubscribeOptions{})
//session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{ // session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{
// Interval: string(s.Interval), // Interval: string(s.Interval),
//}) // })
for _, detection := range s.SupportDetection { for _, detection := range s.SupportDetection {
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{ session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{
@ -93,23 +92,13 @@ func (s *Strategy) Validate() error {
} }
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error { func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
standardIndicatorSet := session.StandardIndicatorSet(s.Symbol)
standardIndicatorSet, ok := session.StandardIndicatorSet(s.Symbol)
if !ok {
return fmt.Errorf("standardIndicatorSet is nil, symbol %s", s.Symbol)
}
//binanceExchange, ok := session.Exchange.(*binance.Exchange)
//if !ok {
// log.Error("exchange failed")
//}
if !session.Futures { if !session.Futures {
log.Error("futures not enabled in config for this strategy") log.Error("futures not enabled in config for this strategy")
return nil return nil
} }
//if s.FundingRate != nil {
// go s.listenToFundingRate(ctx, binanceExchange)
//}
premiumIndex, err := session.Exchange.(*binance.Exchange).QueryPremiumIndex(ctx, s.Symbol) premiumIndex, err := session.Exchange.(*binance.Exchange).QueryPremiumIndex(ctx, s.Symbol)
if err != nil { if err != nil {
log.Error("exchange does not support funding rate api") log.Error("exchange does not support funding rate api")

View File

@ -66,7 +66,7 @@ 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) store, _ := session.MarketDataStore(s.Symbol)
standardIndicator, _ := session.StandardIndicatorSet(s.Symbol) standardIndicator := session.StandardIndicatorSet(s.Symbol)
s.lastLow = fixedpoint.Zero s.lastLow = fixedpoint.Zero

View File

@ -53,7 +53,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
return fmt.Errorf("market %s is not defined", s.Symbol) return fmt.Errorf("market %s is not defined", s.Symbol)
} }
standardIndicatorSet, ok := session.StandardIndicatorSet(s.Symbol) standardIndicatorSet := session.StandardIndicatorSet(s.Symbol)
if !ok { if !ok {
return fmt.Errorf("standardIndicatorSet is nil, symbol %s", s.Symbol) return fmt.Errorf("standardIndicatorSet is nil, symbol %s", s.Symbol)
} }

View File

@ -8,7 +8,6 @@ import (
"github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/indicator"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
@ -82,32 +81,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.State = &State{Counter: 1} s.State = &State{Counter: 1}
} }
// Optional: You can get the market data store from session indicators := session.StandardIndicatorSet(s.Symbol)
store, ok := session.MarketDataStore(s.Symbol) atr := indicators.ATR(types.IntervalWindow{
if !ok { Interval: types.Interval1m,
return fmt.Errorf("market data store %s not found", s.Symbol) Window: 14,
} })
// Initialize a custom indicator
atr := &indicator.ATR{
IntervalWindow: types.IntervalWindow{
Interval: types.Interval1m,
Window: 14,
},
}
// Bind the indicator to the market data store, so that when a new kline is received,
// the indicator will be updated.
atr.Bind(store)
// To get the past kline history, call KLinesOfInterval from the market data store
klines, ok := store.KLinesOfInterval(types.Interval1m)
if !ok {
return fmt.Errorf("market data store %s lkline not found", s.Symbol)
}
// Use the history data to initialize the indicator
atr.CalculateAndUpdate(*klines)
// To get the market information from the current session // To get the market information from the current session
// The market object provides the precision, MoQ (minimal of quantity) information // The market object provides the precision, MoQ (minimal of quantity) information

View File

@ -387,10 +387,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
log.Infof("adjusted minimal support volume to %s according to sensitivity %s", s.MinVolume.String(), s.Sensitivity.String()) log.Infof("adjusted minimal support volume to %s according to sensitivity %s", s.MinVolume.String(), s.Sensitivity.String())
} }
standardIndicatorSet, ok := session.StandardIndicatorSet(s.Symbol) standardIndicatorSet := session.StandardIndicatorSet(s.Symbol)
if !ok {
return fmt.Errorf("standardIndicatorSet is nil, symbol %s", s.Symbol)
}
if s.TriggerMovingAverage != zeroiw { if s.TriggerMovingAverage != zeroiw {
s.triggerEMA = standardIndicatorSet.EWMA(s.TriggerMovingAverage) s.triggerEMA = standardIndicatorSet.EWMA(s.TriggerMovingAverage)

View File

@ -3,7 +3,6 @@ package techsignal
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"strings" "strings"
"time" "time"
@ -145,10 +144,7 @@ func (s *Strategy) listenToFundingRate(ctx context.Context, exchange *binance.Ex
} }
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error { func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
standardIndicatorSet, ok := session.StandardIndicatorSet(s.Symbol) standardIndicatorSet := session.StandardIndicatorSet(s.Symbol)
if !ok {
return fmt.Errorf("standardIndicatorSet is nil, symbol %s", s.Symbol)
}
if s.FundingRate != nil { if s.FundingRate != nil {
if binanceExchange, ok := session.Exchange.(*binance.Exchange); ok { if binanceExchange, ok := session.Exchange.(*binance.Exchange); ok {

View File

@ -681,7 +681,7 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
return fmt.Errorf("maker session market %s is not defined", s.Symbol) return fmt.Errorf("maker session market %s is not defined", s.Symbol)
} }
standardIndicatorSet, ok := s.sourceSession.StandardIndicatorSet(s.Symbol) standardIndicatorSet := s.sourceSession.StandardIndicatorSet(s.Symbol)
if !ok { if !ok {
return fmt.Errorf("%s standard indicator set not found", s.Symbol) return fmt.Errorf("%s standard indicator set not found", s.Symbol)
} }