support balance load and update

This commit is contained in:
c9s 2020-07-14 00:20:15 +08:00
parent 762f965130
commit ef622b0c7c
2 changed files with 68 additions and 27 deletions

View File

@ -1,8 +1,13 @@
package bbgo package bbgo
import "github.com/c9s/bbgo/pkg/bbgo/types" import (
"github.com/c9s/bbgo/pkg/bbgo/types"
"sync"
)
type TradingContext struct { type TradingContext struct {
sync.Mutex
Symbol string Symbol string
// Market is the market configuration of a symbol // Market is the market configuration of a symbol
@ -11,6 +16,7 @@ type TradingContext struct {
AverageBidPrice float64 AverageBidPrice float64
CurrentPrice float64 CurrentPrice float64
Balances map[string]types.Balance
ProfitAndLossCalculator *ProfitAndLossCalculator ProfitAndLossCalculator *ProfitAndLossCalculator
} }

View File

@ -2,6 +2,7 @@ package bbgo
import ( import (
"context" "context"
"github.com/c9s/bbgo/pkg/util"
"time" "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -23,23 +24,35 @@ type Trader struct {
type Strategy interface { type Strategy interface {
Init(trader *Trader, stream *binance.PrivateStream) error Init(trader *Trader) error
OnNewStream(stream *binance.PrivateStream) error
} }
func (t *Trader) RunStrategy(ctx context.Context, strategy Strategy) (chan struct{}, error) { func (trader *Trader) RunStrategy(ctx context.Context, strategy Strategy) (chan struct{}, error) {
symbol := t.Context.Symbol symbol := trader.Context.Symbol
stream, err := t.Exchange.NewPrivateStream() balances, err := trader.Exchange.QueryAccountBalances(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := strategy.Init(t, stream); err != nil { trader.Context.Balances = balances
if err := strategy.Init(trader) ; err != nil {
return nil, err return nil, err
} }
t.reportTimer = time.AfterFunc(1*time.Second, func() { stream, err := trader.Exchange.NewPrivateStream()
t.ReportPnL() if err != nil {
return nil, err
}
if err := strategy.OnNewStream(stream); err != nil {
return nil, err
}
trader.reportTimer = time.AfterFunc(1*time.Second, func() {
trader.ReportPnL()
}) })
stream.OnTrade(func(trade *types.Trade) { stream.OnTrade(func(trade *types.Trade) {
@ -47,20 +60,46 @@ func (t *Trader) RunStrategy(ctx context.Context, strategy Strategy) (chan struc
return return
} }
t.ReportTrade(trade) trader.ReportTrade(trade)
t.Context.ProfitAndLossCalculator.AddTrade(*trade) trader.Context.ProfitAndLossCalculator.AddTrade(*trade)
if t.reportTimer != nil { if trader.reportTimer != nil {
t.reportTimer.Stop() trader.reportTimer.Stop()
} }
t.reportTimer = time.AfterFunc(5*time.Second, func() { trader.reportTimer = time.AfterFunc(5*time.Second, func() {
t.ReportPnL() trader.ReportPnL()
}) })
}) })
stream.OnKLineEvent(func(e *binance.KLineEvent) { stream.OnKLineEvent(func(e *binance.KLineEvent) {
t.Context.SetCurrentPrice(e.KLine.GetClose()) trader.Context.SetCurrentPrice(e.KLine.GetClose())
})
stream.OnOutboundAccountInfoEvent(func(e *binance.OutboundAccountInfoEvent) {
trader.Context.Lock()
defer trader.Context.Unlock()
for _, balance := range e.Balances {
available := util.MustParseFloat(balance.Free)
locked := util.MustParseFloat(balance.Locked)
trader.Context.Balances[balance.Asset] = types.Balance{
Currency: balance.Asset,
Available: available,
Locked: locked,
}
}
})
stream.OnBalanceUpdateEvent(func(e *binance.BalanceUpdateEvent) {
trader.Context.Lock()
defer trader.Context.Unlock()
delta := util.MustParseFloat(e.Delta)
if balance, ok := trader.Context.Balances[e.Asset] ; ok {
balance.Available += delta
trader.Context.Balances[e.Asset] = balance
}
}) })
var eventC = make(chan interface{}, 20) var eventC = make(chan interface{}, 20)
@ -90,24 +129,20 @@ func (t *Trader) RunStrategy(ctx context.Context, strategy Strategy) (chan struc
return done, nil return done, nil
} }
func (t *Trader) Infof(format string, args ...interface{}) { func (trader *Trader) ReportTrade(trade *types.Trade) {
t.Notifier.Notify(format, args...) trader.Notifier.ReportTrade(trade)
} }
func (t *Trader) ReportTrade(trade *types.Trade) { func (trader *Trader) ReportPnL() {
t.Notifier.ReportTrade(trade) report := trader.Context.ProfitAndLossCalculator.Calculate()
}
func (t *Trader) ReportPnL() {
report := t.Context.ProfitAndLossCalculator.Calculate()
report.Print() report.Print()
t.Notifier.ReportPnL(report) trader.Notifier.ReportPnL(report)
} }
func (t *Trader) SubmitOrder(ctx context.Context, order *types.Order) { func (trader *Trader) SubmitOrder(ctx context.Context, order *types.Order) {
t.Notifier.Notify(":memo: Submitting %s order on side %s with volume: %s", order.Type, order.Side, order.VolumeStr, order.SlackAttachment()) trader.Notifier.Notify(":memo: Submitting %s order on side %s with volume: %s", order.Type, order.Side, order.VolumeStr, order.SlackAttachment())
err := t.Exchange.SubmitOrder(ctx, order) err := trader.Exchange.SubmitOrder(ctx, order)
if err != nil { if err != nil {
log.WithError(err).Errorf("order create error: side %s volume: %s", order.Side, order.VolumeStr) log.WithError(err).Errorf("order create error: side %s volume: %s", order.Side, order.VolumeStr)
return return