Skip to content

Commit

Permalink
fix: correct calculation of party market fees
Browse files Browse the repository at this point in the history
  • Loading branch information
ze97286 committed Sep 12, 2024
1 parent 2f119c3 commit 296a58f
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 23 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@
- [11650](https://github.com/vegaprotocol/vega/issues/11650) - Add include sub accounts flag to `listPositions`.
- [11641](https://github.com/vegaprotocol/vega/issues/11641) - Panic with pegged orders.
- [11646](https://github.com/vegaprotocol/vega/issues/11646) - Add tier numbers to API.
- [11665](https://github.com/vegaprotocol/vega/issues/11665) - Delay the final termination of a transfer to the following epoch.
- [11679](https://github.com/vegaprotocol/vega/issues/11679) - Fix calculation of fees in party `stats`.
- [11665](https://github.com/vegaprotocol/vega/issues/11665) - Delay the final termination of a transfer to the following epoch.


## 0.78.1

### 🐛 Fixes
Expand Down
73 changes: 51 additions & 22 deletions datanode/service/party_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,10 @@ func (s *PSvc) GetPartyStats(ctx context.Context, partyID string, markets []stri
lastE := uint64(epoch.ID - 1)

data := &v2.GetPartyDiscountStatsResponse{}
pfFactors := partyFeeFactors{}
rfDiscountFactors := partyFeeFactors{}
rfRewardFactors := partyFeeFactors{}
vdDiscountFactors := partyFeeFactors{}

// now that we've gotten the epoch and all markets, get the party stats.
// 1. referral set stats.
refStats, _, err := s.ref.GetReferralSetStats(ctx, nil, &lastE, ptr.From(entities.PartyID(partyID)), entities.DefaultCursorPagination(true))
Expand All @@ -130,7 +133,7 @@ func (s *PSvc) GetPartyStats(ctx context.Context, partyID string, markets []stri
if err != nil {
return nil, err
}
if err := addRefFeeFactors(&pfFactors, refStats[0]); err != nil {
if err := setRefFeeFactors(&rfRewardFactors, &rfDiscountFactors, refStats[0]); err != nil {
return nil, err
}
if tier != nil {
Expand All @@ -147,7 +150,7 @@ func (s *PSvc) GetPartyStats(ctx context.Context, partyID string, markets []stri
if err != nil {
return nil, err
}
if err := addVolFeeFactors(&pfFactors, vdStats[0]); err != nil {
if err := setVolFeeFactors(&vdDiscountFactors, vdStats[0]); err != nil {
return nil, err
}
if tier != nil {
Expand All @@ -159,51 +162,53 @@ func (s *PSvc) GetPartyStats(ctx context.Context, partyID string, markets []stri
if err != nil {
return nil, err
}
var rebate num.Decimal
if len(vrStats) > 0 {
tier, err := s.getVolumeRebateTier(ctx, vrStats[0])
if err != nil {
return nil, err
}
rebate, err := num.DecimalFromString(vrStats[0].AdditionalRebate)
rebate, err = num.DecimalFromString(vrStats[0].AdditionalRebate)
if err != nil {
return nil, err
}
pfFactors.rebate = rebate
if tier != nil {
data.VolumeRebateTier = *tier.TierNumber
}
}
for _, mkt := range mkts {
// @TODO ensure non-nil slice!
if err := setMarketFees(data, mkt, pfFactors); err != nil {
if err := setMarketFees(data, mkt, rfDiscountFactors, rfRewardFactors, vdDiscountFactors, rebate); err != nil {
return nil, err
}
}
return data, nil
}

func setMarketFees(data *v2.GetPartyDiscountStatsResponse, mkt entities.Market, factors partyFeeFactors) error {
maker, infra, liquidity, err := feeFactors(mkt)
func setMarketFees(data *v2.GetPartyDiscountStatsResponse, mkt entities.Market, rfDiscount, rfRewards, vdFactors partyFeeFactors, rebate num.Decimal) error {
maker, infra, liquidity, bb, treasury, err := feeFactors(mkt)
if err != nil {
return err
}
// undiscounted
base := num.DecimalZero().Add(maker).Add(infra).Add(liquidity)
base := num.DecimalZero().Add(maker).Add(infra).Add(liquidity).Add(bb).Add(treasury)
// discounted
discounted := num.DecimalZero().Add(maker.Sub(factors.maker)).
Add(infra.Sub(factors.infra)).
Add(liquidity.Sub(factors.liquidity))
discountedMaker := maker.Mul(num.DecimalOne().Sub(rfDiscount.maker)).Mul(num.DecimalOne().Sub(vdFactors.maker)).Mul(num.DecimalOne().Sub(rfRewards.maker))
discountedInfra := infra.Mul(num.DecimalOne().Sub(rfDiscount.infra)).Mul(num.DecimalOne().Sub(vdFactors.infra)).Mul(num.DecimalOne().Sub(rfRewards.infra))
discountedLiquidity := liquidity.Mul(num.DecimalOne().Sub(rfDiscount.liquidity)).Mul(num.DecimalOne().Sub(vdFactors.liquidity)).Mul(num.DecimalOne().Sub(rfRewards.liquidity))
discounted := discountedMaker.Add(discountedInfra).Add(discountedLiquidity).Add(bb).Add(treasury)

data.PartyMarketFees = append(data.PartyMarketFees, &v2.MarketFees{
MarketId: mkt.ID.String(),
UndiscountedTakerFee: base.String(),
DiscountedTakerFee: discounted.String(),
BaseMakerRebate: maker.String(),
UserMakerRebate: maker.Add(factors.rebate).String(),
UserMakerRebate: maker.Add(rebate).String(),
})
return nil
}

func feeFactors(mkt entities.Market) (maker, infra, liquidity num.Decimal, err error) {
func feeFactors(mkt entities.Market) (maker, infra, liquidity, bb, treasury num.Decimal, err error) {
if maker, err = num.DecimalFromString(mkt.Fees.Factors.MakerFee); err != nil {
return
}
Expand All @@ -213,44 +218,68 @@ func feeFactors(mkt entities.Market) (maker, infra, liquidity num.Decimal, err e
if liquidity, err = num.DecimalFromString(mkt.Fees.Factors.LiquidityFee); err != nil {
return
}
if bb, err = num.DecimalFromString(mkt.Fees.Factors.BuyBackFee); err != nil {
return
}
if treasury, err = num.DecimalFromString(mkt.Fees.Factors.TreasuryFee); err != nil {
return
}

return
}

func addRefFeeFactors(ff *partyFeeFactors, stats entities.FlattenReferralSetStats) error {
func setRefFeeFactors(rewards, discounts *partyFeeFactors, stats entities.FlattenReferralSetStats) error {
maker, err := num.DecimalFromString(stats.RewardFactors.MakerRewardFactor)
if err != nil {
return err
}
ff.maker = ff.maker.Add(maker)
rewards.maker = maker
infra, err := num.DecimalFromString(stats.RewardFactors.InfrastructureRewardFactor)
if err != nil {
return err
}
ff.infra = ff.infra.Add(infra)
rewards.infra = infra
liquidity, err := num.DecimalFromString(stats.RewardFactors.LiquidityRewardFactor)
if err != nil {
return err
}
ff.liquidity = ff.liquidity.Add(liquidity)
rewards.liquidity = liquidity

dmaker, err := num.DecimalFromString(stats.DiscountFactors.MakerDiscountFactor)
if err != nil {
return err
}
discounts.maker = dmaker
dinfra, err := num.DecimalFromString(stats.DiscountFactors.InfrastructureDiscountFactor)
if err != nil {
return err
}
discounts.infra = dinfra
dliquidity, err := num.DecimalFromString(stats.DiscountFactors.LiquidityDiscountFactor)
if err != nil {
return err
}
discounts.liquidity = dliquidity

return nil
}

func addVolFeeFactors(ff *partyFeeFactors, stats entities.FlattenVolumeDiscountStats) error {
func setVolFeeFactors(ff *partyFeeFactors, stats entities.FlattenVolumeDiscountStats) error {
maker, err := num.DecimalFromString(stats.DiscountFactors.MakerDiscountFactor)
if err != nil {
return err
}
ff.maker = ff.maker.Add(maker)
ff.maker = maker
infra, err := num.DecimalFromString(stats.DiscountFactors.InfrastructureDiscountFactor)
if err != nil {
return err
}
ff.infra = ff.infra.Add(infra)
ff.infra = infra
liquidity, err := num.DecimalFromString(stats.DiscountFactors.LiquidityDiscountFactor)
if err != nil {
return err
}
ff.liquidity = ff.liquidity.Add(liquidity)
ff.liquidity = liquidity
return nil
}

Expand Down
56 changes: 56 additions & 0 deletions datanode/service/party_stats_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package service

Check failure on line 1 in datanode/service/party_stats_test.go

View workflow job for this annotation

GitHub Actions / lint

Missed header for check (goheader)

import (
"testing"

"code.vegaprotocol.io/vega/datanode/entities"
"code.vegaprotocol.io/vega/libs/num"
v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2"

Check failure on line 8 in datanode/service/party_stats_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s prefix(code.vegaprotocol.io/vega) -s default -s blank -s dot --custom-order (gci)
"github.com/stretchr/testify/require"
)

func TestPartyFees(t *testing.T) {
data := &v2.GetPartyDiscountStatsResponse{}
mkt := entities.Market{
ID: entities.MarketID("1234"),
Fees: entities.Fees{
Factors: &entities.FeeFactors{
MakerFee: "0.0002",
InfrastructureFee: "0.0005",
LiquidityFee: "0.00001",
TreasuryFee: "0.0003",
BuyBackFee: "0.0001",
},
},
}
rfDiscount := partyFeeFactors{
maker: num.DecimalFromFloat(0.01),
infra: num.DecimalFromFloat(0.02),
liquidity: num.DecimalFromFloat(0.03),
}
rfReward := partyFeeFactors{
maker: num.DecimalFromFloat(0.001),
infra: num.DecimalFromFloat(0.002),
liquidity: num.DecimalFromFloat(0.003),
}
vdFactors := partyFeeFactors{
maker: num.DecimalFromFloat(0.0001),
infra: num.DecimalFromFloat(0.0002),
liquidity: num.DecimalFromFloat(0.0003),
}
rebate := num.DecimalFromFloat(0.005)
setMarketFees(data, mkt, rfDiscount, rfReward, vdFactors, rebate)
require.Equal(t, 1, len(data.PartyMarketFees))
// 0.0002 + 0.0005 + 0.00001 + 0.0003 + 0.0001
require.Equal(t, "0.00111", data.PartyMarketFees[0].UndiscountedTakerFee)

// 0.0002 * (1-0.01) * (1 - 0.0001) * (1 - 0.001) +
// 0.0005 * (1-0.02) * (1 - 0.0002) * (1 - 0.002) +
// 0.00001 * (1-0.03) * (1 - 0.0003) * (1 - 0.003) +
// 0.0003 +
// 0.0001 =
// 0.0001977822198 + 0.000488922196 + 0.00000966799873 + 0.0003 + 0.0001 = 0.00109637241453
require.Equal(t, "0.00109637241453", data.PartyMarketFees[0].DiscountedTakerFee)
require.Equal(t, "0.0002", data.PartyMarketFees[0].BaseMakerRebate)
require.Equal(t, "0.0052", data.PartyMarketFees[0].UserMakerRebate)
}

0 comments on commit 296a58f

Please sign in to comment.