mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 16:55:15 +00:00
Merge pull request #827 from c9s/strategy/pivotshort
strategy/pivotshort: improve quantity calculation for margin and futures
This commit is contained in:
commit
191e00adeb
29
pkg/exchange/util.go
Normal file
29
pkg/exchange/util.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package exchange
|
||||||
|
|
||||||
|
import "github.com/c9s/bbgo/pkg/types"
|
||||||
|
|
||||||
|
func GetSessionAttributes(exchange types.Exchange) (isMargin, isFutures, isIsolated bool, isolatedSymbol string) {
|
||||||
|
if marginExchange, ok := exchange.(types.MarginExchange); ok {
|
||||||
|
marginSettings := marginExchange.GetMarginSettings()
|
||||||
|
isMargin = marginSettings.IsMargin
|
||||||
|
if isMargin {
|
||||||
|
isIsolated = marginSettings.IsIsolatedMargin
|
||||||
|
if marginSettings.IsIsolatedMargin {
|
||||||
|
isolatedSymbol = marginSettings.IsolatedMarginSymbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if futuresExchange, ok := exchange.(types.FuturesExchange); ok {
|
||||||
|
futuresSettings := futuresExchange.GetFuturesSettings()
|
||||||
|
isFutures = futuresSettings.IsFutures
|
||||||
|
if isFutures {
|
||||||
|
isIsolated = futuresSettings.IsIsolatedFutures
|
||||||
|
if futuresSettings.IsIsolatedFutures {
|
||||||
|
isolatedSymbol = futuresSettings.IsolatedFuturesSymbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isMargin, isFutures, isIsolated, isolatedSymbol
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
exchange2 "github.com/c9s/bbgo/pkg/exchange"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/batch"
|
"github.com/c9s/bbgo/pkg/exchange/batch"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -25,7 +26,7 @@ func (s *BacktestService) SyncKLineByInterval(ctx context.Context, exchange type
|
||||||
log.Infof("synchronizing %s klines with interval %s: %s <=> %s", exchange.Name(), interval, startTime, endTime)
|
log.Infof("synchronizing %s klines with interval %s: %s <=> %s", exchange.Name(), interval, startTime, endTime)
|
||||||
|
|
||||||
// TODO: use isFutures here
|
// TODO: use isFutures here
|
||||||
_, _, isIsolated, isolatedSymbol := getExchangeAttributes(exchange)
|
_, _, isIsolated, isolatedSymbol := exchange2.GetSessionAttributes(exchange)
|
||||||
// override symbol if isolatedSymbol is not empty
|
// override symbol if isolatedSymbol is not empty
|
||||||
if isIsolated && len(isolatedSymbol) > 0 {
|
if isIsolated && len(isolatedSymbol) > 0 {
|
||||||
symbol = isolatedSymbol
|
symbol = isolatedSymbol
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/exchange"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/batch"
|
"github.com/c9s/bbgo/pkg/exchange/batch"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -17,7 +18,7 @@ type DepositService struct {
|
||||||
|
|
||||||
// Sync syncs the withdraw records into db
|
// Sync syncs the withdraw records into db
|
||||||
func (s *DepositService) Sync(ctx context.Context, ex types.Exchange, startTime time.Time) error {
|
func (s *DepositService) Sync(ctx context.Context, ex types.Exchange, startTime time.Time) error {
|
||||||
isMargin, isFutures, isIsolated, _ := getExchangeAttributes(ex)
|
isMargin, isFutures, isIsolated, _ := exchange.GetSessionAttributes(ex)
|
||||||
if isMargin || isFutures || isIsolated {
|
if isMargin || isFutures || isIsolated {
|
||||||
// only works in spot
|
// only works in spot
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
exchange2 "github.com/c9s/bbgo/pkg/exchange"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/batch"
|
"github.com/c9s/bbgo/pkg/exchange/batch"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -19,7 +20,7 @@ type OrderService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol string, startTime time.Time) error {
|
func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol string, startTime time.Time) error {
|
||||||
isMargin, isFutures, isIsolated, isolatedSymbol := getExchangeAttributes(exchange)
|
isMargin, isFutures, isIsolated, isolatedSymbol := exchange2.GetSessionAttributes(exchange)
|
||||||
// override symbol if isolatedSymbol is not empty
|
// override symbol if isolatedSymbol is not empty
|
||||||
if isIsolated && len(isolatedSymbol) > 0 {
|
if isIsolated && len(isolatedSymbol) > 0 {
|
||||||
symbol = isolatedSymbol
|
symbol = isolatedSymbol
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
exchange2 "github.com/c9s/bbgo/pkg/exchange"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/batch"
|
"github.com/c9s/bbgo/pkg/exchange/batch"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -29,7 +30,7 @@ func (s *RewardService) Sync(ctx context.Context, exchange types.Exchange, start
|
||||||
return ErrExchangeRewardServiceNotImplemented
|
return ErrExchangeRewardServiceNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
isMargin, isFutures, _, _ := getExchangeAttributes(exchange)
|
isMargin, isFutures, _, _ := exchange2.GetSessionAttributes(exchange)
|
||||||
if isMargin || isFutures {
|
if isMargin || isFutures {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
exchange2 "github.com/c9s/bbgo/pkg/exchange"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/batch"
|
"github.com/c9s/bbgo/pkg/exchange/batch"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -53,7 +54,7 @@ func NewTradeService(db *sqlx.DB) *TradeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TradeService) Sync(ctx context.Context, exchange types.Exchange, symbol string, startTime time.Time) error {
|
func (s *TradeService) Sync(ctx context.Context, exchange types.Exchange, symbol string, startTime time.Time) error {
|
||||||
isMargin, isFutures, isIsolated, isolatedSymbol := getExchangeAttributes(exchange)
|
isMargin, isFutures, isIsolated, isolatedSymbol := exchange2.GetSessionAttributes(exchange)
|
||||||
// override symbol if isolatedSymbol is not empty
|
// override symbol if isolatedSymbol is not empty
|
||||||
if isIsolated && len(isolatedSymbol) > 0 {
|
if isIsolated && len(isolatedSymbol) > 0 {
|
||||||
symbol = isolatedSymbol
|
symbol = isolatedSymbol
|
||||||
|
@ -412,28 +413,3 @@ func SelectLastTrades(ex types.ExchangeName, symbol string, isMargin, isFutures,
|
||||||
Limit(limit)
|
Limit(limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExchangeAttributes(exchange types.Exchange) (isMargin, isFutures, isIsolated bool, isolatedSymbol string) {
|
|
||||||
if marginExchange, ok := exchange.(types.MarginExchange); ok {
|
|
||||||
marginSettings := marginExchange.GetMarginSettings()
|
|
||||||
isMargin = marginSettings.IsMargin
|
|
||||||
if isMargin {
|
|
||||||
isIsolated = marginSettings.IsIsolatedMargin
|
|
||||||
if marginSettings.IsIsolatedMargin {
|
|
||||||
isolatedSymbol = marginSettings.IsolatedMarginSymbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if futuresExchange, ok := exchange.(types.FuturesExchange); ok {
|
|
||||||
futuresSettings := futuresExchange.GetFuturesSettings()
|
|
||||||
isFutures = futuresSettings.IsFutures
|
|
||||||
if isFutures {
|
|
||||||
isIsolated = futuresSettings.IsIsolatedFutures
|
|
||||||
if futuresSettings.IsIsolatedFutures {
|
|
||||||
isolatedSymbol = futuresSettings.IsolatedFuturesSymbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return isMargin, isFutures, isIsolated, isolatedSymbol
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/exchange"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/batch"
|
"github.com/c9s/bbgo/pkg/exchange/batch"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -17,7 +18,7 @@ type WithdrawService struct {
|
||||||
|
|
||||||
// Sync syncs the withdrawal records into db
|
// Sync syncs the withdrawal records into db
|
||||||
func (s *WithdrawService) Sync(ctx context.Context, ex types.Exchange, startTime time.Time) error {
|
func (s *WithdrawService) Sync(ctx context.Context, ex types.Exchange, startTime time.Time) error {
|
||||||
isMargin, isFutures, isIsolated, _ := getExchangeAttributes(ex)
|
isMargin, isFutures, isIsolated, _ := exchange.GetSessionAttributes(ex)
|
||||||
if isMargin || isFutures || isIsolated {
|
if isMargin || isFutures || isIsolated {
|
||||||
// only works in spot
|
// only works in spot
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -2,10 +2,12 @@ package pivotshort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,6 +27,7 @@ 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"`
|
||||||
Quantity fixedpoint.Value `json:"quantity"`
|
Quantity fixedpoint.Value `json:"quantity"`
|
||||||
StopEMARange fixedpoint.Value `json:"stopEMARange"`
|
StopEMARange fixedpoint.Value `json:"stopEMARange"`
|
||||||
StopEMA *types.IntervalWindow `json:"stopEMA"`
|
StopEMA *types.IntervalWindow `json:"stopEMA"`
|
||||||
|
@ -63,8 +66,8 @@ 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(symbol)
|
store, _ := session.MarketDataStore(s.Symbol)
|
||||||
standardIndicator, _ := session.StandardIndicatorSet(symbol)
|
standardIndicator, _ := session.StandardIndicatorSet(s.Symbol)
|
||||||
|
|
||||||
s.lastLow = fixedpoint.Zero
|
s.lastLow = fixedpoint.Zero
|
||||||
|
|
||||||
|
@ -168,7 +171,15 @@ 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 := s.useQuantityOrBaseBalance(s.Quantity)
|
quantity, err := useQuantityOrBaseBalance(s.session, s.Market, closePrice, s.Quantity, s.Leverage)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("quantity calculation error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if quantity.IsZero() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if s.MarketOrder {
|
if s.MarketOrder {
|
||||||
bbgo.Notify("%s price %f breaks the previous low %f with ratio %f, submitting market sell to open a short position", symbol, kline.Close.Float64(), previousLow.Float64(), s.Ratio.Float64())
|
bbgo.Notify("%s price %f breaks the previous low %f with ratio %f, submitting market sell to open a short position", symbol, kline.Close.Float64(), previousLow.Float64(), s.Ratio.Float64())
|
||||||
_, _ = s.orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
_, _ = s.orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
||||||
|
@ -204,24 +215,70 @@ func (s *BreakLow) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Gener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BreakLow) useQuantityOrBaseBalance(quantity fixedpoint.Value) fixedpoint.Value {
|
func useQuantityOrBaseBalance(session *bbgo.ExchangeSession, market types.Market, price, quantity, leverage fixedpoint.Value) (fixedpoint.Value, error) {
|
||||||
if s.session.Margin || s.session.IsolatedMargin || s.session.Futures || s.session.IsolatedFutures {
|
usingLeverage := session.Margin || session.IsolatedMargin || session.Futures || session.IsolatedFutures
|
||||||
return quantity
|
if usingLeverage {
|
||||||
|
if !quantity.IsZero() {
|
||||||
|
return quantity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if leverage.IsZero() {
|
||||||
|
leverage = fixedpoint.NewFromInt(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// quantity is zero, we need to calculate the quantity
|
||||||
|
baseBalance, _ := session.Account.Balance(market.BaseCurrency)
|
||||||
|
quoteBalance, _ := session.Account.Balance(market.QuoteCurrency)
|
||||||
|
|
||||||
|
// calculate the quantity automatically
|
||||||
|
if session.Margin || session.IsolatedMargin {
|
||||||
|
baseBalanceValue := baseBalance.Total().Mul(price)
|
||||||
|
accountValue := baseBalanceValue.Add(quoteBalance.Total())
|
||||||
|
|
||||||
|
if session.IsolatedMargin {
|
||||||
|
originLeverage := leverage
|
||||||
|
leverage = fixedpoint.Max(leverage, fixedpoint.NewFromInt(10))
|
||||||
|
log.Infof("using isolated margin, maxLeverage=10 originalLeverage=%f currentLeverage=%f",
|
||||||
|
originLeverage.Float64(),
|
||||||
|
leverage.Float64())
|
||||||
|
}
|
||||||
|
|
||||||
|
// spot margin use the equity value, so we use the total quote balance here
|
||||||
|
maxPositionQuantity := risk.CalculateMaxPosition(price, accountValue, leverage)
|
||||||
|
|
||||||
|
log.Infof("margin leverage: calculated maxPositionQuantity=%f price=%f accountValue=%f %s leverage=%f",
|
||||||
|
maxPositionQuantity.Float64(),
|
||||||
|
price.Float64(),
|
||||||
|
accountValue.Float64(),
|
||||||
|
market.QuoteCurrency,
|
||||||
|
leverage.Float64())
|
||||||
|
|
||||||
|
return maxPositionQuantity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if session.Futures || session.IsolatedFutures {
|
||||||
|
// TODO: get mark price here
|
||||||
|
maxPositionQuantity := risk.CalculateMaxPosition(price, quoteBalance.Available, leverage)
|
||||||
|
requiredPositionCost := risk.CalculatePositionCost(price, price, maxPositionQuantity, leverage, types.SideTypeSell)
|
||||||
|
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, nil
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
balance, hasBalance := s.session.Account.Balance(s.Market.BaseCurrency)
|
// For spot, we simply sell the base currency
|
||||||
|
balance, hasBalance := session.Account.Balance(market.BaseCurrency)
|
||||||
if hasBalance {
|
if hasBalance {
|
||||||
if quantity.IsZero() {
|
if quantity.IsZero() {
|
||||||
bbgo.Notify("sell quantity is not set, submitting sell with all base balance: %s", balance.Available.String())
|
log.Warnf("sell quantity is not set, submitting sell with all base balance: %s", balance.Available.String())
|
||||||
quantity = balance.Available
|
quantity = balance.Available
|
||||||
} else {
|
} else {
|
||||||
quantity = fixedpoint.Min(quantity, balance.Available)
|
quantity = fixedpoint.Min(quantity, balance.Available)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if quantity.IsZero() {
|
return quantity, fmt.Errorf("quantity is zero, can not submit sell order, please check your settings")
|
||||||
log.Errorf("quantity is zero, can not submit sell order, please check settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
return quantity
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,10 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
|
||||||
s.session = session
|
s.session = session
|
||||||
s.orderExecutor = orderExecutor
|
s.orderExecutor = orderExecutor
|
||||||
s.activeOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
s.activeOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
||||||
|
s.activeOrders.OnFilled(func(o types.Order) {
|
||||||
|
// reset resistance price
|
||||||
|
s.currentResistancePrice = fixedpoint.Zero
|
||||||
|
})
|
||||||
s.activeOrders.BindStream(session.UserDataStream)
|
s.activeOrders.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
if s.GroupDistance.IsZero() {
|
if s.GroupDistance.IsZero() {
|
||||||
|
@ -112,7 +116,10 @@ func (s *ResistanceShort) updateResistanceOrders(closePrice fixedpoint.Value) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
resistanceUpdated := s.updateCurrentResistancePrice(closePrice)
|
resistanceUpdated := s.updateCurrentResistancePrice(closePrice)
|
||||||
if resistanceUpdated {
|
if resistanceUpdated {
|
||||||
bbgo.Notify("%s Found next resistance price at %f, updating resistance order...", s.Symbol, s.currentResistancePrice.Float64())
|
bbgo.Notify("Found next %s resistance price at %f, updating resistance orders...", s.Symbol, s.currentResistancePrice.Float64())
|
||||||
|
s.placeResistanceOrders(ctx, s.currentResistancePrice)
|
||||||
|
} else if s.activeOrders.NumOfOrders() == 0 && !s.currentResistancePrice.IsZero() {
|
||||||
|
bbgo.Notify("There is no %s resistance open order, re-placing resistance orders at %f...", s.Symbol, s.currentResistancePrice.Float64())
|
||||||
s.placeResistanceOrders(ctx, s.currentResistancePrice)
|
s.placeResistanceOrders(ctx, s.currentResistancePrice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,11 @@ type Strategy struct {
|
||||||
// pivot interval and window
|
// pivot interval and window
|
||||||
types.IntervalWindow
|
types.IntervalWindow
|
||||||
|
|
||||||
|
Leverage fixedpoint.Value `json:"leverage"`
|
||||||
|
Quantity fixedpoint.Value `json:"quantity"`
|
||||||
|
|
||||||
// persistence fields
|
// persistence fields
|
||||||
|
|
||||||
Position *types.Position `persistence:"position"`
|
Position *types.Position `persistence:"position"`
|
||||||
ProfitStats *types.ProfitStats `persistence:"profit_stats"`
|
ProfitStats *types.ProfitStats `persistence:"profit_stats"`
|
||||||
TradeStats *types.TradeStats `persistence:"trade_stats"`
|
TradeStats *types.TradeStats `persistence:"trade_stats"`
|
||||||
|
@ -177,7 +181,6 @@ type Strategy struct {
|
||||||
bbgo.StrategyController
|
bbgo.StrategyController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *Strategy) ID() string {
|
func (s *Strategy) ID() string {
|
||||||
return ID
|
return ID
|
||||||
}
|
}
|
||||||
|
@ -236,6 +239,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.TradeStats = types.NewTradeStats(s.Symbol)
|
s.TradeStats = types.NewTradeStats(s.Symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.Leverage.IsZero() {
|
||||||
|
// the default leverage is 3x
|
||||||
|
s.Leverage = fixedpoint.NewFromInt(3)
|
||||||
|
}
|
||||||
|
|
||||||
// StrategyController
|
// StrategyController
|
||||||
s.Status = types.StrategyStatusRunning
|
s.Status = types.StrategyStatusRunning
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user