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 }