code.vegaprotocol.io/vega@v0.79.0/core/execution/amm/estimator_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package amm
    17  
    18  import (
    19  	"testing"
    20  
    21  	"code.vegaprotocol.io/vega/libs/num"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  )
    25  
    26  func TestEstimateSeparateFunctions(t *testing.T) {
    27  	balance := num.NewUint(100)
    28  	lowerPrice := num.NewUint(900)
    29  	basePrice := num.NewUint(1000)
    30  	upperPrice := num.NewUint(1300)
    31  	leverageAtUpper := num.NewDecimalFromFloat(1.00)
    32  	leverageAtLower := num.NewDecimalFromFloat(5.00)
    33  	sqrter := NewSqrter()
    34  
    35  	shortRiskFactor := num.NewDecimalFromFloat(0.01)
    36  	longRiskFactor := num.NewDecimalFromFloat(0.01)
    37  	linearSlippage := num.NewDecimalFromFloat(0.05)
    38  	initialMargin := num.DecimalOne()
    39  
    40  	// test liquidity unit
    41  	unitLower := LiquidityUnit(sqrter, basePrice, lowerPrice)
    42  	unitUpper := LiquidityUnit(sqrter, upperPrice, basePrice)
    43  
    44  	assert.Equal(t, num.DecimalFromFloat(584.6049894).String(), unitLower.Round(7).String())
    45  	assert.Equal(t, num.DecimalFromFloat(257.2170745).String(), unitUpper.Round(7).String())
    46  
    47  	// test average entry price
    48  	avgEntryLower := AverageEntryPrice(sqrter, unitLower, basePrice)
    49  	avgEntryUpper := AverageEntryPrice(sqrter, unitUpper, upperPrice)
    50  	assert.Equal(t, num.DecimalFromFloat(948.683).String(), avgEntryLower.Round(3).String())
    51  	assert.Equal(t, num.DecimalFromFloat(1140.175).String(), avgEntryUpper.Round(3).String())
    52  
    53  	// test risk factor
    54  	riskFactorLower := RiskFactor(leverageAtLower, longRiskFactor, linearSlippage, initialMargin)
    55  	riskFactorUpper := RiskFactor(leverageAtUpper, shortRiskFactor, linearSlippage, initialMargin)
    56  	assert.Equal(t, leverageAtLower.String(), riskFactorLower.String())
    57  	assert.Equal(t, leverageAtUpper.String(), riskFactorUpper.String())
    58  
    59  	lowerPriceD := lowerPrice.ToDecimal()
    60  	upperPriceD := upperPrice.ToDecimal()
    61  
    62  	// test position at bounds
    63  	lowerBoundPos := PositionAtLowerBound(riskFactorLower, balance.ToDecimal(), lowerPriceD, avgEntryLower, num.DecimalOne())
    64  	upperBoundPos := PositionAtUpperBound(riskFactorUpper, balance.ToDecimal(), upperPriceD, avgEntryUpper, num.DecimalOne())
    65  	assert.Equal(t, num.DecimalFromFloat(0.437).String(), lowerBoundPos.Round(3).String())
    66  	assert.Equal(t, num.DecimalFromFloat(-0.069).String(), upperBoundPos.Round(3).String())
    67  
    68  	// test loss on commitment
    69  	lossAtLower := LossOnCommitment(avgEntryLower, lowerPriceD, lowerBoundPos)
    70  	lossAtUpper := LossOnCommitment(avgEntryUpper, upperPriceD, upperBoundPos)
    71  	assert.Equal(t, num.DecimalFromFloat(21.28852368).String(), lossAtLower.Round(8).String())
    72  	assert.Equal(t, num.DecimalFromFloat(10.94820416).String(), lossAtUpper.Round(8).String())
    73  
    74  	linearSlippageFactor := num.DecimalZero()
    75  
    76  	// test liquidation price
    77  	liquidationPriceAtLower := LiquidationPrice(balance.ToDecimal(), lossAtLower, lowerBoundPos, lowerPriceD, linearSlippageFactor, longRiskFactor)
    78  	liquidationPriceAtUpper := LiquidationPrice(balance.ToDecimal(), lossAtUpper, upperBoundPos, upperPriceD, linearSlippageFactor, shortRiskFactor)
    79  	assert.Equal(t, num.DecimalFromFloat(727.2727273).String(), liquidationPriceAtLower.Round(7).String())
    80  	assert.Equal(t, num.DecimalFromFloat(2574.257426).String(), liquidationPriceAtUpper.Round(6).String())
    81  }
    82  
    83  func TestEstimate(t *testing.T) {
    84  	initialMargin := num.DecimalFromFloat(1)
    85  	riskFactorShort := num.DecimalFromFloat(0.01)
    86  	riskFactorLong := num.DecimalFromFloat(0.01)
    87  	linearSlippageFactor := num.DecimalFromFloat(0)
    88  	sqrter := NewSqrter()
    89  
    90  	t.Run("test 0014-NP-VAMM-001", func(t *testing.T) {
    91  		lowerPrice := num.NewUint(900)
    92  		basePrice := num.NewUint(1000)
    93  		upperPrice := num.NewUint(1100)
    94  		leverageUpper := num.DecimalFromFloat(2.00)
    95  		leverageLower := num.DecimalFromFloat(2.00)
    96  		balance := num.NewUint(100)
    97  
    98  		expectedMetrics := EstimatedBounds{
    99  			PositionSizeAtUpper:     num.DecimalFromFloat(-0.166),
   100  			PositionSizeAtLower:     num.DecimalFromFloat(0.201),
   101  			LossOnCommitmentAtUpper: num.DecimalFromFloat(8.515),
   102  			LossOnCommitmentAtLower: num.DecimalFromFloat(9.762),
   103  			LiquidationPriceAtUpper: num.DecimalFromFloat(1633.663),
   104  			LiquidationPriceAtLower: num.DecimalFromFloat(454.545),
   105  		}
   106  
   107  		metrics := EstimateBounds(
   108  			sqrter,
   109  			lowerPrice,
   110  			basePrice,
   111  			upperPrice,
   112  			leverageLower,
   113  			leverageUpper,
   114  			balance,
   115  			linearSlippageFactor,
   116  			initialMargin,
   117  			riskFactorShort,
   118  			riskFactorLong,
   119  			num.DecimalOne(),
   120  			num.DecimalOne(),
   121  			0,
   122  		)
   123  
   124  		assert.Equal(t, expectedMetrics.PositionSizeAtUpper.String(), metrics.PositionSizeAtUpper.Round(3).String())
   125  		assert.Equal(t, expectedMetrics.PositionSizeAtLower.String(), metrics.PositionSizeAtLower.Round(3).String())
   126  		assert.Equal(t, expectedMetrics.LossOnCommitmentAtUpper.String(), metrics.LossOnCommitmentAtUpper.Round(3).String())
   127  		assert.Equal(t, expectedMetrics.LossOnCommitmentAtLower.String(), metrics.LossOnCommitmentAtLower.Round(3).String())
   128  		assert.Equal(t, expectedMetrics.LiquidationPriceAtUpper.String(), metrics.LiquidationPriceAtUpper.Round(3).String())
   129  		assert.Equal(t, expectedMetrics.LiquidationPriceAtLower.String(), metrics.LiquidationPriceAtLower.Round(3).String())
   130  		assert.True(t, metrics.TooWideLower)
   131  		assert.True(t, metrics.TooWideUpper)
   132  	})
   133  
   134  	t.Run("test 0014-NP-VAMM-004", func(t *testing.T) {
   135  		lowerPrice := num.NewUint(900)
   136  		basePrice := num.NewUint(1000)
   137  		upperPrice := num.NewUint(1300)
   138  		leverageUpper := num.DecimalFromFloat(1)
   139  		leverageLower := num.DecimalFromFloat(5)
   140  		balance := num.NewUint(100)
   141  
   142  		expectedMetrics := EstimatedBounds{
   143  			PositionSizeAtUpper:     num.DecimalFromFloat(-0.069),
   144  			PositionSizeAtLower:     num.DecimalFromFloat(0.437),
   145  			LossOnCommitmentAtUpper: num.DecimalFromFloat(10.948),
   146  			LossOnCommitmentAtLower: num.DecimalFromFloat(21.289),
   147  			LiquidationPriceAtUpper: num.DecimalFromFloat(2574.257),
   148  			LiquidationPriceAtLower: num.DecimalFromFloat(727.273),
   149  		}
   150  
   151  		metrics := EstimateBounds(
   152  			sqrter,
   153  			lowerPrice,
   154  			basePrice,
   155  			upperPrice,
   156  			leverageLower,
   157  			leverageUpper,
   158  			balance,
   159  			linearSlippageFactor,
   160  			initialMargin,
   161  			riskFactorShort,
   162  			riskFactorLong,
   163  			num.DecimalOne(),
   164  			num.DecimalOne(),
   165  			0,
   166  		)
   167  
   168  		assert.Equal(t, expectedMetrics.PositionSizeAtUpper.String(), metrics.PositionSizeAtUpper.Round(3).String())
   169  		assert.Equal(t, expectedMetrics.PositionSizeAtLower.String(), metrics.PositionSizeAtLower.Round(3).String())
   170  		assert.Equal(t, expectedMetrics.LossOnCommitmentAtUpper.String(), metrics.LossOnCommitmentAtUpper.Round(3).String())
   171  		assert.Equal(t, expectedMetrics.LossOnCommitmentAtLower.String(), metrics.LossOnCommitmentAtLower.Round(3).String())
   172  		assert.Equal(t, expectedMetrics.LiquidationPriceAtUpper.String(), metrics.LiquidationPriceAtUpper.Round(3).String())
   173  		assert.Equal(t, expectedMetrics.LiquidationPriceAtLower.String(), metrics.LiquidationPriceAtLower.Round(3).String())
   174  	})
   175  }
   176  
   177  func TestEstimatePositionFactor(t *testing.T) {
   178  	initialMargin := num.DecimalFromFloat(1.2)
   179  	riskFactorShort := num.DecimalFromFloat(0.05529953589167391)
   180  	riskFactorLong := num.DecimalFromFloat(0.05529953589167391)
   181  	linearSlippageFactor := num.DecimalFromFloat(0.01)
   182  	sqrter := NewSqrter()
   183  
   184  	lowerPrice := num.MustUintFromString("80000000000000000000", 10)
   185  	basePrice := num.MustUintFromString("100000000000000000000", 10)
   186  	upperPrice := num.MustUintFromString("120000000000000000000", 10)
   187  	leverageUpper := num.DecimalFromFloat(0.5)
   188  	leverageLower := num.DecimalFromFloat(0.5)
   189  	balance := num.MustUintFromString("390500000000000000000000000", 10)
   190  
   191  	expectedMetrics := EstimatedBounds{
   192  		PositionSizeAtUpper: num.DecimalFromFloat(-1559159.284),
   193  		PositionSizeAtLower: num.DecimalFromFloat(2304613.63),
   194  	}
   195  
   196  	metrics := EstimateBounds(
   197  		sqrter,
   198  		lowerPrice,
   199  		basePrice,
   200  		upperPrice,
   201  		leverageLower,
   202  		leverageUpper,
   203  		balance,
   204  		linearSlippageFactor,
   205  		initialMargin,
   206  		riskFactorShort,
   207  		riskFactorLong,
   208  		num.DecimalFromInt64(1000000000000000000),
   209  		num.DecimalOne(),
   210  		0,
   211  	)
   212  
   213  	assert.Equal(t, expectedMetrics.PositionSizeAtUpper.String(), metrics.PositionSizeAtUpper.Round(3).String())
   214  	assert.Equal(t, expectedMetrics.PositionSizeAtLower.String(), metrics.PositionSizeAtLower.Round(3).String())
   215  	assert.False(t, metrics.TooWideLower)
   216  	assert.False(t, metrics.TooWideUpper)
   217  
   218  	// if commitment is super low then we could panic, so test that we don't
   219  	metrics = EstimateBounds(
   220  		sqrter,
   221  		lowerPrice,
   222  		basePrice,
   223  		upperPrice,
   224  		leverageLower,
   225  		leverageUpper,
   226  		num.MustUintFromString("390500000000000000000", 10),
   227  		linearSlippageFactor,
   228  		initialMargin,
   229  		riskFactorShort,
   230  		riskFactorLong,
   231  		num.DecimalFromInt64(1000000000000000000),
   232  		num.DecimalOne(),
   233  		10,
   234  	)
   235  
   236  	assert.Equal(t, "-1.559", metrics.PositionSizeAtUpper.Round(3).String())
   237  	assert.Equal(t, "2.305", metrics.PositionSizeAtLower.Round(3).String())
   238  	assert.False(t, metrics.TooWideLower) // is valid as there are less than 10 empty price levels
   239  	assert.True(t, metrics.TooWideUpper)  // isn't valid as there are more than 10 empty price levels
   240  }
   241  
   242  func TestEstimateBoundsOneSided(t *testing.T) {
   243  	initialMargin := num.DecimalFromFloat(1)
   244  	riskFactorShort := num.DecimalFromFloat(0.01)
   245  	riskFactorLong := num.DecimalFromFloat(0.01)
   246  	linearSlippageFactor := num.DecimalFromFloat(0)
   247  	sqrter := NewSqrter()
   248  
   249  	lowerPrice := num.NewUint(900)
   250  	basePrice := num.NewUint(1000)
   251  	upperPrice := num.NewUint(1100)
   252  	leverageUpper := num.DecimalFromFloat(2.00)
   253  	leverageLower := num.DecimalFromFloat(2.00)
   254  	balance := num.NewUint(100)
   255  
   256  	// no upper bound supplied
   257  	metrics := EstimateBounds(
   258  		sqrter,
   259  		lowerPrice,
   260  		basePrice,
   261  		nil,
   262  		leverageLower,
   263  		leverageUpper,
   264  		balance,
   265  		linearSlippageFactor,
   266  		initialMargin,
   267  		riskFactorShort,
   268  		riskFactorLong,
   269  		num.DecimalOne(),
   270  		num.DecimalOne(),
   271  		0,
   272  	)
   273  	assert.True(t, metrics.LiquidationPriceAtUpper.IsZero())
   274  	assert.True(t, metrics.PositionSizeAtUpper.IsZero())
   275  	assert.True(t, metrics.LossOnCommitmentAtUpper.IsZero())
   276  
   277  	// no lower bound supplied
   278  	metrics = EstimateBounds(
   279  		sqrter,
   280  		nil,
   281  		basePrice,
   282  		upperPrice,
   283  		leverageLower,
   284  		leverageUpper,
   285  		balance,
   286  		linearSlippageFactor,
   287  		initialMargin,
   288  		riskFactorShort,
   289  		riskFactorLong,
   290  		num.DecimalOne(),
   291  		num.DecimalOne(),
   292  		0,
   293  	)
   294  	assert.True(t, metrics.LiquidationPriceAtLower.IsZero())
   295  	assert.True(t, metrics.PositionSizeAtLower.IsZero())
   296  	assert.True(t, metrics.LossOnCommitmentAtLower.IsZero())
   297  }