Skip to content

Commit 71d6ec8

Browse files
go-docklyc9s
authored andcommitted
release candidate csvsource backtest
1 parent 057fb69 commit 71d6ec8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2356
-463
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*.out
1515

1616
.idea
17+
.vscode
1718

1819
# Dependency directories (remove the comment below to include it)
1920
# vendor/
@@ -48,6 +49,7 @@ testoutput
4849

4950
*.swp
5051
/pkg/backtest/assets.go
52+
/data/backtest
5153

5254
coverage.txt
5355
coverage_dum.txt

doc/topics/back-testing.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
## Back-testing
22

3-
*Before you start back-testing, you need to setup [MySQL](../../README.md#configure-mysql-database) or [SQLite3
3+
Currently bbgo supports two ways to run backtests:
4+
5+
1: Through csv data source (supported right now are binance, bybit and OkEx)
6+
7+
2: Alternatively run backtests through [MySQL](../../README.md#configure-mysql-database) or [SQLite3
48
](../../README.md#configure-sqlite3-database). Using MySQL is highly recommended.*
59

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

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

44-
And then, you can sync remote exchange k-lines (candle bars) data for back-testing:
45-
48+
And then, you can sync remote exchange k-lines (candle bars) data for back-testing through csv data source:
49+
```sh
50+
bbgo backtest -v --csv --verify --config config/grid.yaml
51+
```
52+
or use the sql data source like so:
4653
```sh
4754
bbgo backtest -v --sync --config config/grid.yaml
4855
```
@@ -67,6 +74,11 @@ Run back-test:
6774
```sh
6875
bbgo backtest --base-asset-baseline --config config/grid.yaml
6976
```
77+
or through csv data source
78+
79+
```sh
80+
bbgo backtest -v --csv --base-asset-baseline --config config/grid.yaml --output data/backtest
81+
```
7082

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

pkg/backtest/exchange.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ var ErrEmptyOrderType = errors.New("order type can not be empty string")
5555
type Exchange struct {
5656
sourceName types.ExchangeName
5757
publicExchange types.Exchange
58-
srv *service.BacktestService
58+
srv service.BackTestable
5959
currentTime time.Time
6060

6161
account *types.Account
@@ -78,7 +78,7 @@ type Exchange struct {
7878
}
7979

8080
func NewExchange(
81-
sourceName types.ExchangeName, sourceExchange types.Exchange, srv *service.BacktestService, config *bbgo.Backtest,
81+
sourceName types.ExchangeName, sourceExchange types.Exchange, srv service.BackTestable, config *bbgo.Backtest,
8282
) (*Exchange, error) {
8383
ex := sourceExchange
8484

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

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

379381
var intervals []types.Interval
380382
for interval := range loadedIntervals {
381383
intervals = append(intervals, interval)
382384
}
383-
384385
log.Infof("querying klines from database with exchange: %v symbols: %v and intervals: %v for back-testing", e.Name(), symbols, intervals)
385386
if len(symbols) == 0 {
386387
log.Warnf("empty symbols, will not query kline data from the database")

pkg/backtest/report.go

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -68,49 +68,21 @@ func ReadSummaryReport(filename string) (*SummaryReport, error) {
6868
// SessionSymbolReport is the report per exchange session
6969
// trades are merged, collected and re-calculated
7070
type SessionSymbolReport struct {
71-
Exchange types.ExchangeName `json:"exchange"`
72-
Symbol string `json:"symbol,omitempty"`
73-
Intervals []types.Interval `json:"intervals,omitempty"`
74-
Subscriptions []types.Subscription `json:"subscriptions"`
75-
Market types.Market `json:"market"`
76-
LastPrice fixedpoint.Value `json:"lastPrice,omitempty"`
77-
StartPrice fixedpoint.Value `json:"startPrice,omitempty"`
78-
PnL *pnl.AverageCostPnLReport `json:"pnl,omitempty"`
79-
InitialBalances types.BalanceMap `json:"initialBalances,omitempty"`
80-
FinalBalances types.BalanceMap `json:"finalBalances,omitempty"`
81-
Manifests Manifests `json:"manifests,omitempty"`
82-
TradeCount fixedpoint.Value `json:"tradeCount,omitempty"`
83-
RoundTurnCount fixedpoint.Value `json:"roundTurnCount,omitempty"`
84-
TotalNetProfit fixedpoint.Value `json:"totalNetProfit,omitempty"`
85-
AvgNetProfit fixedpoint.Value `json:"avgNetProfit,omitempty"`
86-
GrossProfit fixedpoint.Value `json:"grossProfit,omitempty"`
87-
GrossLoss fixedpoint.Value `json:"grossLoss,omitempty"`
88-
PRR fixedpoint.Value `json:"prr,omitempty"`
89-
PercentProfitable fixedpoint.Value `json:"percentProfitable,omitempty"`
90-
MaxDrawdown fixedpoint.Value `json:"maxDrawdown,omitempty"`
91-
AverageDrawdown fixedpoint.Value `json:"avgDrawdown,omitempty"`
92-
MaxProfit fixedpoint.Value `json:"maxProfit,omitempty"`
93-
MaxLoss fixedpoint.Value `json:"maxLoss,omitempty"`
94-
AvgProfit fixedpoint.Value `json:"avgProfit,omitempty"`
95-
AvgLoss fixedpoint.Value `json:"avgLoss,omitempty"`
96-
TotalTimeInMarketSec int64 `json:"totalTimeInMarketSec,omitempty"`
97-
AvgHoldSec int64 `json:"avgHoldSec,omitempty"`
98-
WinningCount int `json:"winningCount,omitempty"`
99-
LosingCount int `json:"losingCount,omitempty"`
100-
MaxLossStreak int `json:"maxLossStreak,omitempty"`
101-
Sharpe fixedpoint.Value `json:"sharpeRatio"`
102-
AnnualHistoricVolatility fixedpoint.Value `json:"annualHistoricVolatility,omitempty"`
103-
CAGR fixedpoint.Value `json:"cagr,omitempty"`
104-
Calmar fixedpoint.Value `json:"calmar,omitempty"`
105-
Sterling fixedpoint.Value `json:"sterling,omitempty"`
106-
Burke fixedpoint.Value `json:"burke,omitempty"`
107-
Kelly fixedpoint.Value `json:"kelly,omitempty"`
108-
OptimalF fixedpoint.Value `json:"optimalF,omitempty"`
109-
StatN fixedpoint.Value `json:"statN,omitempty"`
110-
StdErr fixedpoint.Value `json:"statNStdErr,omitempty"`
111-
Sortino fixedpoint.Value `json:"sortinoRatio"`
112-
ProfitFactor fixedpoint.Value `json:"profitFactor"`
113-
WinningRatio fixedpoint.Value `json:"winningRatio"`
71+
Exchange types.ExchangeName `json:"exchange"`
72+
Symbol string `json:"symbol,omitempty"`
73+
Intervals []types.Interval `json:"intervals,omitempty"`
74+
Subscriptions []types.Subscription `json:"subscriptions"`
75+
Market types.Market `json:"market"`
76+
LastPrice fixedpoint.Value `json:"lastPrice,omitempty"`
77+
StartPrice fixedpoint.Value `json:"startPrice,omitempty"`
78+
PnL *pnl.AverageCostPnLReport `json:"pnl,omitempty"`
79+
InitialBalances types.BalanceMap `json:"initialBalances,omitempty"`
80+
FinalBalances types.BalanceMap `json:"finalBalances,omitempty"`
81+
Manifests Manifests `json:"manifests,omitempty"`
82+
Sharpe fixedpoint.Value `json:"sharpeRatio"`
83+
Sortino fixedpoint.Value `json:"sortinoRatio"`
84+
ProfitFactor fixedpoint.Value `json:"profitFactor"`
85+
WinningRatio fixedpoint.Value `json:"winningRatio"`
11486
}
11587

11688
func (r *SessionSymbolReport) InitialEquityValue() fixedpoint.Value {

pkg/bbgo/config.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/pkg/errors"
1313
"gopkg.in/yaml.v3"
1414

15+
"github.com/c9s/bbgo/pkg/datasource/csvsource"
1516
"github.com/c9s/bbgo/pkg/datatype"
1617
"github.com/c9s/bbgo/pkg/dynamic"
1718
"github.com/c9s/bbgo/pkg/fixedpoint"
@@ -150,7 +151,8 @@ type Backtest struct {
150151
Sessions []string `json:"sessions" yaml:"sessions"`
151152

152153
// sync 1 second interval KLines
153-
SyncSecKLines bool `json:"syncSecKLines,omitempty" yaml:"syncSecKLines,omitempty"`
154+
SyncSecKLines bool `json:"syncSecKLines,omitempty" yaml:"syncSecKLines,omitempty"`
155+
CsvSource *csvsource.CsvConfig `json:"csvConfig,omitempty" yaml:"csvConfig,omitempty"`
154156
}
155157

156158
func (b *Backtest) GetAccount(n string) BacktestAccount {

pkg/bbgo/environment.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ func init() {
4040
// IsBackTesting is a global variable that indicates the current environment is back-test or not.
4141
var IsBackTesting = false
4242

43-
var BackTestService *service.BacktestService
43+
var BackTestService service.BackTestable
4444

45-
func SetBackTesting(s *service.BacktestService) {
45+
func SetBackTesting(s service.BackTestable) {
4646
BackTestService = s
4747
IsBackTesting = s != nil
4848
}
@@ -85,7 +85,7 @@ type Environment struct {
8585
TradeService *service.TradeService
8686
ProfitService *service.ProfitService
8787
PositionService *service.PositionService
88-
BacktestService *service.BacktestService
88+
BacktestService service.BackTestable
8989
RewardService *service.RewardService
9090
MarginService *service.MarginService
9191
SyncService *service.SyncService

0 commit comments

Comments
 (0)