code.vegaprotocol.io/vega@v0.79.0/core/liquidity/supplied/statevar_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 supplied
    17  
    18  import (
    19  	"testing"
    20  
    21  	"code.vegaprotocol.io/vega/core/risk/models"
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  var (
    29  	min = num.DecimalZero()
    30  	max = num.MaxUint().ToDecimal()
    31  )
    32  
    33  func TestBidRange(t *testing.T) {
    34  	prob := calculateBidRange(num.DecimalFromFloat(100), num.DecimalFromFloat(0.01), num.DecimalFromInt64(1), pOfT)
    35  	require.Equal(t, 100, len(prob))
    36  	for i := range prob {
    37  		require.Equal(t, num.DecimalFromFloat(1.0).Sub(num.DecimalFromInt64(int64(i)).Div(num.DecimalFromFloat(100))).String(), prob[i].String())
    38  	}
    39  
    40  	prob2 := calculateBidRange(num.DecimalFromFloat(200), num.DecimalFromFloat(0.01), num.DecimalFromInt64(1), pOfT)
    41  	require.Equal(t, 100, len(prob2))
    42  	for i := range prob2 {
    43  		require.Equal(t, num.DecimalFromFloat(1.0).Sub(num.DecimalFromInt64(int64(i)).Div(num.DecimalFromFloat(100))).String(), prob2[i].String())
    44  	}
    45  }
    46  
    47  func TestAskRange(t *testing.T) {
    48  	prob := calculateAskRange(num.DecimalFromFloat(100), num.DecimalFromFloat(0.01), num.DecimalFromInt64(1), pOfT)
    49  	require.Equal(t, 100, len(prob))
    50  	for i := range prob {
    51  		require.Equal(t, num.DecimalFromFloat(1.0).Sub(num.DecimalFromInt64(int64(i)).Div(num.DecimalFromFloat(100))).String(), prob[i].String())
    52  	}
    53  
    54  	prob2 := calculateAskRange(num.DecimalFromFloat(200), num.DecimalFromFloat(0.01), num.DecimalFromInt64(1), pOfT)
    55  	require.Equal(t, 100, len(prob2))
    56  	for i := range prob2 {
    57  		require.Equal(t, num.DecimalFromFloat(1.0).Sub(num.DecimalFromInt64(int64(i)).Div(num.DecimalFromFloat(100))).String(), prob[i].String())
    58  	}
    59  }
    60  
    61  func TestBidRangeAtTheEdge(t *testing.T) {
    62  	params := &types.LogNormalRiskModel{
    63  		RiskAversionParameter: num.DecimalFromFloat(0.001),
    64  		Tau:                   num.DecimalFromFloat(0o0011407711613050422),
    65  		Params: &types.LogNormalModelParams{
    66  			R:     num.DecimalFromFloat(0.016),
    67  			Sigma: num.DecimalFromFloat(1.5),
    68  		},
    69  	}
    70  	risk, _ := models.NewBuiltinFutures(params, "asset")
    71  
    72  	p := calculateBidRange(num.DecimalFromFloat(900), num.DecimalFromFloat(0.001), num.DecimalFromFloat(0.00012345), risk.ProbabilityOfTrading)
    73  
    74  	require.Equal(t, 92, len(p))
    75  
    76  	pot := &probabilityOfTrading{
    77  		bidProbability: p,
    78  		bidOffset:      []uint32{0, 40},
    79  	}
    80  	minProb := num.DecimalFromFloat(0.021)
    81  
    82  	// order price 899, best bid 900
    83  	// offset is therefore int(1600*(900-899)/900) = 1
    84  	// so we're interpolating between the probability 1 at offset 0 and probability of 0.9524363412970467 at offset 40
    85  	// so expecting scaled probability to be (0.975*1 + 0.025*0.9524363412970467)/2 = 0.4999762182
    86  	require.Equal(t, "0.4994054543", getProbabilityOfTrading(num.DecimalFromFloat(900), num.DecimalFromFloat(900), num.DecimalZero(), num.MaxDecimal(), pot, num.DecimalFromFloat(899), true, minProb, num.DecimalFromInt64(1600)).StringFixed(10))
    87  }
    88  
    89  func pOfT(best, p, min, max, tauScaled num.Decimal, isBid bool, applyMinMax bool) num.Decimal {
    90  	if p.LessThanOrEqual(num.DecimalZero()) {
    91  		return defaultMinimumProbabilityOfTrading
    92  	}
    93  	if p.GreaterThanOrEqual(num.DecimalFromInt64(2).Mul(best)) {
    94  		return defaultMinimumProbabilityOfTrading
    95  	}
    96  	return num.DecimalFromFloat(1).Sub(best.Sub(p).Abs().Div(best))
    97  }
    98  
    99  func TestGetProbability(t *testing.T) {
   100  	offsetFactor := num.DecimalFromInt64(1000000)
   101  	minProb := num.DecimalFromFloat(0.21)
   102  
   103  	// no consensus yet within 20% ticks (bid)
   104  	require.Equal(t, defaultInRangeProbabilityOfTrading.String(), getProbabilityOfTrading(num.DecimalFromFloat(200000), num.DecimalFromFloat(600), min, max, &probabilityOfTrading{}, num.DecimalFromInt64(160000), true, minProb, offsetFactor).String())
   105  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(200000), num.DecimalFromFloat(600), min, max, &probabilityOfTrading{}, num.DecimalFromInt64(159999), true, minProb, offsetFactor).String())
   106  
   107  	// no consensus yet within 20% ticks (ask)
   108  	require.Equal(t, defaultInRangeProbabilityOfTrading.String(), getProbabilityOfTrading(num.DecimalFromFloat(100000), num.DecimalFromFloat(200000), min, max, &probabilityOfTrading{}, num.DecimalFromInt64(240000), false, minProb, offsetFactor).String())
   109  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(100000), num.DecimalFromFloat(200000), min, max, &probabilityOfTrading{}, num.DecimalFromInt64(240001), false, minProb, offsetFactor).String())
   110  
   111  	// price is GTE best bid and LTE best ask - use defaultInRangeProbabilityOfTrading
   112  	require.Equal(t, defaultInRangeProbabilityOfTrading, getProbabilityOfTrading(num.DecimalFromFloat(120), num.DecimalFromFloat(220), min, max, &probabilityOfTrading{}, num.DecimalFromInt64(120), true, minProb, offsetFactor))
   113  	require.Equal(t, defaultInRangeProbabilityOfTrading, getProbabilityOfTrading(num.DecimalFromFloat(120), num.DecimalFromFloat(220), min, max, &probabilityOfTrading{}, num.DecimalFromInt64(121), true, minProb, offsetFactor))
   114  	require.Equal(t, defaultInRangeProbabilityOfTrading, getProbabilityOfTrading(num.DecimalFromFloat(120), num.DecimalFromFloat(220), min, max, &probabilityOfTrading{}, num.DecimalFromInt64(220), false, minProb, offsetFactor))
   115  	require.Equal(t, defaultInRangeProbabilityOfTrading, getProbabilityOfTrading(num.DecimalFromFloat(120), num.DecimalFromFloat(220), min, max, &probabilityOfTrading{}, num.DecimalFromInt64(219), false, minProb, offsetFactor))
   116  
   117  	bProb := calculateBidRange(num.DecimalFromFloat(400), num.DecimalFromFloat(0.001), num.DecimalFromFloat(1), pOfT)
   118  	aProb := calculateAskRange(num.DecimalFromFloat(600), num.DecimalFromFloat(0.001), num.DecimalFromInt64(1), pOfT)
   119  
   120  	bOffsets := make([]uint32, 0, len(bProb))
   121  	aOffsets := make([]uint32, 0, len(aProb))
   122  
   123  	for i := range bProb {
   124  		bOffsets = append(bOffsets, uint32(i*1000))
   125  	}
   126  	for i := range aProb {
   127  		aOffsets = append(aOffsets, uint32(i*1000))
   128  	}
   129  
   130  	pot := &probabilityOfTrading{
   131  		bidOffset:      bOffsets,
   132  		bidProbability: bProb,
   133  		askOffset:      aOffsets,
   134  		askProbability: aProb,
   135  	}
   136  
   137  	// find exact match bid side - offset of 200 is the middle point of the probabilities so should have probability of 0.5 scaled by 0.5
   138  	require.Equal(t, "0.25", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(200), true, minProb, offsetFactor).String())
   139  	// linterp bid => (0.75*0.5+0.25*0.51)/2
   140  	require.Equal(t, "0.25125", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(201), true, minProb, offsetFactor).String())
   141  	// linterp bid => (0.5*0.5+0.5*0.51)/2
   142  	require.Equal(t, "0.2525", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(202), true, minProb, offsetFactor).String())
   143  	// linterp bid => (0.25*0.5+0.75*0.51)/2
   144  	require.Equal(t, "0.25375", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(203), true, minProb, offsetFactor).String())
   145  	// linterp bid => (0*0.5+1*0.51)/2
   146  	require.Equal(t, "0.255", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(204), true, minProb, offsetFactor).String())
   147  
   148  	// linterp bid => max(0.2, 0.21) = 0.21
   149  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(100), true, minProb, offsetFactor).String())
   150  	// linterp bid => max(0.75*0 + 0.5*0.2, minProb) = 0.21
   151  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(101), true, minProb, offsetFactor).String())
   152  	// linterp bid => max(0.5*0 + 0.5*0.2, minProb) = 0.21
   153  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(102), true, minProb, offsetFactor).String())
   154  	// linterp bid => max(0.25*0 + 0.5*0.2, minProb) = 0.21
   155  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(103), true, minProb, offsetFactor).String())
   156  
   157  	// find exact match ask side - offset of 200 is the middle point of the probabilities so should have probability of 0.5 scaled by 0.5
   158  	require.Equal(t, "0.25", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(900), false, minProb, offsetFactor).String())
   159  	// linterp ask => (0.75*0.5+0.25*0.51)/2
   160  	require.Equal(t, "0.25125", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromFloat(898.5), false, minProb, offsetFactor).String())
   161  	// linterp ask => (0.5*0.5+0.5*0.51)/2
   162  	require.Equal(t, "0.2525", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(897), false, minProb, offsetFactor).String())
   163  	// linterp ask => (0.25*0.5+0.75*0.51)/2
   164  	require.Equal(t, "0.25375", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromFloat(895.5), false, minProb, offsetFactor).String())
   165  	// linterp ask => (0*0.5+1*0.51)/2
   166  	require.Equal(t, "0.255", getProbabilityOfTrading(num.DecimalFromFloat(400), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(894), false, minProb, offsetFactor).String())
   167  
   168  	// linterp ask => max(0, minProb) = 0.21
   169  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(1000), false, minProb, offsetFactor).String())
   170  	// linterp ask => max(0.75*0 + 0.5*0.01, minProb) = 0.21
   171  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(999), false, minProb, offsetFactor).String())
   172  	// linterp ask => max(0.5*0 + 0.5*0.01, minProb) = 0.21
   173  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(998), false, minProb, offsetFactor).String())
   174  	// linterp ask => max(0.25*0 + 0.5*0.01, minProb) = 0.21
   175  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, pot, num.DecimalFromInt64(997), false, minProb, offsetFactor).String())
   176  
   177  	// // extrapolating
   178  	potForExtrapolation := &probabilityOfTrading{
   179  		bidOffset:      []uint32{0, 1000 * 100},
   180  		askOffset:      []uint32{0, 1000 * 100},
   181  		bidProbability: []num.Decimal{num.DecimalFromFloat(0.9), num.DecimalFromFloat(0.5)},
   182  		askProbability: []num.Decimal{num.DecimalFromFloat(0.9), num.DecimalFromFloat(0.5)},
   183  	}
   184  
   185  	// ask
   186  	require.Equal(t, "0.05", getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, potForExtrapolation, num.DecimalFromInt64(720), false, num.DecimalZero(), offsetFactor).String())
   187  	// too far, floored at min prob
   188  	require.Equal(t, minProb.String(), getProbabilityOfTrading(num.DecimalFromFloat(500), num.DecimalFromFloat(600), min, max, potForExtrapolation, num.DecimalFromInt64(10000), false, minProb, offsetFactor).String())
   189  }