diff --git a/core/banking/recurring_transfers.go b/core/banking/recurring_transfers.go index 7e7f1b65b7..975e740f6e 100644 --- a/core/banking/recurring_transfers.go +++ b/core/banking/recurring_transfers.go @@ -194,7 +194,15 @@ func (e *Engine) dispatchRequired(ctx context.Context, ds *vegapb.DispatchStrate vegapb.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY, vegapb.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN: if ds.EntityScope == vegapb.EntityScope_ENTITY_SCOPE_INDIVIDUALS { - return len(e.marketActivityTracker.CalculateMetricForIndividuals(ctx, ds)) > 0 + hasNonZeroMetric := false + partyMetrics := e.marketActivityTracker.CalculateMetricForIndividuals(ctx, ds) + for _, pm := range partyMetrics { + if !pm.Score.IsZero() { + hasNonZeroMetric = true + break + } + } + return hasNonZeroMetric || (len(partyMetrics) > 0 && ds.DistributionStrategy == vegapb.DistributionStrategy_DISTRIBUTION_STRATEGY_RANK) } else { tcs, _ := e.marketActivityTracker.CalculateMetricForTeams(ctx, ds) return len(tcs) > 0 diff --git a/core/execution/common/market_activity_tracker.go b/core/execution/common/market_activity_tracker.go index 8d050a196b..2f9d3295ff 100644 --- a/core/execution/common/market_activity_tracker.go +++ b/core/execution/common/market_activity_tracker.go @@ -554,7 +554,7 @@ func (mat *MarketActivityTracker) RecordM2M(asset, party, market string, amount } } -// RecordM2M passes the mark to market win/loss transfer amount to the asset/market tracker to be recorded. +// RecordFundingPayment passes the mark to market win/loss transfer amount to the asset/market tracker to be recorded. func (mat *MarketActivityTracker) RecordFundingPayment(asset, party, market string, amount num.Decimal) { if tracker, ok := mat.getMarketTracker(asset, market); ok { tracker.allPartiesCache[party] = struct{}{} @@ -664,8 +664,8 @@ func (mat *MarketActivityTracker) calculateMetricForIndividuals(ctx context.Cont if !mat.isEligibleForReward(ctx, asset, party, markets, minStakingBalanceRequired, notionalTimeWeightedAveragePositionRequired, gameID) { continue } - score := mat.calculateMetricForParty(asset, party, markets, metric, windowSize) - if score.IsZero() { + score, ok := mat.calculateMetricForParty(asset, party, markets, metric, windowSize) + if !ok { continue } ret = append(ret, &types.PartyContributionScore{Party: party, Score: score}) @@ -710,7 +710,7 @@ func calculateMetricForTeamUtil(ctx context.Context, windowSize int, topN num.Decimal, isEligibleForReward func(ctx context.Context, asset, party string, markets []string, minStakingBalanceRequired *num.Uint, notionalTimeWeightedAveragePositionRequired *num.Uint, gameID string) bool, - calculateMetricForParty func(asset, party string, marketsInScope []string, metric vega.DispatchMetric, windowSize int) num.Decimal, + calculateMetricForParty func(asset, party string, marketsInScope []string, metric vega.DispatchMetric, windowSize int) (num.Decimal, bool), gameID string, ) (num.Decimal, []*types.PartyContributionScore) { teamPartyScores := []*types.PartyContributionScore{} @@ -718,7 +718,9 @@ func calculateMetricForTeamUtil(ctx context.Context, if !isEligibleForReward(ctx, asset, party, marketsInScope, minStakingBalanceRequired, notionalTimeWeightedAveragePositionRequired, gameID) { continue } - teamPartyScores = append(teamPartyScores, &types.PartyContributionScore{Party: party, Score: calculateMetricForParty(asset, party, marketsInScope, metric, windowSize)}) + if score, ok := calculateMetricForParty(asset, party, marketsInScope, metric, windowSize); ok { + teamPartyScores = append(teamPartyScores, &types.PartyContributionScore{Party: party, Score: score}) + } } if len(teamPartyScores) == 0 { @@ -750,7 +752,7 @@ func calculateMetricForTeamUtil(ctx context.Context, } // calculateMetricForParty returns the value of a reward metric score for the given party for markets of the given assets which are in scope over the given window size. -func (mat *MarketActivityTracker) calculateMetricForParty(asset, party string, marketsInScope []string, metric vega.DispatchMetric, windowSize int) num.Decimal { +func (mat *MarketActivityTracker) calculateMetricForParty(asset, party string, marketsInScope []string, metric vega.DispatchMetric, windowSize int) (num.Decimal, bool) { // exclude unsupported metrics if metric == vega.DispatchMetric_DISPATCH_METRIC_MARKET_VALUE { mat.log.Panic("unexpected dispatch metric market value here") @@ -762,10 +764,11 @@ func (mat *MarketActivityTracker) calculateMetricForParty(asset, party string, m total := num.DecimalZero() marketTotal := num.DecimalZero() returns := make([]*num.Decimal, windowSize) + found := false assetTrackers, ok := mat.assetToMarketTrackers[asset] if !ok { - return num.DecimalZero() + return num.DecimalZero(), false } markets := marketsInScope @@ -785,14 +788,17 @@ func (mat *MarketActivityTracker) calculateMetricForParty(asset, party string, m switch metric { case vega.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION: if t, ok := marketTracker.getPositionMetricTotal(party, windowSize); ok { + found = true uTotal += t } case vega.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN: if t, ok := marketTracker.getRelativeReturnMetricTotal(party, windowSize); ok { + found = true total = total.Add(t) } case vega.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN: if t, ok := marketTracker.getRealisedReturnMetricTotal(party, windowSize); ok { + found = true total = total.Add(t) } case vega.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY: @@ -800,6 +806,7 @@ func (mat *MarketActivityTracker) calculateMetricForParty(asset, party string, m if !ok { continue } + found = true for i, ret := range r { if ret != nil { if returns[i] != nil { @@ -811,16 +818,25 @@ func (mat *MarketActivityTracker) calculateMetricForParty(asset, party string, m } case vega.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID: if t, ok := getFees(marketTracker.epochMakerFeesPaid, party, windowSize); ok { + if t.IsPositive() { + found = true + } total = total.Add(t) } marketTotal = marketTotal.Add(getTotalFees(marketTracker.epochTotalMakerFeesPaid, windowSize)) case vega.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED: if t, ok := getFees(marketTracker.epochMakerFeesReceived, party, windowSize); ok { + if t.IsPositive() { + found = true + } total = total.Add(t) } marketTotal = marketTotal.Add(getTotalFees(marketTracker.epochTotalMakerFeesReceived, windowSize)) case vega.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED: if t, ok := getFees(marketTracker.epochLpFees, party, windowSize); ok { + if t.IsPositive() { + found = true + } total = total.Add(t) } marketTotal = marketTotal.Add(getTotalFees(marketTracker.epochTotalLpFees, windowSize)) @@ -830,9 +846,9 @@ func (mat *MarketActivityTracker) calculateMetricForParty(asset, party string, m switch metric { case vega.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION: // descaling the total tw position metric by dividing by the scaling factor - return num.DecimalFromInt64(int64(uTotal)).Div(num.DecimalFromInt64(int64(windowSize) * scalingFactor)) + return num.DecimalFromInt64(int64(uTotal)).Div(num.DecimalFromInt64(int64(windowSize) * scalingFactor)), found case vega.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, vega.DispatchMetric_DISPATCH_METRIC_REALISED_RETURN: - return total.Div(num.DecimalFromInt64(int64(windowSize))) + return total.Div(num.DecimalFromInt64(int64(windowSize))), found case vega.DispatchMetric_DISPATCH_METRIC_RETURN_VOLATILITY: filteredReturns := []num.Decimal{} for _, d := range returns { @@ -840,23 +856,23 @@ func (mat *MarketActivityTracker) calculateMetricForParty(asset, party string, m filteredReturns = append(filteredReturns, *d) } } - if len(filteredReturns) == 0 { - return num.DecimalZero() + if len(filteredReturns) < 2 { + return num.DecimalZero(), false } variance, _ := num.Variance(filteredReturns) if !variance.IsZero() { - return num.DecimalOne().Div(variance) + return num.DecimalOne().Div(variance), found } - return variance + return variance, found case vega.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_PAID, vega.DispatchMetric_DISPATCH_METRIC_MAKER_FEES_RECEIVED, vega.DispatchMetric_DISPATCH_METRIC_LP_FEES_RECEIVED: if marketTotal.IsZero() { - return num.DecimalZero() + return num.DecimalZero(), found } - return total.Div(marketTotal) + return total.Div(marketTotal), found default: mat.log.Panic("unexpected metric") } - return num.DecimalZero() + return num.DecimalZero(), found } func (mat *MarketActivityTracker) RecordNotionalTakerVolume(marketID string, party string, volumeToAdd *num.Uint) { @@ -1061,6 +1077,12 @@ func (mt *marketTracker) processPositionEndOfEpoch(epochStartTime time.Time, end mt.epochTimeWeightedPosition = mt.epochTimeWeightedPosition[1:] } mt.epochTimeWeightedPosition = append(mt.epochTimeWeightedPosition, m) + for p, twp := range mt.twPosition { + // if the position at the beginning of the epoch is 0 clear it so we don't keep zero positions forever + if twp.currentEpochTWPosition == 0 && twp.position == 0 { + delete(mt.twPosition, p) + } + } } // //// return metric ////// @@ -1072,11 +1094,9 @@ func (mt *marketTracker) recordM2M(party string, amount num.Decimal) { } if _, ok := mt.partyM2M[party]; !ok { mt.partyM2M[party] = amount - mt.partyRealisedReturn[party] = amount return } mt.partyM2M[party] = mt.partyM2M[party].Add(amount) - mt.partyRealisedReturn[party] = mt.partyRealisedReturn[party].Add(amount) } func (mt *marketTracker) recordFundingPayment(party string, amount num.Decimal) { @@ -1091,7 +1111,7 @@ func (mt *marketTracker) recordFundingPayment(party string, amount num.Decimal) } func (mt *marketTracker) recordRealisedPosition(party string, realisedPosition num.Decimal) { - if party == "network" || realisedPosition.IsZero() { + if party == "network" { return } if _, ok := mt.partyRealisedReturn[party]; !ok { diff --git a/core/execution/common/market_activity_tracker_internal_test.go b/core/execution/common/market_activity_tracker_internal_test.go index 1770f7a542..d37dba4f6e 100644 --- a/core/execution/common/market_activity_tracker_internal_test.go +++ b/core/execution/common/market_activity_tracker_internal_test.go @@ -548,31 +548,41 @@ func TestCalculateMetricForPartyAvePosition(t *testing.T) { // calculate metric for p1 with scope=[m1] for window size=1 // 0*(1-0.9166666666666667)+10*0.9166666666666667 = 9.1666666667 - require.Equal(t, "9.166666", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ := tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "9.166666", score.String()) // calculate metric for p1 with scope=[m2] for window size=1 // 0*(1-0.6666666666666667)+20*0.6666666666666667 = 13.3333333333 - require.Equal(t, "13.333332", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "13.333332", score.String()) // calculate metric for p1 with scope=[m3] for window size=1 // 0*(1-0.5)+30*0.5 = 15 - require.Equal(t, "15", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "15", score.String()) // calculate metric for p1 with scope=[m1, m2] for window size=1 - require.Equal(t, "22.499998", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "22.499998", score.String()) // calculate metric for p1 with no scope for window size=1 - require.Equal(t, "37.499998", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "37.499998", score.String()) // calculate metric for p2 with scope=[m1] for window size=1 // 0*(1-0.75)+100*0.75 = 75 - require.Equal(t, "75", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "75", score.String()) // calculate metric for p2 with scope=[m2] for window size=1 // 0*(1-0.5833333333333333)+200*0.5833333333333333 - require.Equal(t, "116.66666", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "116.66666", score.String()) // calculate metric for p2 with scope=[m3] for window size=1 // 0*(1-0.25)+300*0.25 - require.Equal(t, "75", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "75", score.String()) // calculate metric for p2 with scope=[m1, m3] for window size=1 - require.Equal(t, "150", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "150", score.String()) // calculate metric for p2 with no scope for window size=1 - require.Equal(t, "266.66666", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "266.66666", score.String()) // start epoch2 epochService.target(context.Background(), types.Epoch{Seq: 2, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Unix(60, 0)}) @@ -585,61 +595,81 @@ func TestCalculateMetricForPartyAvePosition(t *testing.T) { // calculate metric for p1 with scope=[m1] for window size=1 // 10*(1-0.5)+20*0.5 - require.Equal(t, "15", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "15", score.String()) // calculate metric for p1 with scope=[m2] for window size=1 // 13.333333333333334*(1-1)+20*1 - require.Equal(t, "20", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "20", score.String()) // calculate metric for p1 with scope=[m3] for window size=1 // 15*(1-1)+30*1 = 30 - require.Equal(t, "30", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "30", score.String()) // calculate metric for p1 with scope=[m1, m3] for window size=1 - require.Equal(t, "35", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "35", score.String()) // calculate metric for p1 with no scope for window size=1 - require.Equal(t, "65", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "65", score.String()) // calculate metric for p2 with scope=[m1] for window size=1 // 75*(1-1)+100*1 - require.Equal(t, "100", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "100", score.String()) // calculate metric for p1 with scope=[m2] for window size=1 // 200*(1-0.75)+10*0.75 - require.Equal(t, "57.5", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "57.5", score.String()) // calculate metric for p1 with scope=[m3] for window size=1 // 75*(1-1)+300*1 - require.Equal(t, "300", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "300", score.String()) // calculate metric for p1 with scope=[m1, m3] for window size=1 - require.Equal(t, "157.5", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "157.5", score.String()) // calculate metric for p1 with no scope for window size=1 - require.Equal(t, "457.5", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "457.5", score.String()) // now calculate for window size=2 // calculate metric for p1 with scope=[m1] for window size=2 // (15 + 9.166666666666667)/2 - require.Equal(t, "12.083333", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "12.083333", score.String()) // calculate metric for p1 with scope=[m2] for window size=2 // (13.333333333333334" + 20)/2 - require.Equal(t, "16.666666", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "16.666666", score.String()) // calculate metric for p1 with scope=[m3] for window size=2 // (15 + 30)/2 - require.Equal(t, "22.5", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "22.5", score.String()) // calculate metric for p1 with scope=[m1, m3] for window size=2 - require.Equal(t, "28.749999", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "28.749999", score.String()) // calculate metric for p1 with no scope for window size=2 - require.Equal(t, "51.249999", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "51.249999", score.String()) // calculate metric for p2 with scope=[m1] for window size=2 // (100 + 75)/2 - require.Equal(t, "87.5", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "87.5", score.String()) // calculate metric for p2 with scope=[m2] for window size=2 // (116.66666666666666 + 57.5)/2 - require.Equal(t, "87.08333", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "87.08333", score.String()) // calculate metric for p2 with scope=[m3] for window size=2 // (300 + 75)/2 - require.Equal(t, "187.5", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "187.5", score.String()) // calculate metric for p2 with scope=[m1, m3] for window size=2 - require.Equal(t, "275", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "275", score.String()) // calculate metric for p2 with no scope for window size=2 - require.Equal(t, "362.08333", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 2) + require.Equal(t, "362.08333", score.String()) // start epoch3 epochService.target(context.Background(), types.Epoch{Seq: 3, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Unix(120, 0)}) @@ -647,61 +677,81 @@ func TestCalculateMetricForPartyAvePosition(t *testing.T) { epochService.target(context.Background(), types.Epoch{Seq: 3, Action: vgproto.EpochAction_EPOCH_ACTION_END, StartTime: time.Unix(120, 0), EndTime: time.Unix(180, 0)}) // calculate metric for p1 with scope=[m1] for window size=1 // 15*(1-1)+20*1 - require.Equal(t, "20", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "20", score.String()) // calculate metric for p1 with scope=[m2] for window size=1 // 20*(1-1)+20*1 - require.Equal(t, "20", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "20", score.String()) // calculate metric for p1 with scope=[m3] for window size=1 // 30*(1-1)+30*1 = 30 - require.Equal(t, "30", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "30", score.String()) // calculate metric for p1 with scope=[m1, m3] for window size=1 - require.Equal(t, "40", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "40", score.String()) // calculate metric for p1 with no scope for window size=1 - require.Equal(t, "70", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "70", score.String()) // calculate metric for p2 with scope=[m1] for window size=1 // 100*(1-1)+100*1 - require.Equal(t, "100", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "100", score.String()) // calculate metric for p2 with scope=[m2] for window size=1 // 57.5*(1-1)+10*1 - require.Equal(t, "10", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "10", score.String()) // calculate metric for p2 with scope=[m3] for window size=1 // 300*(1-1)+300*1 - require.Equal(t, "300", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "300", score.String()) // calculate metric for p2 with scope=[m1, m3] for window size=1 - require.Equal(t, "110", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "110", score.String()) // calculate metric for p2 with no scope for window size=1 - require.Equal(t, "410", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 1) + require.Equal(t, "410", score.String()) // now calculate for window size=3 // calculate metric for p1 with scope=[m1] for window size=3 // (9.166666666666667 + 15 + 20)/3 - require.Equal(t, "14.722222", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "14.722222", score.String()) // calculate metric for p1 with scope=[m2] for window size=3 // (13.333333333333334" + 20 + 20)/3 - require.Equal(t, "17.7777773333333333", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "17.7777773333333333", score.String()) // calculate metric for p1 with scope=[m3] for window size=3 // (15 + 30 + 30)/3 - require.Equal(t, "25", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "25", score.String()) // calculate metric for p1 with scope=[m1, m3] for window size=3 - require.Equal(t, "32.4999993333333333", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "32.4999993333333333", score.String()) // calculate metric for p1 with no scope for window size=3 - require.Equal(t, "57.4999993333333333", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "57.4999993333333333", score.String()) // calculate metric for p2 with scope=[m1] for window size=3 // (100 + 75+100)/3 - require.Equal(t, "91.6666666666666667", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "91.6666666666666667", score.String()) // calculate metric for p2 with scope=[m2] for window size=3 // (116.66666666666666 + 57.5 + 10)/3 - require.Equal(t, "61.3888866666666667", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "61.3888866666666667", score.String()) // calculate metric for p2 with scope=[m3] for window size=3 // (300 + 75 + 300)/3 - require.Equal(t, "225", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "225", score.String()) // calculate metric for p2 with scope=[m1, m3] for window size=3 - require.Equal(t, "316.6666666666666667", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "316.6666666666666667", score.String()) // calculate metric for p2 with no scope for window size=3 - require.Equal(t, "378.0555533333333333", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_AVERAGE_POSITION, 3) + require.Equal(t, "378.0555533333333333", score.String()) } func TestCalculateMetricForIndividualReturnVolatility(t *testing.T) { @@ -1082,34 +1132,44 @@ func TestCalculateMetricForPartyRelativeReturn(t *testing.T) { // calculate metric for p1 with scope=[m1] for window size=1 // 150 / 9.166666 - require.Equal(t, "16.3636375537190948", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ := tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "16.3636375537190948", score.String()) // calculate metric for p1 with scope=[m2] for window size=1 // -50 /13.333332 - require.Equal(t, "-3.7500003750000375", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-3.7500003750000375", score.String()) // calculate metric for p1 with scope=[m3] for window size=1 // 100 / 15 - require.Equal(t, "6.6666666666666667", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "6.6666666666666667", score.String()) // calculate metric for p1 with scope=[m1, m2] for window size=1 // 150 / 9.166666 - 50 /13.333332 - require.Equal(t, "12.6136371787", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "12.6136371787", score.StringFixed(10)) // 150 / 9.166666 - 50 /13.333332 +100/15 - require.Equal(t, "19.2803038454", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "19.2803038454", score.StringFixed(10)) // calculate metric for p2 with scope=[m1] for window size=1 // -150 / 75 - require.Equal(t, "-2", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-2", score.String()) // calculate metric for p2 with scope=[m2] for window size=1 // 50 / 116.66666 - require.Equal(t, "0.4285714531", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0.4285714531", score.StringFixed(10)) // calculate metric for p2 with scope=[m3] for window size=1 // -100 / 75 - require.Equal(t, "-1.3333333333", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-1.3333333333", score.StringFixed(10)) // calculate metric for p2 with scope=[m1, m2] for window size=1 // -2 + 0.4285714531 - require.Equal(t, "-1.5714285469", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-1.5714285469", score.StringFixed(10)) // calculate metric for p2 with no scope for window size=1 // -2+0.4285714531-1.3333333333 - require.Equal(t, "-2.9047618803", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-2.9047618803", score.StringFixed(10)) // start epoch2 epochService.target(context.Background(), types.Epoch{Seq: 2, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Unix(60, 0)}) @@ -1129,64 +1189,84 @@ func TestCalculateMetricForPartyRelativeReturn(t *testing.T) { // calculate metric for p1 with scope=[m1] for window size=1 // 450/15=30 - require.Equal(t, "30", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "30", score.String()) // calculate metric for p1 with scope=[m2] for window size=1 // -100/20 - require.Equal(t, "-5", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-5", score.String()) // calculate metric for p1 with scope=[m3] for window size=1 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p1 with scope=[m1, m2] for window size=1 - require.Equal(t, "25", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "25", score.String()) // calculate metric for p1 with no scope for window size=1 - require.Equal(t, "25", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "25", score.String()) // calculate metric for p2 with scope=[m1] for window size=1 // -450/100 - require.Equal(t, "-4.5", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-4.5", score.String()) // calculate metric for p1 with scope=[m2] for window size=1 // 100/57.5 - require.Equal(t, "1.7391304348", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "1.7391304348", score.StringFixed(10)) // calculate metric for p1 with scope=[m3] for window size=1 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p1 with scope=[m1, m3] for window size=1 - require.Equal(t, "-2.7608695652", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-2.7608695652", score.StringFixed(10)) // calculate metric for p1 with no scope for window size=1 - require.Equal(t, "-2.7608695652", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "-2.7608695652", score.StringFixed(10)) // now calculate for window size=2 // calculate metric for p1 with scope=[m1] for window size=2 // (16.3636375537 + 30)/2 - require.Equal(t, "23.1818187768595474", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "23.1818187768595474", score.String()) // calculate metric for p1 with scope=[m2] for window size=2 - require.Equal(t, "-4.3750001875", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "-4.3750001875", score.StringFixed(10)) // calculate metric for p1 with scope=[m3] for window size=2 // (6.6666666666666667 + 0)/2 - require.Equal(t, "3.3333333333", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "3.3333333333", score.StringFixed(10)) // calculate metric for p1 with scope=[m1, m3] for window size=2 - require.Equal(t, "18.8068185894", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "18.8068185894", score.StringFixed(10)) // calculate metric for p1 with no scope for window size=2 - require.Equal(t, "22.1401519227", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "22.1401519227", score.StringFixed(10)) // calculate metric for p2 with scope=[m1] for window size=2 - require.Equal(t, "-3.25", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "-3.25", score.String()) // calculate metric for p2 with scope=[m2] for window size=2 // (0.4285714285714286 + 1.7391304347826087)/2 - require.Equal(t, "1.0838509439", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "1.0838509439", score.StringFixed(10)) // calculate metric for p2 with scope=[m3] for window size=2 - require.Equal(t, "-0.6666666667", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "-0.6666666667", score.StringFixed(10)) // calculate metric for p2 with scope=[m1, m3] for window size=2 - require.Equal(t, "-3.9166666667", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "-3.9166666667", score.StringFixed(10)) // calculate metric for p2 with no scope for window size=2 - require.Equal(t, "-2.8328157227", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 2) + require.Equal(t, "-2.8328157227", score.StringFixed(10)) // start epoch3 epochService.target(context.Background(), types.Epoch{Seq: 3, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Unix(120, 0)}) @@ -1197,58 +1277,78 @@ func TestCalculateMetricForPartyRelativeReturn(t *testing.T) { // calculate metric for p1 with scope=[m1] for window size=1 // 0/20 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p1 with scope=[m2] for window size=1 // 0/20 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p1 with scope=[m3] for window size=1 // 0/30 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p1 with scope=[m1, m3] for window size=1 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p1 with no scope for window size=1 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p2 with scope=[m1] for window size=1 // 0/100 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p2 with scope=[m2] for window size=1 // 0/10 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p2 with scope=[m3] for window size=1 // 0/300 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p2 with scope=[m1, m3] for window size=1 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // calculate metric for p2 with no scope for window size=1 - require.Equal(t, "0", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1).String()) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 1) + require.Equal(t, "0", score.String()) // // now calculate for window size=3 // calculate metric for p1 with scope=[m1] for window size=3 // (16.363636363636363 + 30)/3 - require.Equal(t, "15.4545458512", tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "15.4545458512", score.StringFixed(10)) // calculate metric for p1 with scope=[m2] for window size=3 - require.Equal(t, "-2.9166667917", tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "-2.9166667917", score.StringFixed(10)) // calculate metric for p1 with scope=[m3] for window size=3 // (6.6666666666666667 + 0)/3 - require.Equal(t, "2.2222222222", tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "2.2222222222", score.StringFixed(10)) // calculate metric for p1 with scope=[m1, m3] for window size=3 - require.Equal(t, "12.5378790596", tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{"m1", "m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "12.5378790596", score.StringFixed(10)) // calculate metric for p1 with no scope for window size=3 - require.Equal(t, "14.7601012818", tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p1", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "14.7601012818", score.StringFixed(10)) // calculate metric for p2 with scope=[m1] for window size=3 - require.Equal(t, "-2.1666666667", tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "-2.1666666667", score.StringFixed(10)) // calculate metric for p2 with scope=[m2] for window size=3 // (0.4285714285714286 + 1.7391304347826087 + 0 )/3 - require.Equal(t, "0.7225672959", tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m2"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "0.7225672959", score.StringFixed(10)) // calculate metric for p2 with scope=[m3] for window size=3 - require.Equal(t, "-0.4444444444", tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "-0.4444444444", score.StringFixed(10)) // calculate metric for p2 with scope=[m1, m3] for window size=3 - require.Equal(t, "-2.6111111111", tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{"m1", "m3"}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "-2.6111111111", score.StringFixed(10)) // calculate metric for p2 with no scope for window size=3 - require.Equal(t, "-1.8885438152", tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3).StringFixed(10)) + score, _ = tracker.calculateMetricForParty("a1", "p2", []string{}, vgproto.DispatchMetric_DISPATCH_METRIC_RELATIVE_RETURN, 3) + require.Equal(t, "-1.8885438152", score.StringFixed(10)) } func TestCalculateMetricForParty(t *testing.T) { @@ -1280,7 +1380,8 @@ func TestCalculateMetricForParty(t *testing.T) { } for _, dm := range ds { - require.Equal(t, num.DecimalZero(), tracker.calculateMetricForParty("a1", "p1", []string{}, dm, 1)) + score, _ := tracker.calculateMetricForParty("a1", "p1", []string{}, dm, 1) + require.Equal(t, num.DecimalZero(), score) } } @@ -1292,23 +1393,23 @@ func TestCalculateMetricForTeamUtil(t *testing.T) { } return false } - calculateMetricForParty := func(asset, party string, marketsInScope []string, metric vega.DispatchMetric, windowSize int) num.Decimal { + calculateMetricForParty := func(asset, party string, marketsInScope []string, metric vega.DispatchMetric, windowSize int) (num.Decimal, bool) { if party == "party1" { - return num.DecimalFromFloat(1.5) + return num.DecimalFromFloat(1.5), true } if party == "party2" { - return num.DecimalFromFloat(2) + return num.DecimalFromFloat(2), true } if party == "party3" { - return num.DecimalFromFloat(0.5) + return num.DecimalFromFloat(0.5), true } if party == "party4" { - return num.DecimalFromFloat(2.5) + return num.DecimalFromFloat(2.5), true } if party == "party5" { - return num.DecimalFromFloat(0.8) + return num.DecimalFromFloat(0.8), true } - return num.DecimalZero() + return num.DecimalZero(), false } gameID := "game123" diff --git a/core/integration/features/rewards/0056-REWA-108.feature b/core/integration/features/rewards/0056-REWA-108.feature index 7f50ec1cd8..205477d2fe 100644 --- a/core/integration/features/rewards/0056-REWA-108.feature +++ b/core/integration/features/rewards/0056-REWA-108.feature @@ -80,10 +80,10 @@ Feature: Team Rewards When the network moves ahead "1" epochs Then parties should have the following vesting account balances: | party | asset | balance | - | ref1-0001 | USD-1-10 | 1724 | - | ref1-0002 | USD-1-10 | 1724 | + | ref1-0001 | USD-1-10 | 1428 | + | ref1-0002 | USD-1-10 | 1428 | | ref3-0001 | USD-1-10 | 0 | - | ref3-0002 | USD-1-10 | 2068 | - | ref2-0001 | USD-1-10 | 2241 | - | ref2-0002 | USD-1-10 | 2241 | + | ref3-0002 | USD-1-10 | 3428 | + | ref2-0001 | USD-1-10 | 1857 | + | ref2-0002 | USD-1-10 | 1857 | diff --git a/core/integration/features/rewards/average_position_with_liquidation_reward.feature b/core/integration/features/rewards/average_position_with_liquidation_reward.feature index ac874a8ece..4b802a624a 100644 --- a/core/integration/features/rewards/average_position_with_liquidation_reward.feature +++ b/core/integration/features/rewards/average_position_with_liquidation_reward.feature @@ -105,6 +105,15 @@ Feature: Calculation of average position during closeout trades | aux1 | USD-1-10 | 4000 | | aux2 | USD-1-10 | 2000 | + Given the network moves ahead "1" epochs + # there are still rewards because while the position is 0 at the beginning of the epoch, the timeweighted position will only become 0 + # at the beginning of the next epoch + Then parties should have the following vesting account balances: + | party | asset | balance | + | party1 | USD-1-10 | 3333 | + | aux2 | USD-1-10 | 3333 | + | aux1 | USD-1-10 | 3333 | + Given the network moves ahead "1" epochs # Expect to see no rewards as no positions open at the start of the epoch Then parties should have the following vesting account balances: diff --git a/core/integration/features/rewards/realised_returns.feature b/core/integration/features/rewards/realised_returns.feature new file mode 100644 index 0000000000..00ea2df842 --- /dev/null +++ b/core/integration/features/rewards/realised_returns.feature @@ -0,0 +1,368 @@ +Feature: Realised returns reward metric + + Background: + + Given the average block duration is "1" + And the following network parameters are set: + | name | value | + | validators.epoch.length | 60s | + | market.fee.factors.makerFee | 0.1 | + | network.markPriceUpdateMaximumFrequency | 0s | + + # Setup market and parties + Given the following assets are registered: + | id | decimal places | quantum | + | USDT.0.1 | 0 | 1 | + And the parties deposit on asset's general account the following amount: + | party | asset | amount | + | aux1 | USDT.0.1 | 1000000000 | + | aux2 | USDT.0.1 | 1000000000 | + | party1 | USDT.0.1 | 1000000000 | + | party2 | USDT.0.1 | 1000000000 | + | party3 | USDT.0.1 | 1000000000 | + | party4 | USDT.0.1 | 1000000000 | + | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | USDT.0.1 | 1000000000 | + And the markets: + | id | quote name | asset | risk model | margin calculator | auction duration | fees | price monitoring | data source config | linear slippage factor | quadratic slippage factor | sla params | decimal places | position decimal places | + | ETH/USDT | USDT.0.1 | USDT.0.1 | default-log-normal-risk-model | default-margin-calculator | 1 | default-none | default-none | default-eth-for-future | 1e-3 | 0 | default-futures | 0 | 0 | + + # Exit opening auction and close the positions of the auxiliary parties so they don't receive rewards + Given the parties place the following orders: + | party | market id | side | volume | price | resulting trades | type | tif | + | aux1 | ETH/USDT | buy | 1000 | 1 | 0 | TYPE_LIMIT | TIF_GTC | + | aux1 | ETH/USDT | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | + | aux2 | ETH/USDT | sell | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | + | aux2 | ETH/USDT | sell | 1000 | 1999 | 0 | TYPE_LIMIT | TIF_GTC | + When the opening auction period ends for market "ETH/USDT" + And the parties should have the following profit and loss: + | party | volume | unrealised pnl | realised pnl | + | aux1 | 1 | 0 | 0 | + | aux2 | -1 | 0 | 0 | + And the trading mode should be "TRADING_MODE_CONTINUOUS" for the market "ETH/USDT" + Given the parties place the following orders: + | party | market id | side | volume | price | resulting trades | type | tif | + | aux1 | ETH/USDT | sell | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | + | aux2 | ETH/USDT | buy | 1 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | + When the network moves ahead "1" blocks + And the parties should have the following profit and loss: + | party | volume | unrealised pnl | realised pnl | + | aux1 | 0 | 0 | 0 | + | aux2 | 0 | 0 | 0 | + + +# Scenario: In a falling market where short positions are profitable, parties have only unrealised pnl (0056-REWA-118)(0056-REWA-129) + +# # Set-up a recurring transfer dispatching rewards based on realised profit and loss +# Given the current epoch is "0" +# And the parties submit the following recurring transfers: +# | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | +# | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | +# And the network moves ahead "1" epochs + +# And the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | aux1 | ETH/USDT | buy | 1 | 900 | 0 | TYPE_LIMIT | TIF_GTC | +# | aux2 | ETH/USDT | sell | 1 | 900 | 1 | TYPE_LIMIT | TIF_GTC | +# When the network moves ahead "1" blocks +# Then the parties should have the following profit and loss: +# | party | volume | unrealised pnl | realised pnl | +# | party1 | 10 | -1000 | 0 | +# | party2 | -10 | 1000 | 0 | +# | aux1 | 1 | 0 | 0 | +# | aux2 | -1 | 0 | 0 | +# # Move to the end of the epoch +# Given the network moves ahead "1" epochs +# Then parties should have the following vesting account balances: +# | party | asset | balance | +# | party1 | USDT.0.1 | 0 | +# | party2 | USDT.0.1 | 0 | + + +# Scenario: In a falling market where short positions are profitable, parties have party realised pnl (0056-REWA-119)(0056-REWA-130) + +# # Set-up a recurring transfer dispatching rewards based on realised profit and loss +# Given the current epoch is "0" +# And the parties submit the following recurring transfers: +# | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | +# | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | +# And the network moves ahead "1" epochs + +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | aux1 | ETH/USDT | buy | 1 | 900 | 0 | TYPE_LIMIT | TIF_GTC | +# | aux2 | ETH/USDT | sell | 1 | 900 | 1 | TYPE_LIMIT | TIF_GTC | +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | sell | 5 | 900 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | buy | 5 | 900 | 1 | TYPE_LIMIT | TIF_GTC | +# When the network moves ahead "1" blocks +# Then the parties should have the following profit and loss: +# | party | volume | unrealised pnl | realised pnl | +# | party1 | 5 | -500 | -500 | +# | party2 | -5 | 500 | 500 | +# | aux1 | 1 | 0 | 0 | +# | aux2 | -1 | 0 | 0 | +# # Move to the end of the epoch +# Given the network moves ahead "1" epochs +# Then parties should have the following vesting account balances: +# | party | asset | balance | +# | party1 | USDT.0.1 | 0 | +# | party2 | USDT.0.1 | 10000 | + + +# Scenario: In a falling market where short positions are profitable, parties have fully realised pnl (0056-REWA-120)(0056-REWA-131) + +# # Set-up a recurring transfer dispatching rewards based on realised profit and loss +# Given the current epoch is "0" +# And the parties submit the following recurring transfers: +# | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | +# | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | +# And the network moves ahead "1" epochs + +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | aux1 | ETH/USDT | buy | 1 | 900 | 0 | TYPE_LIMIT | TIF_GTC | +# | aux2 | ETH/USDT | sell | 1 | 900 | 1 | TYPE_LIMIT | TIF_GTC | +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | sell | 10 | 900 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | buy | 10 | 900 | 1 | TYPE_LIMIT | TIF_GTC | +# When the network moves ahead "1" blocks +# Then the parties should have the following profit and loss: +# | party | volume | unrealised pnl | realised pnl | +# | party1 | 0 | 0 | -1000 | +# | party2 | 0 | 0 | 1000 | +# | aux1 | 1 | 0 | 0 | +# | aux2 | -1 | 0 | 0 | +# # Move to the end of the epoch +# Given the network moves ahead "1" epochs +# Then parties should have the following vesting account balances: +# | party | asset | balance | +# | party1 | USDT.0.1 | 0 | +# | party2 | USDT.0.1 | 10000 | + + +# Scenario: In a falling market where short positions are profitable, parties fully realise pnl and switch sides (0056-REWA-132)(0056-REWA-135) + +# # Set-up a recurring transfer dispatching rewards based on realised profit and loss +# Given the current epoch is "0" +# And the parties submit the following recurring transfers: +# | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | +# | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | +# And the network moves ahead "1" epochs + +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | party3 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party4 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | aux1 | ETH/USDT | buy | 1 | 900 | 0 | TYPE_LIMIT | TIF_GTC | +# | aux2 | ETH/USDT | sell | 1 | 900 | 1 | TYPE_LIMIT | TIF_GTC | +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | sell | 10 | 900 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | buy | 10 | 900 | 1 | TYPE_LIMIT | TIF_GTC | +# | party3 | ETH/USDT | sell | 15 | 900 | 0 | TYPE_LIMIT | TIF_GTC | +# | party4 | ETH/USDT | buy | 15 | 900 | 1 | TYPE_LIMIT | TIF_GTC | +# When the network moves ahead "1" blocks +# Then the parties should have the following profit and loss: +# | party | volume | unrealised pnl | realised pnl | +# | party1 | 0 | 0 | -1000 | +# | party2 | 0 | 0 | 1000 | +# | party3 | -5 | 0 | -1000 | +# | party4 | 5 | 0 | 1000 | +# | aux1 | 1 | 0 | 0 | +# | aux2 | -1 | 0 | 0 | +# # Move to the end of the epoch +# Given the network moves ahead "1" epochs +# Then parties should have the following vesting account balances: +# | party | asset | balance | +# | party1 | USDT.0.1 | 0 | +# | party2 | USDT.0.1 | 5000 | +# | party3 | USDT.0.1 | 0 | +# | party4 | USDT.0.1 | 5000 | + + +# Scenario: In a rising market where long positions are profitable, parties have only unrealised pnl (0056-REWA-122)(0056-REWA-125) + +# # Set-up a recurring transfer dispatching rewards based on realised profit and loss +# Given the current epoch is "0" +# And the parties submit the following recurring transfers: +# | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | +# | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | +# And the network moves ahead "1" epochs + +# And the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | aux1 | ETH/USDT | buy | 1 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | +# | aux2 | ETH/USDT | sell | 1 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | +# When the network moves ahead "1" blocks +# Then the parties should have the following profit and loss: +# | party | volume | unrealised pnl | realised pnl | +# | party1 | 10 | 1000 | 0 | +# | party2 | -10 | -1000 | 0 | +# | aux1 | 1 | 0 | 0 | +# | aux2 | -1 | 0 | 0 | +# # Move to the end of the epoch +# Given the network moves ahead "1" epochs +# Then parties should have the following vesting account balances: +# | party | asset | balance | +# | party1 | USDT.0.1 | 0 | +# | party2 | USDT.0.1 | 0 | + + +# Scenario: In a rising market where long positions are profitable, parties have party realised pnl (0056-REWA-123)(0056-REWA-126) + +# # Set-up a recurring transfer dispatching rewards based on realised profit and loss +# Given the current epoch is "0" +# And the parties submit the following recurring transfers: +# | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | +# | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | +# And the network moves ahead "1" epochs + +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | aux1 | ETH/USDT | buy | 1 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | +# | aux2 | ETH/USDT | sell | 1 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | sell | 5 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | buy | 5 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | +# When the network moves ahead "1" blocks +# Then the parties should have the following profit and loss: +# | party | volume | unrealised pnl | realised pnl | +# | party1 | 5 | 500 | 500 | +# | party2 | -5 | -500 | -500 | +# | aux1 | 1 | 0 | 0 | +# | aux2 | -1 | 0 | 0 | +# # Move to the end of the epoch +# Given the network moves ahead "1" epochs +# Then parties should have the following vesting account balances: +# | party | asset | balance | +# | party1 | USDT.0.1 | 10000 | +# | party2 | USDT.0.1 | 0 | + + +# Scenario: In a rising market where long positions are profitable, parties have fully realised pnl (0056-REWA-124)(0056-REWA-127) + +# # Set-up a recurring transfer dispatching rewards based on realised profit and loss +# Given the current epoch is "0" +# And the parties submit the following recurring transfers: +# | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | +# | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | +# And the network moves ahead "1" epochs + +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | aux1 | ETH/USDT | buy | 1 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | +# | aux2 | ETH/USDT | sell | 1 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | sell | 10 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | buy | 10 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | +# When the network moves ahead "1" blocks +# Then the parties should have the following profit and loss: +# | party | volume | unrealised pnl | realised pnl | +# | party1 | 0 | 0 | 1000 | +# | party2 | 0 | 0 | -1000 | +# | aux1 | 1 | 0 | 0 | +# | aux2 | -1 | 0 | 0 | +# # Move to the end of the epoch +# Given the network moves ahead "1" epochs +# Then parties should have the following vesting account balances: +# | party | asset | balance | +# | party1 | USDT.0.1 | 10000 | +# | party2 | USDT.0.1 | 0 | + + +# Scenario: In a rising market where long positions are profitable, parties fully realise pnl and switch sides (0056-REWA-133)(0056-REWA-134) + +# # Set-up a recurring transfer dispatching rewards based on realised profit and loss +# Given the current epoch is "0" +# And the parties submit the following recurring transfers: +# | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | +# | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | +# And the network moves ahead "1" epochs + +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | party3 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | +# | party4 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | +# | aux1 | ETH/USDT | buy | 1 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | +# | aux2 | ETH/USDT | sell | 1 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | +# Given the parties place the following orders: +# | party | market id | side | volume | price | resulting trades | type | tif | +# | party1 | ETH/USDT | sell | 10 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | +# | party2 | ETH/USDT | buy | 10 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | +# | party3 | ETH/USDT | sell | 15 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | +# | party4 | ETH/USDT | buy | 15 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | +# When the network moves ahead "1" blocks +# Then the parties should have the following profit and loss: +# | party | volume | unrealised pnl | realised pnl | +# | party1 | 0 | 0 | 1000 | +# | party2 | 0 | 0 | -1000 | +# | party3 | -5 | 0 | 1000 | +# | party4 | 5 | 0 | -1000 | +# | aux1 | 1 | 0 | 0 | +# | aux2 | -1 | 0 | 0 | +# # Move to the end of the epoch +# Given the network moves ahead "1" epochs +# Then parties should have the following vesting account balances: +# | party | asset | balance | +# | party1 | USDT.0.1 | 5000 | +# | party2 | USDT.0.1 | 0 | +# | party3 | USDT.0.1 | 5000 | +# | party4 | USDT.0.1 | 0 | + + + Scenario: Parties with long and short positions open and close position at same price, they have 0 realised returns but should still receive rewards (0056-REWA-121)(0056-REWA-128) + + # Set-up a recurring transfer dispatching rewards based on realised profit and loss + Given the current epoch is "0" + And the parties submit the following recurring transfers: + | id | from | from_account_type | to | to_account_type | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | + | reward | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_REALISED_RETURN | USDT.0.1 | 10000 | 1 | | 1 | DISPATCH_METRIC_REALISED_RETURN | USDT.0.1 | ETH/USDT | 100 | + And the network moves ahead "1" epochs + + Given the parties place the following orders: + | party | market id | side | volume | price | resulting trades | type | tif | + | party1 | ETH/USDT | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | + | party2 | ETH/USDT | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | + | party3 | ETH/USDT | buy | 10 | 1100 | 0 | TYPE_LIMIT | TIF_GTC | + | party4 | ETH/USDT | sell | 10 | 1100 | 1 | TYPE_LIMIT | TIF_GTC | + Given the parties place the following orders: + | party | market id | side | volume | price | resulting trades | type | tif | + | party1 | ETH/USDT | sell | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | + | party2 | ETH/USDT | buy | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | + | party3 | ETH/USDT | sell | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | + | party4 | ETH/USDT | buy | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | + When the network moves ahead "1" blocks + Then the parties should have the following profit and loss: + | party | volume | unrealised pnl | realised pnl | + | party1 | 0 | 0 | 0 | + | party2 | 0 | 0 | 0 | + | party3 | 0 | 0 | -1000 | + | party4 | 0 | 0 | 1000 | + # Move to the end of the epoch + Given the network moves ahead "1" epochs + Then parties should have the following vesting account balances: + | party | asset | balance | + | party1 | USDT.0.1 | 2500 | + | party2 | USDT.0.1 | 2500 | + | party3 | USDT.0.1 | 0 | + | party4 | USDT.0.1 | 5000 | \ No newline at end of file diff --git a/core/integration/features/rewards/team-rewards.feature b/core/integration/features/rewards/team-rewards.feature index d9b6e0ab3b..71ed25d1ea 100644 --- a/core/integration/features/rewards/team-rewards.feature +++ b/core/integration/features/rewards/team-rewards.feature @@ -86,9 +86,9 @@ Feature: Team Rewards | aux1 | ETH/USD-1-10 | sell | 5 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | | referee3 | ETH/USD-1-10 | buy | 5 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | When the network moves ahead "1" epochs - Then "referee1" should have vesting account balance of "5000" for asset "USD-1-10" - And "referee2" should have vesting account balance of "2500" for asset "USD-1-10" - And "referee3" should have vesting account balance of "2500" for asset "USD-1-10" + Then "referee1" should have vesting account balance of "5714" for asset "USD-1-10" + And "referee2" should have vesting account balance of "2142" for asset "USD-1-10" + And "referee3" should have vesting account balance of "2142" for asset "USD-1-10" diff --git a/core/integration/features/teams/0083-RFPR-062.feature b/core/integration/features/teams/0083-RFPR-062.feature index 9595657fac..f956d6174f 100644 --- a/core/integration/features/teams/0083-RFPR-062.feature +++ b/core/integration/features/teams/0083-RFPR-062.feature @@ -109,6 +109,6 @@ Feature: Test allow lists, based on team_rewards.feature test in rewards set. | aux1 | ETH/USD-1-10 | sell | 5 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | | referee3 | ETH/USD-1-10 | buy | 5 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | When the network moves ahead "1" epochs - Then "referee1" should have vesting account balance of "3999" for asset "USD-1-10" - And "referee2" should have vesting account balance of "3000" for asset "USD-1-10" - And "referee3" should have vesting account balance of "3000" for asset "USD-1-10" + Then "referee1" should have vesting account balance of "5714" for asset "USD-1-10" + And "referee2" should have vesting account balance of "2142" for asset "USD-1-10" + And "referee3" should have vesting account balance of "2142" for asset "USD-1-10" diff --git a/core/integration/features/teams/0083-RFPR-063.feature b/core/integration/features/teams/0083-RFPR-063.feature index 992ec64139..549d8c44e8 100644 --- a/core/integration/features/teams/0083-RFPR-063.feature +++ b/core/integration/features/teams/0083-RFPR-063.feature @@ -108,9 +108,9 @@ Feature: Test allow lists, based on team_rewards.feature test in rewards set. | aux1 | ETH/USD-1-10 | sell | 5 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | | referee3 | ETH/USD-1-10 | buy | 5 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | When the network moves ahead "1" epochs - Then "referee1" should have vesting account balance of "5000" for asset "USD-1-10" - And "referee2" should have vesting account balance of "2500" for asset "USD-1-10" - And "referee3" should have vesting account balance of "2500" for asset "USD-1-10" + Then "referee1" should have vesting account balance of "5714" for asset "USD-1-10" + And "referee2" should have vesting account balance of "2142" for asset "USD-1-10" + And "referee3" should have vesting account balance of "2142" for asset "USD-1-10" @Closed Scenario: 0083-RFPR-063 Joining a closed team while not on the allow list should fail, team with non-empty join list @@ -141,7 +141,7 @@ Feature: Test allow lists, based on team_rewards.feature test in rewards set. | aux1 | ETH/USD-1-10 | sell | 5 | 1000 | 0 | TYPE_LIMIT | TIF_GTC | | referee3 | ETH/USD-1-10 | buy | 5 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | When the network moves ahead "1" epochs - Then "referee1" should have vesting account balance of "5000" for asset "USD-1-10" - And "referee2" should have vesting account balance of "2500" for asset "USD-1-10" - And "referee3" should have vesting account balance of "2500" for asset "USD-1-10" + Then "referee1" should have vesting account balance of "5714" for asset "USD-1-10" + And "referee2" should have vesting account balance of "2142" for asset "USD-1-10" + And "referee3" should have vesting account balance of "2142" for asset "USD-1-10" diff --git a/core/integration/features/verified/rewards-over-window.feature b/core/integration/features/verified/rewards-over-window.feature index 8f184b9ea5..1c80de7477 100644 --- a/core/integration/features/verified/rewards-over-window.feature +++ b/core/integration/features/verified/rewards-over-window.feature @@ -111,6 +111,8 @@ Feature: Maker fees paid reward metric calculated correctly for time window | referee3 | ETH/USD-1-10 | buy | 5 | 1000 | 1 | TYPE_LIMIT | TIF_GTC | When the network moves ahead "1" epochs - Then "referee1" should have vesting account balance of "5000" for asset "USD-1-10" - And "referee2" should have vesting account balance of "2500" for asset "USD-1-10" - And "referee3" should have vesting account balance of "2500" for asset "USD-1-10" + # NB: the change here is because before we were returning the score for fees paid for 0 so when choosing the top n members we'd be looking at the top 2 scores out of the 3 + # so team2 would get a score of 0.6, now they get 0.3, and team1 gets 0.4 so team1 gets 0.4/0.7 and team2 gets 0.3/0.7 + Then "referee1" should have vesting account balance of "5714" for asset "USD-1-10" + And "referee2" should have vesting account balance of "2142" for asset "USD-1-10" + And "referee3" should have vesting account balance of "2142" for asset "USD-1-10" diff --git a/core/rewards/reward_distribution.go b/core/rewards/reward_distribution.go index 98cc6e3d4d..e500bbd80b 100644 --- a/core/rewards/reward_distribution.go +++ b/core/rewards/reward_distribution.go @@ -36,7 +36,7 @@ func adjustScoreForNegative(partyScores []*types.PartyContributionScore) []*type } } - if minScore.IsPositive() { + if !minScore.IsNegative() { return partyScores }