From 425f8674d260a24cd02ac0e8885b042d2cdc59fc Mon Sep 17 00:00:00 2001 From: c9s Date: Sat, 4 Jun 2022 19:15:11 +0800 Subject: [PATCH] service: add kline partial sync --- pkg/service/backtest.go | 25 ++++++++++++++- pkg/service/backtest_test.go | 60 +++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/pkg/service/backtest.go b/pkg/service/backtest.go index ac69907d2..e4093fbf0 100644 --- a/pkg/service/backtest.go +++ b/pkg/service/backtest.go @@ -364,7 +364,30 @@ func (s *BacktestService) SyncPartial(ctx context.Context, ex types.Exchange, sy if err != nil { return err } - _ = timeRanges + + // there are few cases: + // t1 == since && t2 == until + if since.Before(t1.Time()) { + // shift slice + timeRanges = append([]TimeRange{ + {Start: since.Add(-2 * time.Second), End: t1.Time()}, // include since + }, timeRanges...) + } + + if t2.Time().Before(until) { + timeRanges = append(timeRanges, TimeRange{ + Start: t2.Time(), + End: until.Add(2 * time.Second), // include until + }) + } + + for _, timeRange := range timeRanges { + err = s.SyncKLineByInterval(ctx, ex, symbol, types.Interval1h, timeRange.Start.Add(time.Second), timeRange.End.Add(-time.Second)) + if err != nil { + return err + } + } + return nil } diff --git a/pkg/service/backtest_test.go b/pkg/service/backtest_test.go index 957783948..85256b606 100644 --- a/pkg/service/backtest_test.go +++ b/pkg/service/backtest_test.go @@ -13,7 +13,65 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -func TestBacktestService(t *testing.T) { +func TestBacktestService_SyncPartial(t *testing.T) { + db, err := prepareDB(t) + if err != nil { + t.Fatal(err) + } + + defer db.Close() + + ctx := context.Background() + dbx := sqlx.NewDb(db.DB, "sqlite3") + + ex, err := exchange.NewPublic(types.ExchangeBinance) + assert.NoError(t, err) + + service := &BacktestService{DB: dbx} + + symbol := "BTCUSDT" + now := time.Now() + startTime1 := now.AddDate(0, 0, -7).Truncate(time.Hour) + endTime1 := now.AddDate(0, 0, -6).Truncate(time.Hour) + + startTime2 := now.AddDate(0, 0, -5).Truncate(time.Hour) + endTime2 := now.AddDate(0, 0, -4).Truncate(time.Hour) + + // kline query is exclusive + err = service.SyncKLineByInterval(ctx, ex, symbol, types.Interval1h, startTime1.Add(-time.Second), endTime1.Add(time.Second)) + assert.NoError(t, err) + + err = service.SyncKLineByInterval(ctx, ex, symbol, types.Interval1h, startTime2.Add(-time.Second), endTime2.Add(time.Second)) + assert.NoError(t, err) + + timeRanges, err := service.FindMissingTimeRanges(ctx, ex, symbol, types.Interval1h, startTime1, endTime2) + assert.NoError(t, err) + assert.NotEmpty(t, timeRanges) + + t.Run("fill missing time ranges", func(t *testing.T) { + err = service.SyncPartial(ctx, ex, symbol, types.Interval1h, startTime1, endTime2) + assert.NoError(t, err, "sync partial should not return error") + + timeRanges2, err := service.FindMissingTimeRanges(ctx, ex, symbol, types.Interval1h, startTime1, endTime2) + assert.NoError(t, err) + assert.Empty(t, timeRanges2) + }) + + t.Run("extend time ranges", func(t *testing.T) { + startTime3 := startTime1.AddDate(0, 0, -3) + endTime3 := endTime2.AddDate(0, 0, 3) + + err = service.SyncPartial(ctx, ex, symbol, types.Interval1h, startTime3, endTime3) + assert.NoError(t, err, "sync partial should not return error") + + timeRanges3, err := service.FindMissingTimeRanges(ctx, ex, symbol, types.Interval1h, startTime3, endTime3) + assert.NoError(t, err) + assert.Empty(t, timeRanges3) + }) + +} + +func TestBacktestService_FindMissingTimeRanges(t *testing.T) { db, err := prepareDB(t) if err != nil { t.Fatal(err)