emit klines and setup account balances

This commit is contained in:
c9s 2020-11-07 03:18:05 +08:00
parent 22a214328d
commit b13a2deec5
7 changed files with 84 additions and 36 deletions

View File

@ -58,17 +58,9 @@ backtest:
USDT: 5000.0
exchangeStrategies:
- on: binance
- on: max
buyandhold:
symbol: "BTCUSDT"
interval: "1m"
baseQuantity: 0.01
minDropPercentage: -0.02
- on: max
xpuremaker:
symbol: MAXUSDT
numOrders: 2
side: both
behindVolume: 1000.0
priceTick: 0.01
baseQuantity: 100.0

View File

@ -6,6 +6,7 @@ import (
"github.com/pkg/errors"
"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/exchange/binance"
"github.com/c9s/bbgo/pkg/exchange/max"
"github.com/c9s/bbgo/pkg/service"
@ -18,27 +19,55 @@ type Exchange struct {
srv *service.BacktestService
startTime time.Time
account *types.Account
config *bbgo.Backtest
closedOrders []types.SubmitOrder
openOrders []types.SubmitOrder
stream *Stream
}
func NewExchange(sourceExchange types.ExchangeName, srv *service.BacktestService, startTime time.Time) *Exchange {
func NewExchange(sourceExchange types.ExchangeName, srv *service.BacktestService, config *bbgo.Backtest) *Exchange {
ex, err := newPublicExchange(sourceExchange)
if err != nil {
panic(err)
}
if config == nil {
panic(errors.New("backtest config can not be nil"))
}
startTime, err := config.ParseStartTime()
if err != nil {
panic(err)
}
balances := config.Account.Balances.BalanceMap()
account := &types.Account{
MakerCommission: config.Account.MakerCommission,
TakerCommission: config.Account.TakerCommission,
AccountType: "SPOT", // currently not used
}
account.UpdateBalances(balances)
return &Exchange{
sourceExchange: sourceExchange,
publicExchange: ex,
srv: srv,
config: config,
account: account,
startTime: startTime,
}
}
func (e *Exchange) NewStream() types.Stream {
// TODO: return the stream and feed the data
return &Stream{}
if e.stream != nil {
panic("backtest stream is already allocated, please check if there are extra NewStream calls")
}
e.stream = &Stream{exchange: e}
return e.stream
}
func (e Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error) {
@ -58,11 +87,11 @@ func (e Exchange) CancelOrders(ctx context.Context, orders ...types.Order) error
}
func (e Exchange) QueryAccount(ctx context.Context) (*types.Account, error) {
panic("implement me")
return e.account, nil
}
func (e Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap, error) {
panic("implement me")
func (e *Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap, error) {
return e.account.Balances(), nil
}
func (e Exchange) QueryKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error) {

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/types"
)
@ -15,6 +16,8 @@ type Stream struct {
}
func (s *Stream) Connect(ctx context.Context) error {
log.Infof("collecting backtest configurations...")
loadedSymbols := map[string]struct{}{}
loadedIntervals := map[types.Interval]struct{}{}
for _, sub := range s.Subscriptions {
@ -39,6 +42,8 @@ func (s *Stream) Connect(ctx context.Context) error {
intervals = append(intervals, interval)
}
log.Infof("used symbols: %v and intervals: %v", symbols, intervals)
// TODO: we can sync before we connect
/*
if err := backtestService.Sync(ctx, exchange, symbol, startTime); err != nil {

View File

@ -4,11 +4,13 @@ import (
"encoding/json"
"io/ioutil"
"reflect"
"time"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
type PnLReporterConfig struct {
@ -57,6 +59,14 @@ type Backtest struct {
Account BacktestAccount `json:"account" yaml:"account"`
}
func (t Backtest) ParseStartTime() (time.Time, error) {
if len(t.StartTime) == 0 {
return time.Time{}, errors.New("backtest.startTime must be defined")
}
return time.Parse("2006-01-02", t.StartTime)
}
type BacktestAccount struct {
MakerCommission int `json:"makerCommission"`
TakerCommission int `json:"takerCommission"`
@ -67,6 +77,18 @@ type BacktestAccount struct {
type BacktestAccountBalanceMap map[string]fixedpoint.Value
func (m BacktestAccountBalanceMap) BalanceMap() types.BalanceMap {
balances := make(types.BalanceMap)
for currency, value := range m {
balances[currency] = types.Balance{
Currency: currency,
Available: value.Float64(),
Locked: 0.0,
}
}
return balances
}
type Config struct {
Imports []string `json:"imports" yaml:"imports"`

View File

@ -18,8 +18,7 @@ import (
func init() {
BacktestCmd.Flags().String("exchange", "", "target exchange")
BacktestCmd.Flags().String("start", "", "start time")
BacktestCmd.Flags().Bool("backtest", true, "sync backtest data")
BacktestCmd.Flags().Bool("sync", true, "sync backtest data")
BacktestCmd.Flags().String("config", "config/bbgo.yaml", "strategy config file")
RootCmd.AddCommand(BacktestCmd)
}
@ -61,27 +60,29 @@ var BacktestCmd = &cobra.Command{
return err
}
// set default start time to the past 6 months
startTime := time.Now().AddDate(0, -6, 0)
startTimeArg, err := cmd.Flags().GetString("start")
if err != nil {
return err
if userConfig.Backtest == nil {
return errors.New("backtest config is not defined")
}
if len(startTimeArg) > 0 {
startTime, err = time.Parse("2006-01-02", startTimeArg)
if err != nil {
return err
}
// set default start time to the past 6 months
startTime := time.Now().AddDate(0, -6, 0)
if len(userConfig.Backtest.StartTime) == 0 {
userConfig.Backtest.StartTime = startTime.Format("2006-01-02")
}
backtestService := &service.BacktestService{DB: db}
exchange := backtest.NewExchange(exchangeName, backtestService, startTime)
exchange := backtest.NewExchange(exchangeName, backtestService, userConfig.Backtest)
environ := bbgo.NewEnvironment()
environ.AddExchange(exchangeName.String(), exchange)
environ.Notifiability = bbgo.Notifiability{
SymbolChannelRouter: bbgo.NewPatternChannelRouter(nil),
SessionChannelRouter: bbgo.NewPatternChannelRouter(nil),
ObjectChannelRouter: bbgo.NewObjectChannelRouter(),
}
trader := bbgo.NewTrader(environ)
if userConfig.RiskControls != nil {
trader.SetRiskControls(userConfig.RiskControls)
@ -96,7 +97,7 @@ var BacktestCmd = &cobra.Command{
log.Warnf("backtest does not support CrossExchangeStrategy, strategies won't be added.")
}
if err := trader.Run(ctx) ; err != nil {
if err := trader.Run(ctx); err != nil {
return err
}

View File

@ -262,8 +262,8 @@ func (e *Exchange) QueryAccount(ctx context.Context) (*types.Account, error) {
}
a := &types.Account{
MakerCommission: account.MakerCommission,
TakerCommission: account.TakerCommission,
MakerCommission: int(account.MakerCommission),
TakerCommission: int(account.TakerCommission),
}
a.UpdateBalances(balances)
return a, nil
@ -537,4 +537,3 @@ func (e *Exchange) BatchQueryKLines(ctx context.Context, symbol string, interval
return allKLines, nil
}

View File

@ -19,9 +19,9 @@ type BalanceMap map[string]Balance
type Account struct {
sync.Mutex
MakerCommission int64
TakerCommission int64
AccountType string
MakerCommission int `json:"makerCommission"`
TakerCommission int `json:"takerCommission"`
AccountType string `json:"accountType"`
balances BalanceMap
}