code.vegaprotocol.io/vega@v0.79.0/datanode/entities/marketdata_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 entities_test
    17  
    18  import (
    19  	"testing"
    20  	"time"
    21  
    22  	"code.vegaprotocol.io/vega/datanode/entities"
    23  	types "code.vegaprotocol.io/vega/protos/vega"
    24  
    25  	"github.com/shopspring/decimal"
    26  	"github.com/stretchr/testify/assert"
    27  )
    28  
    29  func TestMarketDataFromProto(t *testing.T) {
    30  	t.Run("should parse all valid prices", testParseAllValidPrices)
    31  	t.Run("should return zero for prices if string is empty", testParseEmptyPrices)
    32  	t.Run("should return error if an invalid price string is provided", testParseInvalidPriceString)
    33  	t.Run("should parse valid market data records successfully", testParseMarketDataSuccessfully)
    34  }
    35  
    36  func testParseAllValidPrices(t *testing.T) {
    37  	marketdata := types.MarketData{
    38  		MarkPrice:            "1",
    39  		BestBidPrice:         "1",
    40  		BestOfferPrice:       "1",
    41  		BestStaticBidPrice:   "1",
    42  		BestStaticOfferPrice: "1",
    43  		MidPrice:             "1",
    44  		StaticMidPrice:       "1",
    45  		IndicativePrice:      "1",
    46  		TargetStake:          "1",
    47  		SuppliedStake:        "1",
    48  	}
    49  
    50  	md, err := entities.MarketDataFromProto(&marketdata, generateTxHash())
    51  	assert.NoError(t, err)
    52  	assert.NotNil(t, md.MarkPrice)
    53  	assert.NotNil(t, md.BestBidPrice)
    54  	assert.NotNil(t, md.BestOfferPrice)
    55  	assert.NotNil(t, md.BestStaticBidPrice)
    56  	assert.NotNil(t, md.BestStaticOfferVolume)
    57  	assert.NotNil(t, md.MidPrice)
    58  	assert.NotNil(t, md.StaticMidPrice)
    59  	assert.NotNil(t, md.IndicativePrice)
    60  	assert.NotNil(t, md.TargetStake)
    61  	assert.NotNil(t, md.SuppliedStake)
    62  
    63  	want := decimal.NewFromInt(1)
    64  	assert.True(t, want.Equal(md.MarkPrice))
    65  	assert.True(t, want.Equal(md.BestBidPrice))
    66  	assert.True(t, want.Equal(md.BestOfferPrice))
    67  	assert.True(t, want.Equal(md.BestStaticBidPrice))
    68  	assert.True(t, want.Equal(md.BestStaticOfferPrice))
    69  	assert.True(t, want.Equal(md.MidPrice))
    70  	assert.True(t, want.Equal(md.StaticMidPrice))
    71  	assert.True(t, want.Equal(md.IndicativePrice))
    72  	assert.True(t, want.Equal(md.TargetStake))
    73  	assert.True(t, want.Equal(md.SuppliedStake))
    74  }
    75  
    76  func testParseEmptyPrices(t *testing.T) {
    77  	marketdata := types.MarketData{}
    78  	md, err := entities.MarketDataFromProto(&marketdata, generateTxHash())
    79  	assert.NoError(t, err)
    80  	assert.True(t, decimal.Zero.Equals(md.MarkPrice))
    81  	assert.True(t, decimal.Zero.Equals(md.BestBidPrice))
    82  	assert.True(t, decimal.Zero.Equals(md.BestOfferPrice))
    83  	assert.True(t, decimal.Zero.Equals(md.BestStaticBidPrice))
    84  	assert.True(t, decimal.Zero.Equals(md.BestStaticOfferPrice))
    85  	assert.True(t, decimal.Zero.Equals(md.MidPrice))
    86  	assert.True(t, decimal.Zero.Equals(md.StaticMidPrice))
    87  	assert.True(t, decimal.Zero.Equals(md.IndicativePrice))
    88  	assert.True(t, decimal.Zero.Equals(md.TargetStake))
    89  	assert.True(t, decimal.Zero.Equals(md.SuppliedStake))
    90  }
    91  
    92  func testParseInvalidPriceString(t *testing.T) {
    93  	type args struct {
    94  		marketdata types.MarketData
    95  	}
    96  	testCases := []struct {
    97  		name string
    98  		args args
    99  	}{
   100  		{
   101  			name: "Invalid Mark Price",
   102  			args: args{
   103  				marketdata: types.MarketData{
   104  					MarkPrice: "Test",
   105  				},
   106  			},
   107  		},
   108  		{
   109  			name: "Invalid Best Bid Price",
   110  			args: args{
   111  				marketdata: types.MarketData{
   112  					BestBidPrice: "Test",
   113  				},
   114  			},
   115  		},
   116  		{
   117  			name: "Invalid Best Offer Price",
   118  			args: args{
   119  				marketdata: types.MarketData{
   120  					BestOfferPrice: "Test",
   121  				},
   122  			},
   123  		},
   124  		{
   125  			name: "Invalid Best Static Bid Price",
   126  			args: args{
   127  				marketdata: types.MarketData{
   128  					BestStaticBidPrice: "Test",
   129  				},
   130  			},
   131  		},
   132  		{
   133  			name: "Invalid Best Static Offer Price",
   134  			args: args{
   135  				marketdata: types.MarketData{
   136  					BestStaticOfferPrice: "Test",
   137  				},
   138  			},
   139  		},
   140  		{
   141  			name: "Invalid Mid Price",
   142  			args: args{
   143  				marketdata: types.MarketData{
   144  					MidPrice: "Test",
   145  				},
   146  			},
   147  		},
   148  		{
   149  			name: "Invalid Static Mid Price",
   150  			args: args{
   151  				marketdata: types.MarketData{
   152  					StaticMidPrice: "Test",
   153  				},
   154  			},
   155  		},
   156  		{
   157  			name: "Invalid Indicative Price",
   158  			args: args{
   159  				marketdata: types.MarketData{
   160  					IndicativePrice: "Test",
   161  				},
   162  			},
   163  		},
   164  		{
   165  			name: "Invalid Target Stake",
   166  			args: args{
   167  				marketdata: types.MarketData{
   168  					TargetStake: "Test",
   169  				},
   170  			},
   171  		},
   172  		{
   173  			name: "Invalid Supplied Stake",
   174  			args: args{
   175  				marketdata: types.MarketData{
   176  					SuppliedStake: "Test",
   177  				},
   178  			},
   179  		},
   180  	}
   181  
   182  	for _, tc := range testCases {
   183  		t.Run(tc.name, func(tt *testing.T) {
   184  			md, err := entities.MarketDataFromProto(&tc.args.marketdata, generateTxHash())
   185  			assert.Error(tt, err)
   186  			assert.Nil(tt, md)
   187  		})
   188  	}
   189  }
   190  
   191  func testParseMarketDataSuccessfully(t *testing.T) {
   192  	type args struct {
   193  		marketdata types.MarketData
   194  	}
   195  
   196  	nextMTM := time.Now()
   197  	nextNC := time.Now()
   198  	zeroTime := time.Unix(0, 0)
   199  
   200  	testCases := []struct {
   201  		name string
   202  		args args
   203  		want *entities.MarketData
   204  	}{
   205  		{
   206  			name: "Empty market data",
   207  			args: args{
   208  				marketdata: types.MarketData{},
   209  			},
   210  			want: &entities.MarketData{
   211  				AuctionTrigger:      "AUCTION_TRIGGER_UNSPECIFIED",
   212  				MarketState:         "STATE_UNSPECIFIED",
   213  				MarketTradingMode:   "TRADING_MODE_UNSPECIFIED",
   214  				ExtensionTrigger:    "AUCTION_TRIGGER_UNSPECIFIED",
   215  				TxHash:              generateTxHash(),
   216  				NextMarkToMarket:    zeroTime,
   217  				NextNetworkCloseout: zeroTime,
   218  				MarkPriceType:       "COMPOSITE_PRICE_TYPE_UNSPECIFIED",
   219  			},
   220  		},
   221  		{
   222  			name: "Market data with auction trigger specified",
   223  			args: args{
   224  				marketdata: types.MarketData{
   225  					Trigger:             types.AuctionTrigger_AUCTION_TRIGGER_PRICE,
   226  					NextMarkToMarket:    nextMTM.UnixNano(),
   227  					NextNetworkCloseout: nextNC.UnixNano(),
   228  				},
   229  			},
   230  			want: &entities.MarketData{
   231  				AuctionTrigger:      "AUCTION_TRIGGER_PRICE",
   232  				MarketState:         "STATE_UNSPECIFIED",
   233  				MarketTradingMode:   "TRADING_MODE_UNSPECIFIED",
   234  				ExtensionTrigger:    "AUCTION_TRIGGER_UNSPECIFIED",
   235  				MarkPriceType:       "COMPOSITE_PRICE_TYPE_UNSPECIFIED",
   236  				NextMarkToMarket:    nextMTM,
   237  				NextNetworkCloseout: nextNC,
   238  				TxHash:              generateTxHash(),
   239  			},
   240  		},
   241  		{
   242  			name: "Market data with auction trigger and market trading mode specified",
   243  			args: args{
   244  				marketdata: types.MarketData{
   245  					Trigger:             types.AuctionTrigger_AUCTION_TRIGGER_PRICE,
   246  					MarketTradingMode:   types.Market_TRADING_MODE_CONTINUOUS,
   247  					NextMarkToMarket:    nextMTM.UnixNano(),
   248  					NextNetworkCloseout: nextNC.UnixNano(),
   249  				},
   250  			},
   251  			want: &entities.MarketData{
   252  				AuctionTrigger:      "AUCTION_TRIGGER_PRICE",
   253  				MarketTradingMode:   "TRADING_MODE_CONTINUOUS",
   254  				MarketState:         "STATE_UNSPECIFIED",
   255  				ExtensionTrigger:    "AUCTION_TRIGGER_UNSPECIFIED",
   256  				MarkPriceType:       "COMPOSITE_PRICE_TYPE_UNSPECIFIED",
   257  				NextMarkToMarket:    nextMTM,
   258  				NextNetworkCloseout: nextNC,
   259  				TxHash:              generateTxHash(),
   260  			},
   261  		},
   262  		{
   263  			name: "Market data with best bid and best offer specified",
   264  			args: args{
   265  				marketdata: types.MarketData{
   266  					BestBidPrice:        "100.0",
   267  					BestOfferPrice:      "110.0",
   268  					Trigger:             types.AuctionTrigger_AUCTION_TRIGGER_PRICE,
   269  					MarketTradingMode:   types.Market_TRADING_MODE_CONTINUOUS,
   270  					MarketState:         types.Market_STATE_ACTIVE,
   271  					NextMarkToMarket:    nextMTM.UnixNano(),
   272  					NextNetworkCloseout: nextNC.UnixNano(),
   273  				},
   274  			},
   275  			want: &entities.MarketData{
   276  				BestBidPrice:        decimal.NewFromFloat(100.0),
   277  				BestOfferPrice:      decimal.NewFromFloat(110.0),
   278  				AuctionTrigger:      "AUCTION_TRIGGER_PRICE",
   279  				MarketState:         "STATE_ACTIVE",
   280  				MarketTradingMode:   "TRADING_MODE_CONTINUOUS",
   281  				ExtensionTrigger:    "AUCTION_TRIGGER_UNSPECIFIED",
   282  				MarkPriceType:       "COMPOSITE_PRICE_TYPE_UNSPECIFIED",
   283  				TxHash:              generateTxHash(),
   284  				NextMarkToMarket:    nextMTM,
   285  				NextNetworkCloseout: nextNC,
   286  			},
   287  		},
   288  		{
   289  			name: "Market data with best bid and best offer specified and price monitoring bounds",
   290  			args: args{
   291  				marketdata: types.MarketData{
   292  					BestBidPrice:      "100.0",
   293  					BestOfferPrice:    "110.0",
   294  					Trigger:           types.AuctionTrigger_AUCTION_TRIGGER_PRICE,
   295  					MarketTradingMode: types.Market_TRADING_MODE_CONTINUOUS,
   296  					PriceMonitoringBounds: []*types.PriceMonitoringBounds{
   297  						{
   298  							MinValidPrice: "100",
   299  							MaxValidPrice: "200",
   300  						},
   301  					},
   302  					NextMarkToMarket:    nextMTM.UnixNano(),
   303  					NextNetworkCloseout: nextNC.UnixNano(),
   304  				},
   305  			},
   306  			want: &entities.MarketData{
   307  				BestBidPrice:      decimal.NewFromFloat(100.0),
   308  				BestOfferPrice:    decimal.NewFromFloat(110.0),
   309  				AuctionTrigger:    "AUCTION_TRIGGER_PRICE",
   310  				MarketTradingMode: "TRADING_MODE_CONTINUOUS",
   311  				MarketState:       "STATE_UNSPECIFIED",
   312  				ExtensionTrigger:  "AUCTION_TRIGGER_UNSPECIFIED",
   313  				MarkPriceType:     "COMPOSITE_PRICE_TYPE_UNSPECIFIED",
   314  				PriceMonitoringBounds: []*types.PriceMonitoringBounds{
   315  					{
   316  						MinValidPrice:  "100",
   317  						MaxValidPrice:  "200",
   318  						ReferencePrice: "",
   319  					},
   320  				},
   321  				TxHash:              generateTxHash(),
   322  				NextMarkToMarket:    nextMTM,
   323  				NextNetworkCloseout: nextNC,
   324  			},
   325  		},
   326  	}
   327  
   328  	for _, tc := range testCases {
   329  		t.Run(tc.name, func(tt *testing.T) {
   330  			got, err := entities.MarketDataFromProto(&tc.args.marketdata, tc.want.TxHash)
   331  			assert.NoError(tt, err)
   332  			assert.True(tt, tc.want.Equal(*got))
   333  		})
   334  	}
   335  }