From 141f5ecb3db093b30e37f728cc2ca0fe0b9f79ce Mon Sep 17 00:00:00 2001 From: altafan <18440657+altafan@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:06:01 +0200 Subject: [PATCH] Add calc of default timeframe in market report --- .../application/operator/market_account.go | 72 ++++++++++++++----- internal/interfaces/grpc/handler/operator.go | 4 +- internal/interfaces/grpc/handler/utils.go | 8 +-- 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/internal/core/application/operator/market_account.go b/internal/core/application/operator/market_account.go index 7a95e1cd..56e9db79 100644 --- a/internal/core/application/operator/market_account.go +++ b/internal/core/application/operator/market_account.go @@ -109,12 +109,19 @@ func (s *service) ListMarketExternalAddresses( func (s *service) GetMarketReport( ctx context.Context, market ports.Market, - timeRange ports.TimeRange, groupByHours int, + timeRange ports.TimeRange, timeFrame int, ) (ports.MarketReport, error) { - rangeStart, rangeEnd := timeRangeToDates(timeRange) + rangeStart, rangeEnd, err := timeRangeToDates(timeRange) + if err != nil { + return nil, err + } - if int(rangeEnd.Sub(rangeStart).Hours()) <= groupByHours { - return nil, fmt.Errorf("time range too small for given grouping period") + if timeFrame == 0 { + timeFrame = getDefaultTimeFrameForRange(rangeStart, rangeEnd) + } + + if int(rangeEnd.Sub(rangeStart).Hours()) < timeFrame { + return nil, fmt.Errorf("time range must be larger than time frame") } mkt, err := s.repoManager.MarketRepository().GetMarketByAssets( @@ -136,7 +143,7 @@ func (s *service) GetMarketReport( return trades[i].SwapRequest.Timestamp > trades[j].SwapRequest.Timestamp }) - subVolumes := splitTimeRange(rangeStart, rangeEnd, groupByHours) + subVolumes := splitTimeRange(rangeStart, rangeEnd, timeFrame) tradesFee := make([]tradeFeeInfo, 0) for _, trade := range trades { if isInTimeRange(trade.SwapRequest.Timestamp, rangeStart, rangeEnd) { @@ -375,15 +382,21 @@ func (s *service) UpdateMarketStrategy( ) } -func timeRangeToDates(tr ports.TimeRange) (startTime, endTime time.Time) { +func timeRangeToDates(tr ports.TimeRange) (startTime, endTime time.Time, err error) { now := time.Now() endTime = now if p := tr.GetCustomPeriod(); p != nil { - startTime, _ = time.Parse(time.RFC3339, p.GetStartDate()) + startTime, err = time.Parse(time.RFC3339, p.GetStartDate()) + if err != nil { + return + } if p.GetEndDate() != "" { - endTime, _ = time.Parse(time.RFC3339, p.GetEndDate()) + endTime, err = time.Parse(time.RFC3339, p.GetEndDate()) + if err != nil { + return + } } return } @@ -420,10 +433,10 @@ func timeRangeToDates(tr ports.TimeRange) (startTime, endTime time.Time) { return } -// initGroupedVolume splits the given time range (start, end) into a list of -// MarketVolume, ie. smaller consecutive time ranges of numHours hours in -// descending order. Example: -// in: 2009-11-10 19:00:00 (start), 2009-11-11 00:00:00 (end), 2 (numHours) +// splitTimeRange splits the given time range (start, end) into a list of +// sub-ranges of frame hours, ordered from end to start. +// Example: +// in: 2009-11-10 19:00:00 (start), 2009-11-11 00:00:00 (end), 1 (frame) // out: [ // // {end: 2009-11-11 00:00:00, start: 2009-11-10 22:00:01}, @@ -432,19 +445,19 @@ func timeRangeToDates(tr ports.TimeRange) (startTime, endTime time.Time) { // // ] func splitTimeRange( - start, end time.Time, groupByHours int, + start, end time.Time, frame int, ) marketVolumeInfoList { - groupedVolume := make([]*marketVolumeInfo, 0) + subRanges := make([]*marketVolumeInfo, 0) for { if end.Equal(start) || end.Before(start) { - return groupedVolume + return subRanges } else { - nextEnd := end.Add(-time.Hour * time.Duration(groupByHours)) + nextEnd := end.Add(-time.Hour * time.Duration(frame)) nextStart := start if nextEnd.Sub(start).Seconds() > 0 { nextStart = nextEnd.Add(time.Second) } - groupedVolume = append(groupedVolume, &marketVolumeInfo{ + subRanges = append(subRanges, &marketVolumeInfo{ start: nextStart, end: end, }) end = nextEnd @@ -456,3 +469,28 @@ func isInTimeRange(t int64, start, end time.Time) bool { tt := time.Unix(t, 0) return !tt.Before(start) && !tt.After(end) } + +// getDefaultTimeFrameForRange returns the appropriate time frame (tf) +// based on the delta in days between start and end. +// - delta >= 5y -> tf = 1m +// - delta >= 1y -> tf = 7d +// - delta >= 3m -> tf = 1d +// - delta >= 7d -> tf = 4h +// - otherwise tf = 1h +func getDefaultTimeFrameForRange(start, end time.Time) int { + delta := int64(end.Sub(start).Hours() / 24) + + if delta >= 365*5 { + return 24 * 30 + } + if delta >= 365 { + return 24 * 7 + } + if delta >= 88 { + return 24 + } + if delta >= 7 { + return 4 + } + return 1 +} diff --git a/internal/interfaces/grpc/handler/operator.go b/internal/interfaces/grpc/handler/operator.go index 6abd8b38..b6b4ccbd 100644 --- a/internal/interfaces/grpc/handler/operator.go +++ b/internal/interfaces/grpc/handler/operator.go @@ -485,13 +485,13 @@ func (h *operatorHandler) getMarketReport( if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } - groupByTimeFrame, err := parseTimeFrame(req.GetTimeFrame()) + timeFrame, err := parseTimeFrame(req.GetTimeFrame()) if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } report, err := h.operatorSvc.GetMarketReport( - ctx, market, timeRange, groupByTimeFrame, + ctx, market, timeRange, timeFrame, ) if err != nil { return nil, err diff --git a/internal/interfaces/grpc/handler/utils.go b/internal/interfaces/grpc/handler/utils.go index b2ca8923..09f6e1d8 100644 --- a/internal/interfaces/grpc/handler/utils.go +++ b/internal/interfaces/grpc/handler/utils.go @@ -294,7 +294,9 @@ func parseTimeRange(timeRange *daemonv2.TimeRange) (ports.TimeRange, error) { func parseTimeFrame(timeFrame daemonv2.TimeFrame) (int, error) { switch timeFrame { - case daemonv2.TimeFrame_TIME_FRAME_UNSPECIFIED, daemonv2.TimeFrame_TIME_FRAME_HOUR: + case daemonv2.TimeFrame_TIME_FRAME_UNSPECIFIED: + return 0, nil + case daemonv2.TimeFrame_TIME_FRAME_HOUR: return 1, nil case daemonv2.TimeFrame_TIME_FRAME_FOUR_HOURS: return 4, nil @@ -303,9 +305,7 @@ func parseTimeFrame(timeFrame daemonv2.TimeFrame) (int, error) { case daemonv2.TimeFrame_TIME_FRAME_WEEK: return 24 * 7, nil case daemonv2.TimeFrame_TIME_FRAME_MONTH: - year, month, _ := time.Now().Date() - numOfDaysForCurrentMont := time.Date(year, month+1, 0, 0, 0, 0, 0, time.UTC).Day() - return numOfDaysForCurrentMont, nil + return 24 * 30, nil default: return -1, fmt.Errorf("unknown time frame") }