diff --git a/.gitignore b/.gitignore index 4c36e38..fc8de1f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea/ vendor/ +.DS_Store + diff --git a/Makefile b/Makefile index e3a8193..01c6ba1 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ lint: ## Run golang lint using docker -v ${GOPATH}/pkg/mod:/go/pkg/mod \ -v ${PWD}:/app \ -w /app \ - golangci/golangci-lint:v1.55.2 \ + golangci/golangci-lint:v1.56.2 \ golangci-lint run -v --modules-download-mode=readonly test: ## Run tests diff --git a/timeseries/candle.go b/timeseries/candle.go index b390e9e..5f22f73 100644 --- a/timeseries/candle.go +++ b/timeseries/candle.go @@ -4,12 +4,13 @@ import "time" // Candle represents trading candle type Candle struct { - Time time.Time `json:"time" db:"time" validate:"required"` - High float64 `json:"high" db:"high" validate:"required"` - Low float64 `json:"low" db:"low" validate:"required"` - Open float64 `json:"open" db:"open" validate:"required"` - Close float64 `json:"close" db:"close" validate:"required"` - Volume int64 `json:"volume" db:"volume" validate:"required"` + Time time.Time `json:"time" db:"time" validate:"required"` + High float64 `json:"high" db:"high" validate:"required"` + Low float64 `json:"low" db:"low" validate:"required"` + Open float64 `json:"open" db:"open" validate:"required"` + Close float64 `json:"close" db:"close" validate:"required"` + Volume int64 `json:"volume" db:"volume" validate:"required"` + IsComplete bool `json:"is_complete" db:"is_complete"` } // NewCandle creates new candle diff --git a/timeseries/time_series.go b/timeseries/time_series.go index 05f00de..70c5ebb 100644 --- a/timeseries/time_series.go +++ b/timeseries/time_series.go @@ -70,7 +70,7 @@ func (ts *TimeSeries) Trim(startIndex int, endIndex int) (*TimeSeries, error) { return &newTS, nil } -// LastCandle returns last candle in series +// LastCandle returns last candle in series or nil if series is empty func (ts *TimeSeries) LastCandle() *Candle { if len(ts.candles) > 0 { return ts.candles[len(ts.candles)-1] @@ -79,7 +79,19 @@ func (ts *TimeSeries) LastCandle() *Candle { return nil } -// Candle returns candle by index [0, len(series)-1] +// LastCompleteCandle returns last complete candle and index in series or nil if there are no complete candles +func (ts *TimeSeries) LastCompleteCandle() (*Candle, int) { + for i := ts.Length() - 1; i >= 0; i-- { + candle := ts.Candle(i) + if candle.IsComplete { + return candle, i + } + } + + return nil, 0 +} + +// Candle returns candle by index [0, len(series)-1] or nil if index out of series func (ts *TimeSeries) Candle(index int) *Candle { if index >= 0 && index < len(ts.candles) { return ts.candles[index] diff --git a/timeseries/time_series_test.go b/timeseries/time_series_test.go index f45eee6..a692734 100644 --- a/timeseries/time_series_test.go +++ b/timeseries/time_series_test.go @@ -192,3 +192,33 @@ func TestTimeSeries_Length(t *testing.T) { assert.Equal(t, 2, series.Length()) } + +func TestTimeSeries_LastCompleteCandle(t *testing.T) { + t.Run("LastCandle=nil", func(t *testing.T) { + series := New() + candle, _ := series.LastCompleteCandle() + assert.Nil(t, candle) + }) + + t.Run("LastCompleteCandle not nil", func(t *testing.T) { + series := New() + + err := series.AddCandle(createTestCandle()) + assert.Nil(t, err) + + completeCandle := createTestCandle() + completeCandle.Time = time.Unix(2, 0) + completeCandle.IsComplete = true + err = series.AddCandle(completeCandle) + assert.Nil(t, err) + + candle := createTestCandle() + candle.Time = time.Unix(3, 0) + err = series.AddCandle(candle) + assert.Nil(t, err) + + candle, index := series.LastCompleteCandle() + assert.Equal(t, completeCandle, candle) + assert.Equal(t, 1, index) + }) +}