Skip to content

Commit

Permalink
release candidate csvsource backtest
Browse files Browse the repository at this point in the history
  • Loading branch information
go-dockly authored and c9s committed Dec 14, 2023
1 parent 671f9d4 commit eba3074
Show file tree
Hide file tree
Showing 45 changed files with 2,356 additions and 463 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*.out

.idea
.vscode

# Dependency directories (remove the comment below to include it)
# vendor/
Expand Down Expand Up @@ -48,6 +49,7 @@ testoutput

*.swp
/pkg/backtest/assets.go
/data/backtest

coverage.txt
coverage_dum.txt
Expand Down
20 changes: 16 additions & 4 deletions doc/topics/back-testing.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
## Back-testing

*Before you start back-testing, you need to setup [MySQL](../../README.md#configure-mysql-database) or [SQLite3
Currently bbgo supports two ways to run backtests:

1: Through csv data source (supported right now are binance, bybit and OkEx)

2: Alternatively run backtests through [MySQL](../../README.md#configure-mysql-database) or [SQLite3
](../../README.md#configure-sqlite3-database). Using MySQL is highly recommended.*

First, you need to add the back-testing config to your `bbgo.yaml`:
Let's start by adding the back-testing section to your config eg: `bbgo.yaml`:

```yaml
backtest:
Expand Down Expand Up @@ -41,8 +45,11 @@ Note on date formats, the following date formats are supported:
* RFC822, which looks like `02 Jan 06 15:04 MST`
* You can also use `2021-11-26T15:04:56`

And then, you can sync remote exchange k-lines (candle bars) data for back-testing:

And then, you can sync remote exchange k-lines (candle bars) data for back-testing through csv data source:
```sh
bbgo backtest -v --csv --verify --config config/grid.yaml
```
or use the sql data source like so:
```sh
bbgo backtest -v --sync --config config/grid.yaml
```
Expand All @@ -67,6 +74,11 @@ Run back-test:
```sh
bbgo backtest --base-asset-baseline --config config/grid.yaml
```
or through csv data source

```sh
bbgo backtest -v --csv --base-asset-baseline --config config/grid.yaml --output data/backtest
```

If you're developing a strategy, you might want to start with a command like this:

Expand Down
7 changes: 4 additions & 3 deletions pkg/backtest/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var ErrEmptyOrderType = errors.New("order type can not be empty string")
type Exchange struct {
sourceName types.ExchangeName
publicExchange types.Exchange
srv *service.BacktestService
srv service.BackTestable
currentTime time.Time

account *types.Account
Expand All @@ -78,7 +78,7 @@ type Exchange struct {
}

func NewExchange(
sourceName types.ExchangeName, sourceExchange types.Exchange, srv *service.BacktestService, config *bbgo.Backtest,
sourceName types.ExchangeName, sourceExchange types.Exchange, srv service.BackTestable, config *bbgo.Backtest,
) (*Exchange, error) {
ex := sourceExchange

Expand Down Expand Up @@ -366,6 +366,7 @@ func (e *Exchange) SubscribeMarketData(
loadedIntervals[sub.Options.Interval] = struct{}{}

default:
// todo support stream back test with csv tick source
// Since Environment is not yet been injected at this point, no hard error
log.Errorf("stream channel %s is not supported in backtest", sub.Channel)
}
Expand All @@ -375,12 +376,12 @@ func (e *Exchange) SubscribeMarketData(
for symbol := range loadedSymbols {
symbols = append(symbols, symbol)
}
symbols = append(symbols, "FXSUSDT")

var intervals []types.Interval
for interval := range loadedIntervals {
intervals = append(intervals, interval)
}

log.Infof("querying klines from database with exchange: %v symbols: %v and intervals: %v for back-testing", e.Name(), symbols, intervals)
if len(symbols) == 0 {
log.Warnf("empty symbols, will not query kline data from the database")
Expand Down
58 changes: 15 additions & 43 deletions pkg/backtest/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,49 +68,21 @@ func ReadSummaryReport(filename string) (*SummaryReport, error) {
// SessionSymbolReport is the report per exchange session
// trades are merged, collected and re-calculated
type SessionSymbolReport struct {
Exchange types.ExchangeName `json:"exchange"`
Symbol string `json:"symbol,omitempty"`
Intervals []types.Interval `json:"intervals,omitempty"`
Subscriptions []types.Subscription `json:"subscriptions"`
Market types.Market `json:"market"`
LastPrice fixedpoint.Value `json:"lastPrice,omitempty"`
StartPrice fixedpoint.Value `json:"startPrice,omitempty"`
PnL *pnl.AverageCostPnLReport `json:"pnl,omitempty"`
InitialBalances types.BalanceMap `json:"initialBalances,omitempty"`
FinalBalances types.BalanceMap `json:"finalBalances,omitempty"`
Manifests Manifests `json:"manifests,omitempty"`
TradeCount fixedpoint.Value `json:"tradeCount,omitempty"`
RoundTurnCount fixedpoint.Value `json:"roundTurnCount,omitempty"`
TotalNetProfit fixedpoint.Value `json:"totalNetProfit,omitempty"`
AvgNetProfit fixedpoint.Value `json:"avgNetProfit,omitempty"`
GrossProfit fixedpoint.Value `json:"grossProfit,omitempty"`
GrossLoss fixedpoint.Value `json:"grossLoss,omitempty"`
PRR fixedpoint.Value `json:"prr,omitempty"`
PercentProfitable fixedpoint.Value `json:"percentProfitable,omitempty"`
MaxDrawdown fixedpoint.Value `json:"maxDrawdown,omitempty"`
AverageDrawdown fixedpoint.Value `json:"avgDrawdown,omitempty"`
MaxProfit fixedpoint.Value `json:"maxProfit,omitempty"`
MaxLoss fixedpoint.Value `json:"maxLoss,omitempty"`
AvgProfit fixedpoint.Value `json:"avgProfit,omitempty"`
AvgLoss fixedpoint.Value `json:"avgLoss,omitempty"`
TotalTimeInMarketSec int64 `json:"totalTimeInMarketSec,omitempty"`
AvgHoldSec int64 `json:"avgHoldSec,omitempty"`
WinningCount int `json:"winningCount,omitempty"`
LosingCount int `json:"losingCount,omitempty"`
MaxLossStreak int `json:"maxLossStreak,omitempty"`
Sharpe fixedpoint.Value `json:"sharpeRatio"`
AnnualHistoricVolatility fixedpoint.Value `json:"annualHistoricVolatility,omitempty"`
CAGR fixedpoint.Value `json:"cagr,omitempty"`
Calmar fixedpoint.Value `json:"calmar,omitempty"`
Sterling fixedpoint.Value `json:"sterling,omitempty"`
Burke fixedpoint.Value `json:"burke,omitempty"`
Kelly fixedpoint.Value `json:"kelly,omitempty"`
OptimalF fixedpoint.Value `json:"optimalF,omitempty"`
StatN fixedpoint.Value `json:"statN,omitempty"`
StdErr fixedpoint.Value `json:"statNStdErr,omitempty"`
Sortino fixedpoint.Value `json:"sortinoRatio"`
ProfitFactor fixedpoint.Value `json:"profitFactor"`
WinningRatio fixedpoint.Value `json:"winningRatio"`
Exchange types.ExchangeName `json:"exchange"`
Symbol string `json:"symbol,omitempty"`
Intervals []types.Interval `json:"intervals,omitempty"`
Subscriptions []types.Subscription `json:"subscriptions"`
Market types.Market `json:"market"`
LastPrice fixedpoint.Value `json:"lastPrice,omitempty"`
StartPrice fixedpoint.Value `json:"startPrice,omitempty"`
PnL *pnl.AverageCostPnLReport `json:"pnl,omitempty"`
InitialBalances types.BalanceMap `json:"initialBalances,omitempty"`
FinalBalances types.BalanceMap `json:"finalBalances,omitempty"`
Manifests Manifests `json:"manifests,omitempty"`
Sharpe fixedpoint.Value `json:"sharpeRatio"`
Sortino fixedpoint.Value `json:"sortinoRatio"`
ProfitFactor fixedpoint.Value `json:"profitFactor"`
WinningRatio fixedpoint.Value `json:"winningRatio"`
}

func (r *SessionSymbolReport) InitialEquityValue() fixedpoint.Value {
Expand Down
4 changes: 3 additions & 1 deletion pkg/bbgo/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/pkg/errors"
"gopkg.in/yaml.v3"

"github.com/c9s/bbgo/pkg/datasource/csvsource"
"github.com/c9s/bbgo/pkg/datatype"
"github.com/c9s/bbgo/pkg/dynamic"
"github.com/c9s/bbgo/pkg/fixedpoint"
Expand Down Expand Up @@ -150,7 +151,8 @@ type Backtest struct {
Sessions []string `json:"sessions" yaml:"sessions"`

// sync 1 second interval KLines
SyncSecKLines bool `json:"syncSecKLines,omitempty" yaml:"syncSecKLines,omitempty"`
SyncSecKLines bool `json:"syncSecKLines,omitempty" yaml:"syncSecKLines,omitempty"`
CsvSource *csvsource.CsvConfig `json:"csvConfig,omitempty" yaml:"csvConfig,omitempty"`
}

func (b *Backtest) GetAccount(n string) BacktestAccount {
Expand Down
6 changes: 3 additions & 3 deletions pkg/bbgo/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ func init() {
// IsBackTesting is a global variable that indicates the current environment is back-test or not.
var IsBackTesting = false

var BackTestService *service.BacktestService
var BackTestService service.BackTestable

func SetBackTesting(s *service.BacktestService) {
func SetBackTesting(s service.BackTestable) {
BackTestService = s
IsBackTesting = s != nil
}
Expand Down Expand Up @@ -85,7 +85,7 @@ type Environment struct {
TradeService *service.TradeService
ProfitService *service.ProfitService
PositionService *service.PositionService
BacktestService *service.BacktestService
BacktestService service.BackTestable
RewardService *service.RewardService
MarginService *service.MarginService
SyncService *service.SyncService
Expand Down
Loading

0 comments on commit eba3074

Please sign in to comment.