all: solve cyclic import

This commit is contained in:
c9s 2022-09-09 17:40:17 +08:00
parent 2e95246687
commit 8dca24e9ee
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
9 changed files with 38 additions and 46 deletions

View File

@ -21,7 +21,7 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
"gopkg.in/tucnak/telebot.v2" "gopkg.in/tucnak/telebot.v2"
exchange2 "github.com/c9s/bbgo/pkg/exchange" "github.com/c9s/bbgo/pkg/exchange"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/interact" "github.com/c9s/bbgo/pkg/interact"
"github.com/c9s/bbgo/pkg/notifier/slacknotifier" "github.com/c9s/bbgo/pkg/notifier/slacknotifier"
@ -223,12 +223,12 @@ func (environ *Environment) ConfigureExchangeSessions(userConfig *Config) error
func (environ *Environment) AddExchangesByViperKeys() error { func (environ *Environment) AddExchangesByViperKeys() error {
for _, n := range types.SupportedExchanges { for _, n := range types.SupportedExchanges {
if viper.IsSet(string(n) + "-api-key") { if viper.IsSet(string(n) + "-api-key") {
exchange, err := exchange2.NewWithEnvVarPrefix(n, "") ex, err := exchange.NewWithEnvVarPrefix(n, "")
if err != nil { if err != nil {
return err return err
} }
environ.AddExchange(n.String(), exchange) environ.AddExchange(n.String(), ex)
} }
} }

1
pkg/bbgo/log.go Normal file
View File

@ -0,0 +1 @@
package bbgo

View File

@ -9,7 +9,6 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/risk"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
@ -180,7 +179,7 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
if options.Long { if options.Long {
if quantity.IsZero() { if quantity.IsZero() {
quoteQuantity, err := risk.CalculateQuoteQuantity(ctx, e.session, e.position.QuoteCurrency, options.Leverage) quoteQuantity, err := CalculateQuoteQuantity(ctx, e.session, e.position.QuoteCurrency, options.Leverage)
if err != nil { if err != nil {
return err return err
} }
@ -200,7 +199,7 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
} else if options.Short { } else if options.Short {
if quantity.IsZero() { if quantity.IsZero() {
var err error var err error
quantity, err = risk.CalculateBaseQuantity(e.session, e.position.Market, price, quantity, options.Leverage) quantity, err = CalculateBaseQuantity(e.session, e.position.Market, price, quantity, options.Leverage)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,34 +1,30 @@
package risk package bbgo
import ( import (
"context" "context"
"fmt" "fmt"
"time" "time"
"github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/risk"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
var log = logrus.WithField("risk", "AccountValueCalculator")
var one = fixedpoint.One
var defaultLeverage = fixedpoint.NewFromInt(3) var defaultLeverage = fixedpoint.NewFromInt(3)
var maxLeverage = fixedpoint.NewFromInt(10) var maxLeverage = fixedpoint.NewFromInt(10)
type AccountValueCalculator struct { type AccountValueCalculator struct {
session *bbgo.ExchangeSession session *ExchangeSession
quoteCurrency string quoteCurrency string
prices map[string]fixedpoint.Value prices map[string]fixedpoint.Value
tickers map[string]types.Ticker tickers map[string]types.Ticker
updateTime time.Time updateTime time.Time
} }
func NewAccountValueCalculator(session *bbgo.ExchangeSession, quoteCurrency string) *AccountValueCalculator { func NewAccountValueCalculator(session *ExchangeSession, quoteCurrency string) *AccountValueCalculator {
return &AccountValueCalculator{ return &AccountValueCalculator{
session: session, session: session,
quoteCurrency: quoteCurrency, quoteCurrency: quoteCurrency,
@ -190,7 +186,7 @@ func (c *AccountValueCalculator) MarginLevel(ctx context.Context) (fixedpoint.Va
return marginLevel, nil return marginLevel, nil
} }
func CalculateBaseQuantity(session *bbgo.ExchangeSession, market types.Market, price, quantity, leverage fixedpoint.Value) (fixedpoint.Value, error) { func CalculateBaseQuantity(session *ExchangeSession, market types.Market, price, quantity, leverage fixedpoint.Value) (fixedpoint.Value, error) {
// default leverage guard // default leverage guard
if leverage.IsZero() { if leverage.IsZero() {
leverage = defaultLeverage leverage = defaultLeverage
@ -205,7 +201,7 @@ func CalculateBaseQuantity(session *bbgo.ExchangeSession, market types.Market, p
balance, hasBalance := session.Account.Balance(market.BaseCurrency) balance, hasBalance := session.Account.Balance(market.BaseCurrency)
if hasBalance { if hasBalance {
if quantity.IsZero() { if quantity.IsZero() {
logrus.Warnf("sell quantity is not set, using all available base balance: %v", balance) log.Warnf("sell quantity is not set, using all available base balance: %v", balance)
if !balance.Available.IsZero() { if !balance.Available.IsZero() {
return balance.Available, nil return balance.Available, nil
} }
@ -222,7 +218,7 @@ func CalculateBaseQuantity(session *bbgo.ExchangeSession, market types.Market, p
} }
// using leverage -- starts from here // using leverage -- starts from here
logrus.Infof("calculating available leveraged base quantity: base balance = %+v, quote balance = %+v", baseBalance, quoteBalance) log.Infof("calculating available leveraged base quantity: base balance = %+v, quote balance = %+v", baseBalance, quoteBalance)
// calculate the quantity automatically // calculate the quantity automatically
if session.Margin || session.IsolatedMargin { if session.Margin || session.IsolatedMargin {
@ -232,22 +228,22 @@ func CalculateBaseQuantity(session *bbgo.ExchangeSession, market types.Market, p
// avoid using all account value since there will be some trade loss for interests and the fee // avoid using all account value since there will be some trade loss for interests and the fee
accountValue = accountValue.Mul(one.Sub(fixedpoint.NewFromFloat(0.01))) accountValue = accountValue.Mul(one.Sub(fixedpoint.NewFromFloat(0.01)))
logrus.Infof("calculated account value %f %s", accountValue.Float64(), market.QuoteCurrency) log.Infof("calculated account value %f %s", accountValue.Float64(), market.QuoteCurrency)
if session.IsolatedMargin { if session.IsolatedMargin {
originLeverage := leverage originLeverage := leverage
leverage = fixedpoint.Min(leverage, maxLeverage) leverage = fixedpoint.Min(leverage, maxLeverage)
logrus.Infof("using isolated margin, maxLeverage=10 originalLeverage=%f currentLeverage=%f", log.Infof("using isolated margin, maxLeverage=10 originalLeverage=%f currentLeverage=%f",
originLeverage.Float64(), originLeverage.Float64(),
leverage.Float64()) leverage.Float64())
} }
// spot margin use the equity value, so we use the total quote balance here // spot margin use the equity value, so we use the total quote balance here
maxPosition := CalculateMaxPosition(price, accountValue, leverage) maxPosition := risk.CalculateMaxPosition(price, accountValue, leverage)
debt := baseBalance.Debt() debt := baseBalance.Debt()
maxQuantity := maxPosition.Sub(debt) maxQuantity := maxPosition.Sub(debt)
logrus.Infof("margin leverage: calculated maxQuantity=%f maxPosition=%f debt=%f price=%f accountValue=%f %s leverage=%f", log.Infof("margin leverage: calculated maxQuantity=%f maxPosition=%f debt=%f price=%f accountValue=%f %s leverage=%f",
maxQuantity.Float64(), maxQuantity.Float64(),
maxPosition.Float64(), maxPosition.Float64(),
debt.Float64(), debt.Float64(),
@ -261,8 +257,8 @@ func CalculateBaseQuantity(session *bbgo.ExchangeSession, market types.Market, p
if session.Futures || session.IsolatedFutures { if session.Futures || session.IsolatedFutures {
// TODO: get mark price here // TODO: get mark price here
maxPositionQuantity := CalculateMaxPosition(price, quoteBalance.Available, leverage) maxPositionQuantity := risk.CalculateMaxPosition(price, quoteBalance.Available, leverage)
requiredPositionCost := CalculatePositionCost(price, price, maxPositionQuantity, leverage, types.SideTypeSell) requiredPositionCost := risk.CalculatePositionCost(price, price, maxPositionQuantity, leverage, types.SideTypeSell)
if quoteBalance.Available.Compare(requiredPositionCost) < 0 { if quoteBalance.Available.Compare(requiredPositionCost) < 0 {
return maxPositionQuantity, fmt.Errorf("available margin %f %s is not enough, can not submit order", quoteBalance.Available.Float64(), market.QuoteCurrency) return maxPositionQuantity, fmt.Errorf("available margin %f %s is not enough, can not submit order", quoteBalance.Available.Float64(), market.QuoteCurrency)
} }
@ -273,7 +269,7 @@ func CalculateBaseQuantity(session *bbgo.ExchangeSession, market types.Market, p
return quantity, fmt.Errorf("quantity is zero, can not submit sell order, please check your settings") return quantity, fmt.Errorf("quantity is zero, can not submit sell order, please check your settings")
} }
func CalculateQuoteQuantity(ctx context.Context, session *bbgo.ExchangeSession, quoteCurrency string, leverage fixedpoint.Value) (fixedpoint.Value, error) { func CalculateQuoteQuantity(ctx context.Context, session *ExchangeSession, quoteCurrency string, leverage fixedpoint.Value) (fixedpoint.Value, error) {
// default leverage guard // default leverage guard
if leverage.IsZero() { if leverage.IsZero() {
leverage = defaultLeverage leverage = defaultLeverage
@ -294,7 +290,8 @@ func CalculateQuoteQuantity(ctx context.Context, session *bbgo.ExchangeSession,
log.WithError(err).Errorf("can not update available quote") log.WithError(err).Errorf("can not update available quote")
return fixedpoint.Zero, err return fixedpoint.Zero, err
} }
logrus.Infof("calculating available leveraged quote quantity: account available quote = %+v", availableQuote)
log.Infof("calculating available leveraged quote quantity: account available quote = %+v", availableQuote)
return availableQuote.Mul(leverage), nil return availableQuote.Mul(leverage), nil
} }

View File

@ -1,4 +1,4 @@
package risk package bbgo
import ( import (
"context" "context"
@ -8,7 +8,6 @@ import (
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/c9s/bbgo/pkg/bbgo"
"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/c9s/bbgo/pkg/types/mocks" "github.com/c9s/bbgo/pkg/types/mocks"
@ -40,7 +39,7 @@ func TestAccountValueCalculator_NetValue(t *testing.T) {
"BTCUSDT": newTestTicker(), "BTCUSDT": newTestTicker(),
}, nil) }, nil)
session := bbgo.NewExchangeSession("test", mockEx) session := NewExchangeSession("test", mockEx)
session.Account.UpdateBalances(types.BalanceMap{ session.Account.UpdateBalances(types.BalanceMap{
"BTC": { "BTC": {
Currency: "BTC", Currency: "BTC",
@ -81,7 +80,7 @@ func TestAccountValueCalculator_NetValue(t *testing.T) {
"BTCUSDT": newTestTicker(), "BTCUSDT": newTestTicker(),
}, nil) }, nil)
session := bbgo.NewExchangeSession("test", mockEx) session := NewExchangeSession("test", mockEx)
session.Account.UpdateBalances(types.BalanceMap{ session.Account.UpdateBalances(types.BalanceMap{
"BTC": { "BTC": {
Currency: "BTC", Currency: "BTC",
@ -123,7 +122,7 @@ func TestNewAccountValueCalculator_MarginLevel(t *testing.T) {
"BTCUSDT": newTestTicker(), "BTCUSDT": newTestTicker(),
}, nil) }, nil)
session := bbgo.NewExchangeSession("test", mockEx) session := NewExchangeSession("test", mockEx)
session.Account.UpdateBalances(types.BalanceMap{ session.Account.UpdateBalances(types.BalanceMap{
"BTC": { "BTC": {
Currency: "BTC", Currency: "BTC",

View File

@ -6,7 +6,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/indicator"
"github.com/c9s/bbgo/pkg/risk"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
@ -197,7 +196,7 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
// graceful cancel all active orders // graceful cancel all active orders
_ = orderExecutor.GracefulCancel(ctx) _ = orderExecutor.GracefulCancel(ctx)
quantity, err := risk.CalculateBaseQuantity(s.session, s.Market, closePrice, s.Quantity, s.Leverage) quantity, err := bbgo.CalculateBaseQuantity(s.session, s.Market, closePrice, s.Quantity, s.Leverage)
if err != nil { if err != nil {
log.WithError(err).Errorf("quantity calculation error") log.WithError(err).Errorf("quantity calculation error")
} }
@ -241,7 +240,7 @@ func (s *BreakLow) pilotQuantityCalculation() {
s.Quantity.Float64(), s.Quantity.Float64(),
s.Leverage.Float64()) s.Leverage.Float64())
quantity, err := risk.CalculateBaseQuantity(s.session, s.Market, s.lastLow, s.Quantity, s.Leverage) quantity, err := bbgo.CalculateBaseQuantity(s.session, s.Market, s.lastLow, s.Quantity, s.Leverage)
if err != nil { if err != nil {
log.WithError(err).Errorf("quantity calculation error") log.WithError(err).Errorf("quantity calculation error")
} }

View File

@ -6,7 +6,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/indicator"
"github.com/c9s/bbgo/pkg/risk"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
@ -209,7 +208,7 @@ func (s *FailedBreakHigh) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
// graceful cancel all active orders // graceful cancel all active orders
_ = orderExecutor.GracefulCancel(ctx) _ = orderExecutor.GracefulCancel(ctx)
quantity, err := risk.CalculateBaseQuantity(s.session, s.Market, closePrice, s.Quantity, s.Leverage) quantity, err := bbgo.CalculateBaseQuantity(s.session, s.Market, closePrice, s.Quantity, s.Leverage)
if err != nil { if err != nil {
log.WithError(err).Errorf("quantity calculation error") log.WithError(err).Errorf("quantity calculation error")
} }
@ -260,7 +259,7 @@ func (s *FailedBreakHigh) pilotQuantityCalculation() {
s.Quantity.Float64(), s.Quantity.Float64(),
s.Leverage.Float64()) s.Leverage.Float64())
quantity, err := risk.CalculateBaseQuantity(s.session, s.Market, s.lastHigh, s.Quantity, s.Leverage) quantity, err := bbgo.CalculateBaseQuantity(s.session, s.Market, s.lastHigh, s.Quantity, s.Leverage)
if err != nil { if err != nil {
log.WithError(err).Errorf("quantity calculation error") log.WithError(err).Errorf("quantity calculation error")
} }

View File

@ -7,7 +7,6 @@ import (
"github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/datatype/floats"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/indicator"
"github.com/c9s/bbgo/pkg/risk"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
@ -128,7 +127,7 @@ func (s *ResistanceShort) updateResistanceOrders(closePrice fixedpoint.Value) {
} }
func (s *ResistanceShort) placeResistanceOrders(ctx context.Context, resistancePrice fixedpoint.Value) { func (s *ResistanceShort) placeResistanceOrders(ctx context.Context, resistancePrice fixedpoint.Value) {
totalQuantity, err := risk.CalculateBaseQuantity(s.session, s.Market, resistancePrice, s.Quantity, s.Leverage) totalQuantity, err := bbgo.CalculateBaseQuantity(s.session, s.Market, resistancePrice, s.Quantity, s.Leverage)
if err != nil { if err != nil {
log.WithError(err).Errorf("quantity calculation error") log.WithError(err).Errorf("quantity calculation error")
} }

View File

@ -6,13 +6,12 @@ import (
"os" "os"
"sync" "sync"
"github.com/c9s/bbgo/pkg/data/tsv"
"github.com/c9s/bbgo/pkg/datatype/floats"
"github.com/c9s/bbgo/pkg/risk"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/data/tsv"
"github.com/c9s/bbgo/pkg/datatype/floats"
"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/indicator"
@ -173,7 +172,7 @@ type Strategy struct {
Leverage fixedpoint.Value `json:"leverage"` Leverage fixedpoint.Value `json:"leverage"`
// Quantity sets the fixed order qty, takes precedence over Leverage // Quantity sets the fixed order qty, takes precedence over Leverage
Quantity fixedpoint.Value `json:"quantity"` Quantity fixedpoint.Value `json:"quantity"`
AccountValueCalculator *risk.AccountValueCalculator AccountValueCalculator *bbgo.AccountValueCalculator
// TakeProfitAtrMultiplier TP according to ATR multiple, 0 to disable this // TakeProfitAtrMultiplier TP according to ATR multiple, 0 to disable this
TakeProfitAtrMultiplier float64 `json:"takeProfitAtrMultiplier"` TakeProfitAtrMultiplier float64 `json:"takeProfitAtrMultiplier"`
@ -389,7 +388,7 @@ func (s *Strategy) calculateQuantity(ctx context.Context, currentPrice fixedpoin
return balance.Available.Mul(fixedpoint.Min(s.Leverage, fixedpoint.One)) return balance.Available.Mul(fixedpoint.Min(s.Leverage, fixedpoint.One))
} else { // Using leverage or spot buy } else { // Using leverage or spot buy
quoteQty, err := risk.CalculateQuoteQuantity(ctx, s.session, s.Market.QuoteCurrency, s.Leverage) quoteQty, err := bbgo.CalculateQuoteQuantity(ctx, s.session, s.Market.QuoteCurrency, s.Leverage)
if err != nil { if err != nil {
log.WithError(err).Errorf("can not update %s quote balance from exchange", s.Symbol) log.WithError(err).Errorf("can not update %s quote balance from exchange", s.Symbol)
return fixedpoint.Zero return fixedpoint.Zero
@ -449,7 +448,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.orderExecutor.Bind() s.orderExecutor.Bind()
// AccountValueCalculator // AccountValueCalculator
s.AccountValueCalculator = risk.NewAccountValueCalculator(s.session, s.Market.QuoteCurrency) s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, s.Market.QuoteCurrency)
// Accumulated profit report // Accumulated profit report
if bbgo.IsBackTesting { if bbgo.IsBackTesting {