code.vegaprotocol.io/vega@v0.79.0/datanode/entities/market_depth.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
    17  
    18  import (
    19  	"errors"
    20  	"sort"
    21  
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  	"code.vegaprotocol.io/vega/protos/vega"
    25  )
    26  
    27  type PriceLevel struct {
    28  	// Price of the price level
    29  	Price *num.Uint
    30  	// How many orders are at this level
    31  	TotalOrders uint64
    32  	// How much volume is at this level
    33  	TotalVolume uint64
    34  	// How much volume from AMM's are at this level
    35  	TotalAMMVolume uint64
    36  	// How much estimated volume from AMM's are at this level
    37  	TotalEstimatedAMMVolume uint64
    38  	// What side of the book is this level
    39  	Side types.Side
    40  }
    41  
    42  type MarketDepth struct {
    43  	// Which market is this for
    44  	MarketID string
    45  	// All of the orders in the order book
    46  	LiveOrders map[string]*types.Order
    47  	// Just the buy side of the book
    48  	BuySide []*PriceLevel
    49  	// Just the sell side of the book
    50  	SellSide []*PriceLevel
    51  	// All price levels that have changed in the last update
    52  	Changes []*PriceLevel
    53  	// Sequence number is an increment-only value to identify a state
    54  	// of the market depth in time. Used when trying to match updates
    55  	// to a snapshot dump
    56  	SequenceNumber uint64
    57  	// PreviousSequenceNumber is the sequence number of the last published update. 'Changes' include
    58  	// updates from all events with a sequence number > PreviousSequenceNumber and <= SequenceNumber
    59  	PreviousSequenceNumber uint64
    60  }
    61  
    62  func (md *MarketDepth) ToProto(limit uint64) *vega.MarketDepth {
    63  	buyLimit := uint64(len(md.BuySide))
    64  	sellLimit := uint64(len(md.SellSide))
    65  	if limit > 0 {
    66  		buyLimit = min(buyLimit, limit)
    67  		sellLimit = min(sellLimit, limit)
    68  	}
    69  
    70  	buyPtr := make([]*types.PriceLevel, buyLimit)
    71  	sellPtr := make([]*types.PriceLevel, sellLimit)
    72  
    73  	// Copy the data across
    74  	for index, pl := range md.BuySide[:buyLimit] {
    75  		buyPtr[index] = &types.PriceLevel{
    76  			Volume:             pl.TotalVolume,
    77  			NumberOfOrders:     pl.TotalOrders,
    78  			Price:              pl.Price.Clone(),
    79  			AMMVolume:          pl.TotalAMMVolume,
    80  			AMMVolumeEstimated: pl.TotalEstimatedAMMVolume,
    81  		}
    82  	}
    83  
    84  	for index, pl := range md.SellSide[:sellLimit] {
    85  		sellPtr[index] = &types.PriceLevel{
    86  			Volume:             pl.TotalVolume,
    87  			NumberOfOrders:     pl.TotalOrders,
    88  			Price:              pl.Price.Clone(),
    89  			AMMVolume:          pl.TotalAMMVolume,
    90  			AMMVolumeEstimated: pl.TotalEstimatedAMMVolume,
    91  		}
    92  	}
    93  
    94  	return &types.MarketDepth{
    95  		MarketId:       md.MarketID,
    96  		Buy:            types.PriceLevels(buyPtr).IntoProto(),
    97  		Sell:           types.PriceLevels(sellPtr).IntoProto(),
    98  		SequenceNumber: md.SequenceNumber,
    99  	}
   100  }
   101  
   102  func (md *MarketDepth) AddAMMOrder(order *types.Order, estimated bool) {
   103  	md.addOrder(order, estimated)
   104  }
   105  
   106  func (md *MarketDepth) AddOrderUpdate(order *types.Order, estimated bool) {
   107  	// Do we know about this order already?
   108  	originalOrder := md.orderExists(order.ID)
   109  	if originalOrder != nil {
   110  		// Check to see if we are updating the order or removing it
   111  		if order.Status == types.OrderStatusCancelled ||
   112  			order.Status == types.OrderStatusExpired ||
   113  			order.Status == types.OrderStatusStopped ||
   114  			order.Status == types.OrderStatusFilled ||
   115  			order.Status == types.OrderStatusPartiallyFilled ||
   116  			order.Status == types.OrderStatusRejected ||
   117  			order.Status == types.OrderStatusParked {
   118  			md.removeOrder(originalOrder, estimated)
   119  		} else {
   120  			md.updateOrder(originalOrder, order)
   121  		}
   122  	} else {
   123  		if order.TrueRemaining() > 0 && order.Status == types.OrderStatusActive {
   124  			md.addOrder(order, estimated)
   125  		}
   126  	}
   127  }
   128  
   129  func (md *MarketDepth) orderExists(orderID string) *types.Order {
   130  	return md.LiveOrders[orderID]
   131  }
   132  
   133  func (md *MarketDepth) addOrder(order *types.Order, estimated bool) {
   134  	// Cache the orderID
   135  	orderCopy := order.Clone()
   136  	md.LiveOrders[order.ID] = orderCopy
   137  
   138  	// Update the price level
   139  	pl := md.GetPriceLevel(order.Side, order.Price)
   140  
   141  	if pl == nil {
   142  		pl = md.createNewPriceLevel(order, estimated)
   143  	} else if order.GeneratedOffbook {
   144  		if estimated {
   145  			pl.TotalEstimatedAMMVolume += order.TrueRemaining()
   146  		} else {
   147  			pl.TotalAMMVolume += order.TrueRemaining()
   148  		}
   149  	} else {
   150  		pl.TotalOrders++
   151  		pl.TotalVolume += order.TrueRemaining()
   152  	}
   153  	md.Changes = append(md.Changes, pl)
   154  }
   155  
   156  func (md *MarketDepth) removeOrder(order *types.Order, estimated bool) error {
   157  	// Find the price level
   158  	pl := md.GetPriceLevel(order.Side, order.Price)
   159  
   160  	if pl == nil {
   161  		return errors.New("unknown pricelevel")
   162  	}
   163  	// Update the values
   164  	if order.GeneratedOffbook {
   165  		if estimated {
   166  			pl.TotalEstimatedAMMVolume -= order.TrueRemaining()
   167  		} else {
   168  			pl.TotalAMMVolume -= order.TrueRemaining()
   169  		}
   170  	} else {
   171  		pl.TotalOrders--
   172  		pl.TotalVolume -= order.TrueRemaining()
   173  	}
   174  
   175  	// See if we can remove this price level
   176  	if pl.TotalOrders == 0 {
   177  		md.removePriceLevel(order)
   178  	}
   179  
   180  	md.Changes = append(md.Changes, pl)
   181  
   182  	// Remove the orderID from the list of live orders
   183  	delete(md.LiveOrders, order.ID)
   184  	return nil
   185  }
   186  
   187  func (md *MarketDepth) updateOrder(originalOrder, newOrder *types.Order) {
   188  	// If the price is the same, we can update the original order
   189  	if originalOrder.Price.EQ(newOrder.Price) {
   190  		if newOrder.TrueRemaining() == 0 {
   191  			md.removeOrder(newOrder, false)
   192  		} else {
   193  			// Update
   194  			pl := md.GetPriceLevel(originalOrder.Side, originalOrder.Price)
   195  			pl.TotalVolume += newOrder.TrueRemaining() - originalOrder.TrueRemaining()
   196  			originalOrder.Remaining = newOrder.Remaining
   197  			if originalOrder.IcebergOrder != nil {
   198  				originalOrder.IcebergOrder = newOrder.IcebergOrder.Clone()
   199  			}
   200  			originalOrder.Size = newOrder.Size
   201  			md.Changes = append(md.Changes, pl)
   202  		}
   203  	} else {
   204  		md.removeOrder(originalOrder, false)
   205  		if newOrder.TrueRemaining() > 0 {
   206  			md.addOrder(newOrder, false)
   207  		}
   208  	}
   209  }
   210  
   211  func (md *MarketDepth) createNewPriceLevel(order *types.Order, estimated bool) *PriceLevel {
   212  	pl := &PriceLevel{
   213  		Price: order.Price.Clone(),
   214  		Side:  order.Side,
   215  	}
   216  
   217  	if order.GeneratedOffbook {
   218  		if estimated {
   219  			pl.TotalEstimatedAMMVolume = order.TrueRemaining()
   220  		} else {
   221  			pl.TotalAMMVolume = order.TrueRemaining()
   222  		}
   223  	} else {
   224  		pl.TotalOrders = 1
   225  		pl.TotalVolume = order.TrueRemaining()
   226  	}
   227  
   228  	if order.Side == types.SideBuy {
   229  		index := sort.Search(len(md.BuySide), func(i int) bool { return md.BuySide[i].Price.LTE(order.Price) })
   230  		if index < len(md.BuySide) {
   231  			// We need to go midslice
   232  			md.BuySide = append(md.BuySide, nil)
   233  			copy(md.BuySide[index+1:], md.BuySide[index:])
   234  			md.BuySide[index] = pl
   235  		} else {
   236  			// We can tag on the end
   237  			md.BuySide = append(md.BuySide, pl)
   238  		}
   239  	} else {
   240  		index := sort.Search(len(md.SellSide), func(i int) bool { return md.SellSide[i].Price.GTE(order.Price) })
   241  		if index < len(md.SellSide) {
   242  			// We need to go midslice
   243  			md.SellSide = append(md.SellSide, nil)
   244  			copy(md.SellSide[index+1:], md.SellSide[index:])
   245  			md.SellSide[index] = pl
   246  		} else {
   247  			// We can tag on the end
   248  			md.SellSide = append(md.SellSide, pl)
   249  		}
   250  	}
   251  	return pl
   252  }
   253  
   254  func (md *MarketDepth) GetPriceLevel(side types.Side, price *num.Uint) *PriceLevel {
   255  	var i int
   256  	if side == types.SideBuy {
   257  		// buy side levels should be ordered in descending
   258  		i = sort.Search(len(md.BuySide), func(i int) bool { return md.BuySide[i].Price.LTE(price) })
   259  		if i < len(md.BuySide) && md.BuySide[i].Price.EQ(price) {
   260  			return md.BuySide[i]
   261  		}
   262  	} else {
   263  		// sell side levels should be ordered in ascending
   264  		i = sort.Search(len(md.SellSide), func(i int) bool { return md.SellSide[i].Price.GTE(price) })
   265  		if i < len(md.SellSide) && md.SellSide[i].Price.EQ(price) {
   266  			return md.SellSide[i]
   267  		}
   268  	}
   269  	return nil
   270  }
   271  
   272  func (md *MarketDepth) removePriceLevel(order *types.Order) {
   273  	var i int
   274  	if order.Side == types.SideBuy {
   275  		// buy side levels should be ordered in descending
   276  		i = sort.Search(len(md.BuySide), func(i int) bool { return md.BuySide[i].Price.LTE(order.Price) })
   277  		if i < len(md.BuySide) && md.BuySide[i].Price.EQ(order.Price) {
   278  			copy(md.BuySide[i:], md.BuySide[i+1:])
   279  			md.BuySide[len(md.BuySide)-1] = nil
   280  			md.BuySide = md.BuySide[:len(md.BuySide)-1]
   281  		}
   282  	} else {
   283  		// sell side levels should be ordered in ascending
   284  		i = sort.Search(len(md.SellSide), func(i int) bool { return md.SellSide[i].Price.GTE(order.Price) })
   285  		// we found the level just return it.
   286  		if i < len(md.SellSide) && md.SellSide[i].Price.EQ(order.Price) {
   287  			copy(md.SellSide[i:], md.SellSide[i+1:])
   288  			md.SellSide[len(md.SellSide)-1] = nil
   289  			md.SellSide = md.SellSide[:len(md.SellSide)-1]
   290  		}
   291  	}
   292  }
   293  
   294  // Returns the min of 2 uint64s.
   295  func min(x, y uint64) uint64 {
   296  	if y < x {
   297  		return y
   298  	}
   299  	return x
   300  }