build/ci: Update Go to v1.24, golangci-lint to v1.64.6 and fix issues (#1804)

* build/ci: Update Go to v1.24, golangci-lint to v1.64.5 and fix issues

* Address shazbert's nitters

* linter/config: Fix new linter issue and use versionSize const

* Address gk's nitters and fix additional linter issue after rebase

* Address glorious nits

* staticcheck: Fix additional linter issues after upgrading to Go 1.24.1 and golangci-lint v1.64.6

Also addresses nits

* Improve testing, assertify usage and use common.ErrParsingWSField

* TestCreateNewStrategy: Replace must > should wording
This commit is contained in:
Adrian Gallagher
2025-03-10 16:33:55 +11:00
committed by GitHub
parent c086e281cf
commit d64d56f77c
114 changed files with 5080 additions and 9355 deletions

View File

@@ -346,12 +346,17 @@ func durationToWord(in Interval) string {
}
// TotalCandlesPerInterval returns the total number of candle intervals between the start and end date
func TotalCandlesPerInterval(start, end time.Time, interval Interval) int64 {
func TotalCandlesPerInterval(start, end time.Time, interval Interval) uint64 {
if interval <= 0 {
return 0
}
if start.After(end) {
return 0
}
window := end.Sub(start)
return int64(window) / int64(interval)
return uint64(window) / uint64(interval) //nolint:gosec // No overflow risk
}
// IntervalsPerYear helps determine the number of intervals in a year
@@ -461,7 +466,7 @@ func (k *Item) ConvertToNewInterval(newInterval Interval) (*Item, error) {
// CalculateCandleDateRanges will calculate the expected candle data in intervals in a date range
// If an API is limited in the amount of candles it can make in a request, it will automatically separate
// ranges into the limit
func CalculateCandleDateRanges(start, end time.Time, interval Interval, limit uint32) (*IntervalRangeHolder, error) {
func CalculateCandleDateRanges(start, end time.Time, interval Interval, limit uint64) (*IntervalRangeHolder, error) {
if err := common.StartEndTimeCheck(start, end); err != nil && !errors.Is(err, common.ErrStartAfterTimeNow) {
return nil, err
}
@@ -471,44 +476,39 @@ func CalculateCandleDateRanges(start, end time.Time, interval Interval, limit ui
start = start.Round(interval.Duration())
end = end.Round(interval.Duration())
window := end.Sub(start)
count := int64(window) / int64(interval)
requests := float64(count) / float64(limit)
switch {
case requests <= 1:
requests = 1
case limit == 0:
requests, limit = 1, uint32(count)
case requests-float64(int64(requests)) > 0:
requests++
count := uint64(end.Sub(start) / interval.Duration()) //nolint:gosec // No overflow risk
if count == 0 {
return nil, common.ErrStartEqualsEnd
}
potentialRequests := make([]IntervalRange, int(requests))
requestStart := start
for x := range potentialRequests {
potentialRequests[x].Start = CreateIntervalTime(requestStart)
count -= int64(limit)
if count < 0 {
potentialRequests[x].Intervals = make([]IntervalData, count+int64(limit))
} else {
potentialRequests[x].Intervals = make([]IntervalData, limit)
}
for y := range potentialRequests[x].Intervals {
potentialRequests[x].Intervals[y].Start = CreateIntervalTime(requestStart)
requestStart = requestStart.Add(interval.Duration())
potentialRequests[x].Intervals[y].End = CreateIntervalTime(requestStart)
}
potentialRequests[x].End = CreateIntervalTime(requestStart)
intervals := make([]IntervalData, 0, count)
for iStart := start; iStart.Before(end); iStart = iStart.Add(interval.Duration()) {
intervals = append(intervals, IntervalData{
Start: CreateIntervalTime(iStart),
End: CreateIntervalTime(iStart.Add(interval.Duration())),
})
}
return &IntervalRangeHolder{
Start: CreateIntervalTime(start),
End: CreateIntervalTime(requestStart),
Ranges: potentialRequests,
Limit: int(limit),
}, nil
if limit == 0 {
limit = count
}
h := &IntervalRangeHolder{
Start: CreateIntervalTime(start),
End: CreateIntervalTime(end),
Limit: limit,
}
for _, b := range common.Batch(intervals, int(limit)) { //nolint:gosec // Ignore this warning as Batch requires int
h.Ranges = append(h.Ranges, IntervalRange{
Start: b[0].Start,
End: b[len(b)-1].End,
Intervals: b,
})
}
return h, nil
}
// HasDataAtDate determines whether a there is any data at a set
@@ -653,7 +653,7 @@ func (k *Item) EqualSource(i *Item) error {
func DeployExchangeIntervals(enabled ...IntervalCapacity) ExchangeIntervals {
sort.Slice(enabled, func(i, j int) bool { return enabled[i].Interval < enabled[j].Interval })
supported := make(map[Interval]int64)
supported := make(map[Interval]uint64)
for x := range enabled {
supported[enabled[x].Interval] = enabled[x].Capacity
}
@@ -693,7 +693,7 @@ func (e *ExchangeIntervals) Construct(required Interval) (Interval, error) {
// GetIntervalResultLimit returns the maximum amount of candles that can be
// returned for a specific interval. If the individual interval limit is not set,
// it will be ignored and the global result limit will be returned.
func (e *ExchangeCapabilitiesEnabled) GetIntervalResultLimit(interval Interval) (int64, error) {
func (e *ExchangeCapabilitiesEnabled) GetIntervalResultLimit(interval Interval) (uint64, error) {
if e == nil {
return 0, errExchangeCapabilitiesEnabledIsNil
}
@@ -711,5 +711,5 @@ func (e *ExchangeCapabilitiesEnabled) GetIntervalResultLimit(interval Interval)
return 0, fmt.Errorf("%w there is no global result limit set", errCannotFetchIntervalLimit)
}
return int64(e.GlobalResultLimit), nil
return e.GlobalResultLimit, nil
}

View File

@@ -11,6 +11,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/database"
@@ -282,13 +283,17 @@ func TestDurationToWord(t *testing.T) {
func TestTotalCandlesPerInterval(t *testing.T) {
t.Parallel()
tmNow := time.Now()
assert.Equal(t, uint64(0), TotalCandlesPerInterval(tmNow.AddDate(0, 0, 1), tmNow, OneMin))
start := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
testCases := []struct {
name string
interval Interval
expected int64
expected uint64
}{
{
"FifteenSecond",
@@ -413,65 +418,41 @@ func TestCalculateCandleDateRanges(t *testing.T) {
pt := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
ft := time.Date(2222, 1, 1, 0, 0, 0, 0, time.UTC)
et := time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC)
nt := time.Time{}
_, err := CalculateCandleDateRanges(nt, nt, OneMin, 300)
if !errors.Is(err, common.ErrDateUnset) {
t.Errorf("received %v expected %v", err, common.ErrDateUnset)
}
_, err := CalculateCandleDateRanges(time.Time{}, time.Time{}, OneMin, 300)
assert.ErrorIs(t, err, common.ErrDateUnset)
_, err = CalculateCandleDateRanges(et, pt, OneMin, 300)
if !errors.Is(err, common.ErrStartAfterEnd) {
t.Errorf("received %v expected %v", err, common.ErrStartAfterEnd)
}
assert.ErrorIs(t, err, common.ErrStartAfterEnd)
_, err = CalculateCandleDateRanges(et, ft, 0, 300)
if !errors.Is(err, ErrInvalidInterval) {
t.Errorf("received %v expected %v", err, ErrInvalidInterval)
}
assert.ErrorIs(t, err, ErrInvalidInterval)
_, err = CalculateCandleDateRanges(et, et, OneMin, 300)
if !errors.Is(err, common.ErrStartEqualsEnd) {
t.Errorf("received %v expected %v", err, common.ErrStartEqualsEnd)
}
assert.ErrorIs(t, err, common.ErrStartEqualsEnd)
v, err := CalculateCandleDateRanges(pt, et, OneWeek, 300)
if !errors.Is(err, nil) {
t.Errorf("received '%v' expected '%v'", err, nil)
}
if !v.Ranges[0].Start.Time.Equal(time.Unix(1546214400, 0)) {
t.Errorf("expected %v received %v", 1546214400, v.Ranges[0].Start.Ticks)
}
require.NoError(t, err)
assert.Equal(t, int64(1546214400), v.Ranges[0].Start.Ticks)
v, err = CalculateCandleDateRanges(pt, et, OneWeek, 100)
if !errors.Is(err, nil) {
t.Errorf("received '%v' expected '%v'", err, nil)
}
if len(v.Ranges) != 1 {
t.Fatalf("expected %v received %v", 1, len(v.Ranges))
}
if len(v.Ranges[0].Intervals) != 52 {
t.Errorf("expected %v received %v", 52, len(v.Ranges[0].Intervals))
}
require.NoError(t, err)
assert.Equal(t, 1, len(v.Ranges))
assert.Equal(t, 52, len(v.Ranges[0].Intervals))
v, err = CalculateCandleDateRanges(et, ft, OneWeek, 5)
if !errors.Is(err, nil) {
t.Errorf("received '%v' expected '%v'", err, nil)
}
if len(v.Ranges) != 2108 {
t.Errorf("expected %v received %v", 2108, len(v.Ranges))
}
if len(v.Ranges[0].Intervals) != 5 {
t.Errorf("expected %v received %v", 5, len(v.Ranges[0].Intervals))
}
if len(v.Ranges[1].Intervals) != 5 {
t.Errorf("expected %v received %v", 5, len(v.Ranges[1].Intervals))
}
require.NoError(t, err)
assert.Equal(t, 2108, len(v.Ranges))
assert.Equal(t, 5, len(v.Ranges[0].Intervals))
lenRanges := len(v.Ranges) - 1
lenIntervals := len(v.Ranges[lenRanges].Intervals) - 1
if !v.Ranges[lenRanges].Intervals[lenIntervals].End.Equal(ft.Round(OneWeek.Duration())) {
t.Errorf("expected %v received %v", ft.Round(OneDay.Duration()), v.Ranges[lenRanges].Intervals[lenIntervals].End)
}
assert.True(t, v.Ranges[lenRanges].Intervals[lenIntervals].End.Equal(ft.Round(OneWeek.Duration())))
start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
end := start.Add(24 * time.Hour)
v, err = CalculateCandleDateRanges(start, end, OneDay, 0)
require.NoError(t, err)
assert.Equal(t, uint64(1), v.Limit)
}
func TestItem_SortCandlesByTimestamp(t *testing.T) {
@@ -901,7 +882,7 @@ func BenchmarkJustifyIntervalTimeStoringUnixValues1(b *testing.B) {
tt1 := time.Now()
tt2 := time.Now().Add(-time.Hour)
tt3 := time.Now().Add(time.Hour)
for i := 0; i < b.N; i++ {
for b.Loop() {
if tt1.Unix() == tt2.Unix() || (tt1.Unix() > tt2.Unix() && tt1.Unix() < tt3.Unix()) {
continue
}
@@ -916,7 +897,7 @@ func BenchmarkJustifyIntervalTimeStoringUnixValues2(b *testing.B) {
tt1 := time.Now().Unix()
tt2 := time.Now().Add(-time.Hour).Unix()
tt3 := time.Now().Add(time.Hour).Unix()
for i := 0; i < b.N; i++ {
for b.Loop() {
if tt1 >= tt2 && tt1 <= tt3 {
continue
}
@@ -1371,7 +1352,7 @@ func TestGetIntervalResultLimit(t *testing.T) {
}
e.Intervals = ExchangeIntervals{
supported: map[Interval]int64{
supported: map[Interval]uint64{
OneDay: 100000,
OneMin: 0,
},

View File

@@ -161,13 +161,13 @@ type ExchangeCapabilitiesEnabled struct {
// across all intervals. This is used to determine if a request will exceed
// the exchange limits. Indivudal interval limits are stored in the
// ExchangeIntervals struct. If this is set to 0, it will be ignored.
GlobalResultLimit uint32
GlobalResultLimit uint64
}
// ExchangeIntervals stores the supported intervals in an optimized lookup table
// with a supplementary aligned retrieval list
type ExchangeIntervals struct {
supported map[Interval]int64
supported map[Interval]uint64
aligned []IntervalCapacity
}
@@ -180,7 +180,7 @@ type IntervalRangeHolder struct {
Start IntervalTime
End IntervalTime
Ranges []IntervalRange
Limit int
Limit uint64
}
// IntervalRange is a subset of candles based on exchange API request limits
@@ -209,5 +209,5 @@ type IntervalTime struct {
// IntervalCapacity is used to store the interval and capacity for a candle return
type IntervalCapacity struct {
Interval Interval
Capacity int64
Capacity uint64
}

View File

@@ -58,12 +58,12 @@ type Request struct {
ProcessedCandles []Candle
// RequestLimit is the potential maximum amount of candles that can be
// returned
RequestLimit int64
RequestLimit uint64
}
// CreateKlineRequest generates a `Request` type for interval conversions
// supported by an exchange.
func CreateKlineRequest(name string, pair, formatted currency.Pair, a asset.Item, clientRequired, exchangeInterval Interval, start, end time.Time, specificEndpointLimit int64) (*Request, error) {
func CreateKlineRequest(name string, pair, formatted currency.Pair, a asset.Item, clientRequired, exchangeInterval Interval, start, end time.Time, specificEndpointLimit uint64) (*Request, error) {
if name == "" {
return nil, ErrUnsetName
}
@@ -132,7 +132,7 @@ func CreateKlineRequest(name string, pair, formatted currency.Pair, a asset.Item
// GetRanges returns the date ranges for candle intervals broken up over
// requests
func (r *Request) GetRanges(limit uint32) (*IntervalRangeHolder, error) {
func (r *Request) GetRanges(limit uint64) (*IntervalRangeHolder, error) {
if r == nil {
return nil, errNilRequest
}
@@ -193,12 +193,12 @@ func (r *Request) ProcessResponse(timeSeries []Candle) (*Item, error) {
}
// Size returns the max length of return for pre-allocation.
func (r *Request) Size() int {
func (r *Request) Size() uint64 {
if r == nil {
return 0
}
return int(TotalCandlesPerInterval(r.Start, r.End, r.ExchangeInterval))
return TotalCandlesPerInterval(r.Start, r.End, r.ExchangeInterval)
}
// ExtendedRequest used in extended functionality for when candles requested
@@ -236,12 +236,12 @@ func (r *ExtendedRequest) ProcessResponse(timeSeries []Candle) (*Item, error) {
}
// Size returns the max length of return for pre-allocation.
func (r *ExtendedRequest) Size() int {
func (r *ExtendedRequest) Size() uint64 {
if r == nil || r.RangeHolder == nil {
return 0
}
if r.RangeHolder.Limit == 0 {
log.Warnf(log.ExchangeSys, "%v candle request limit is zero while calling Size()", r.Exchange)
}
return r.RangeHolder.Limit * len(r.RangeHolder.Ranges)
return r.RangeHolder.Limit * uint64(len(r.RangeHolder.Ranges))
}