code.vegaprotocol.io/vega@v0.79.0/core/subscribers/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 subscribers
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  	"fmt"
    22  	"sort"
    23  	"sync"
    24  
    25  	"code.vegaprotocol.io/vega/core/events"
    26  	"code.vegaprotocol.io/vega/core/types"
    27  	"code.vegaprotocol.io/vega/libs/num"
    28  	"code.vegaprotocol.io/vega/logging"
    29  	ptypes "code.vegaprotocol.io/vega/protos/vega"
    30  )
    31  
    32  type OE interface {
    33  	events.Event
    34  	Order() *ptypes.Order
    35  }
    36  
    37  type CO interface {
    38  	events.Event
    39  	OrderIDs() []string
    40  	MarketID() string
    41  }
    42  
    43  type priceLevel struct {
    44  	// Price of the price level
    45  	price *num.Uint
    46  	// How many orders are at this level
    47  	totalOrders uint64
    48  	// How much volume is at this level
    49  	totalVolume uint64
    50  	// What side of the book is this level
    51  	side types.Side
    52  }
    53  
    54  // MarketDepth holds all the details about a single markets MarketDepth.
    55  type MarketDepth struct {
    56  	// Which market is this for
    57  	marketID string
    58  	// All of the orders in the order book
    59  	liveOrders map[string]*types.Order
    60  	// Just the buy side of the book
    61  	buySide []*priceLevel
    62  	// Just the sell side of the book
    63  	sellSide []*priceLevel
    64  	// All price levels that have changed in the last update
    65  	changes []*priceLevel
    66  	// Sequence number is an increment-only value to identify a state
    67  	// of the market depth in time. Used when trying to match updates
    68  	// to a snapshot dump
    69  	sequenceNumber uint64
    70  }
    71  
    72  // MarketDepthBuilder is a subscriber of order events
    73  // used to build the live market depth structure.
    74  type MarketDepthBuilder struct {
    75  	*Base
    76  	mu sync.RWMutex
    77  	// Map of all the markets to their market depth
    78  	marketDepths map[string]*MarketDepth
    79  	// Incrementing counter for subscriberID
    80  	subscriberID uint64
    81  	// Map of subscriberIds to their channels
    82  	subscribers map[uint64]chan<- *types.MarketDepthUpdate
    83  	// Logger
    84  	log *logging.Logger
    85  }
    86  
    87  // NewMarketDepthBuilder constructor to create a market depth subscriber.
    88  func NewMarketDepthBuilder(ctx context.Context, log *logging.Logger, ack bool) *MarketDepthBuilder {
    89  	mdb := MarketDepthBuilder{
    90  		Base:         NewBase(ctx, 10, ack),
    91  		log:          log,
    92  		marketDepths: map[string]*MarketDepth{},
    93  		subscribers:  map[uint64]chan<- *types.MarketDepthUpdate{},
    94  	}
    95  
    96  	if mdb.isRunning() {
    97  		go mdb.loop(mdb.ctx)
    98  	}
    99  	return &mdb
   100  }
   101  
   102  func (mdb *MarketDepthBuilder) loop(ctx context.Context) {
   103  	for {
   104  		select {
   105  		case <-ctx.Done():
   106  			mdb.Halt()
   107  			return
   108  		case e := <-mdb.ch:
   109  			if mdb.isRunning() {
   110  				mdb.Push(e...)
   111  			}
   112  		}
   113  	}
   114  }
   115  
   116  // Push takes order messages and applied them to the makret depth structure.
   117  func (mdb *MarketDepthBuilder) Push(evts ...events.Event) {
   118  	for _, e := range evts {
   119  		switch et := e.(type) {
   120  		case OE:
   121  			order, _ := types.OrderFromProto(et.Order())
   122  			mdb.updateMarketDepth(order)
   123  		case CO:
   124  			for _, o := range mdb.applyOrderCancellations(et) {
   125  				mdb.updateMarketDepth(o)
   126  			}
   127  		default:
   128  			mdb.log.Panic("Unknown event type in market depth builder", logging.String("Type", et.Type().String()))
   129  		}
   130  	}
   131  }
   132  
   133  func (mdb *MarketDepthBuilder) applyOrderCancellations(evt CO) []*types.Order {
   134  	mdb.mu.Lock()
   135  	defer mdb.mu.Unlock()
   136  
   137  	mktOrders, ok := mdb.marketDepths[evt.MarketID()]
   138  	if !ok {
   139  		return nil
   140  	}
   141  	orders := []*types.Order{}
   142  	for _, oid := range evt.OrderIDs() {
   143  		if o := mktOrders.orderExists(oid); o != nil {
   144  			cpy := o.Clone()
   145  			cpy.Status = types.OrderStatusCancelled
   146  			orders = append(orders, cpy)
   147  		}
   148  	}
   149  	return orders
   150  }
   151  
   152  // Types returns all the message types this subscriber wants to receive.
   153  func (mdb *MarketDepthBuilder) Types() []events.Type {
   154  	ret := []events.Type{
   155  		events.OrderEvent,
   156  		events.CancelledOrdersEvent,
   157  	}
   158  	return ret
   159  }
   160  
   161  func (md *MarketDepth) orderExists(orderID string) *types.Order {
   162  	return md.liveOrders[orderID]
   163  }
   164  
   165  func (md *MarketDepth) removeOrder(order *types.Order) error {
   166  	// Find the price level
   167  	pl := md.getPriceLevel(order.Side, order.Price)
   168  
   169  	if pl == nil {
   170  		return errors.New("unknown pricelevel")
   171  	}
   172  	// Update the values
   173  	pl.totalOrders--
   174  	pl.totalVolume -= order.TrueRemaining()
   175  
   176  	// See if we can remove this price level
   177  	if pl.totalOrders == 0 {
   178  		md.removePriceLevel(order)
   179  	}
   180  
   181  	md.changes = append(md.changes, pl)
   182  
   183  	// Remove the orderID from the list of live orders
   184  	delete(md.liveOrders, order.ID)
   185  	return nil
   186  }
   187  
   188  func (md *MarketDepth) createNewPriceLevel(order *types.Order) *priceLevel {
   189  	pl := &priceLevel{
   190  		price:       order.Price.Clone(),
   191  		totalOrders: 1,
   192  		totalVolume: order.TrueRemaining(),
   193  		side:        order.Side,
   194  	}
   195  
   196  	if order.Side == types.SideBuy {
   197  		index := sort.Search(len(md.buySide), func(i int) bool { return md.buySide[i].price.LTE(order.Price) })
   198  		if index < len(md.buySide) {
   199  			// We need to go midslice
   200  			md.buySide = append(md.buySide, nil)
   201  			copy(md.buySide[index+1:], md.buySide[index:])
   202  			md.buySide[index] = pl
   203  		} else {
   204  			// We can tag on the end
   205  			md.buySide = append(md.buySide, pl)
   206  		}
   207  	} else {
   208  		index := sort.Search(len(md.sellSide), func(i int) bool { return md.sellSide[i].price.GTE(order.Price) })
   209  		if index < len(md.sellSide) {
   210  			// We need to go midslice
   211  			md.sellSide = append(md.sellSide, nil)
   212  			copy(md.sellSide[index+1:], md.sellSide[index:])
   213  			md.sellSide[index] = pl
   214  		} else {
   215  			// We can tag on the end
   216  			md.sellSide = append(md.sellSide, pl)
   217  		}
   218  	}
   219  	return pl
   220  }
   221  
   222  func (md *MarketDepth) addOrder(order *types.Order) {
   223  	// Cache the orderID
   224  	orderCopy := order.Clone()
   225  	md.liveOrders[order.ID] = orderCopy
   226  
   227  	// Update the price level
   228  	pl := md.getPriceLevel(order.Side, order.Price)
   229  
   230  	if pl == nil {
   231  		pl = md.createNewPriceLevel(order)
   232  	} else {
   233  		pl.totalOrders++
   234  		pl.totalVolume += order.TrueRemaining()
   235  	}
   236  	md.changes = append(md.changes, pl)
   237  }
   238  
   239  func (md *MarketDepth) updateOrder(originalOrder, newOrder *types.Order) {
   240  	// If the price is the same, we can update the original order
   241  	if originalOrder.Price.EQ(newOrder.Price) {
   242  		if newOrder.TrueRemaining() == 0 {
   243  			md.removeOrder(newOrder)
   244  		} else {
   245  			// Update
   246  			pl := md.getPriceLevel(originalOrder.Side, originalOrder.Price)
   247  			pl.totalVolume += newOrder.TrueRemaining() - originalOrder.TrueRemaining()
   248  			originalOrder.Remaining = newOrder.Remaining
   249  			originalOrder.Size = newOrder.Size
   250  
   251  			// copy across iceberg reserves
   252  			if originalOrder.IcebergOrder != nil {
   253  				originalOrder.IcebergOrder = newOrder.IcebergOrder.Clone()
   254  			}
   255  			md.changes = append(md.changes, pl)
   256  		}
   257  	} else {
   258  		md.removeOrder(originalOrder)
   259  		if newOrder.TrueRemaining() > 0 {
   260  			md.addOrder(newOrder)
   261  		}
   262  	}
   263  }
   264  
   265  func (md *MarketDepth) getPriceLevel(side types.Side, price *num.Uint) *priceLevel {
   266  	var i int
   267  	if side == types.SideBuy {
   268  		// buy side levels should be ordered in descending
   269  		i = sort.Search(len(md.buySide), func(i int) bool { return md.buySide[i].price.LTE(price) })
   270  		if i < len(md.buySide) && md.buySide[i].price.EQ(price) {
   271  			return md.buySide[i]
   272  		}
   273  	} else {
   274  		// sell side levels should be ordered in ascending
   275  		i = sort.Search(len(md.sellSide), func(i int) bool { return md.sellSide[i].price.GTE(price) })
   276  		if i < len(md.sellSide) && md.sellSide[i].price.EQ(price) {
   277  			return md.sellSide[i]
   278  		}
   279  	}
   280  	return nil
   281  }
   282  
   283  func (md *MarketDepth) removePriceLevel(order *types.Order) {
   284  	var i int
   285  	if order.Side == types.SideBuy {
   286  		// buy side levels should be ordered in descending
   287  		i = sort.Search(len(md.buySide), func(i int) bool { return md.buySide[i].price.LTE(order.Price) })
   288  		if i < len(md.buySide) && md.buySide[i].price.EQ(order.Price) {
   289  			copy(md.buySide[i:], md.buySide[i+1:])
   290  			md.buySide[len(md.buySide)-1] = nil
   291  			md.buySide = md.buySide[:len(md.buySide)-1]
   292  		}
   293  	} else {
   294  		// sell side levels should be ordered in ascending
   295  		i = sort.Search(len(md.sellSide), func(i int) bool { return md.sellSide[i].price.GTE(order.Price) })
   296  		// we found the level just return it.
   297  		if i < len(md.sellSide) && md.sellSide[i].price.EQ(order.Price) {
   298  			copy(md.sellSide[i:], md.sellSide[i+1:])
   299  			md.sellSide[len(md.sellSide)-1] = nil
   300  			md.sellSide = md.sellSide[:len(md.sellSide)-1]
   301  		}
   302  	}
   303  }
   304  
   305  func (mdb *MarketDepthBuilder) updateMarketDepth(order *types.Order) {
   306  	mdb.mu.Lock()
   307  	defer mdb.mu.Unlock()
   308  
   309  	// Non persistent and network orders do not matter
   310  	if order.Type == types.OrderTypeMarket ||
   311  		order.TimeInForce == types.OrderTimeInForceFOK ||
   312  		order.TimeInForce == types.OrderTimeInForceIOC {
   313  		return
   314  	}
   315  
   316  	// Orders that where not valid are ignored
   317  	if order.Status == types.OrderStatusUnspecified {
   318  		return
   319  	}
   320  
   321  	// See if we already have a MarketDepth item for this market
   322  	md := mdb.marketDepths[order.MarketID]
   323  	if md == nil {
   324  		// First time we have an update for this market
   325  		// so we need to create a new MarketDepth
   326  		md = &MarketDepth{
   327  			marketID:   order.MarketID,
   328  			liveOrders: map[string]*types.Order{},
   329  		}
   330  		mdb.marketDepths[order.MarketID] = md
   331  	}
   332  
   333  	// Initialise changes slice ready for new items
   334  	md.changes = []*priceLevel{}
   335  
   336  	// Do we know about this order already?
   337  	originalOrder := md.orderExists(order.ID)
   338  	if originalOrder != nil {
   339  		// Check to see if we are updating the order or removing it
   340  		if order.Status == types.OrderStatusCancelled ||
   341  			order.Status == types.OrderStatusExpired ||
   342  			order.Status == types.OrderStatusStopped ||
   343  			order.Status == types.OrderStatusFilled ||
   344  			order.Status == types.OrderStatusPartiallyFilled ||
   345  			order.Status == types.OrderStatusRejected ||
   346  			order.Status == types.OrderStatusParked {
   347  			md.removeOrder(originalOrder)
   348  		} else {
   349  			md.updateOrder(originalOrder, order)
   350  		}
   351  	} else {
   352  		if order.TrueRemaining() > 0 && order.Status == types.OrderStatusActive {
   353  			md.addOrder(order)
   354  		}
   355  	}
   356  
   357  	// If nothing changed we can stop here
   358  	if len(md.changes) == 0 {
   359  		return
   360  	}
   361  	md.sequenceNumber++
   362  
   363  	buyPtr := []*types.PriceLevel{}
   364  	sellPtr := []*types.PriceLevel{}
   365  
   366  	// Send out market depth updates to any listeners
   367  	for _, pl := range md.changes {
   368  		if pl.side == types.SideBuy {
   369  			buyPtr = append(buyPtr, &types.PriceLevel{
   370  				Price:          pl.price.Clone(),
   371  				NumberOfOrders: pl.totalOrders,
   372  				Volume:         pl.totalVolume,
   373  			})
   374  		} else {
   375  			sellPtr = append(sellPtr, &types.PriceLevel{
   376  				Price:          pl.price.Clone(),
   377  				NumberOfOrders: pl.totalOrders,
   378  				Volume:         pl.totalVolume,
   379  			})
   380  		}
   381  	}
   382  
   383  	marketDepthUpdate := &types.MarketDepthUpdate{
   384  		MarketId:       order.MarketID,
   385  		Buy:            types.PriceLevels(buyPtr).IntoProto(),
   386  		Sell:           types.PriceLevels(sellPtr).IntoProto(),
   387  		SequenceNumber: md.sequenceNumber,
   388  	}
   389  
   390  	for _, channel := range mdb.subscribers {
   391  		channel <- marketDepthUpdate
   392  	}
   393  
   394  	// Clear the list of changes
   395  	md.changes = make([]*priceLevel, 0, len(md.changes))
   396  }
   397  
   398  // Returns the min of 2 uint64s.
   399  func min(x, y uint64) uint64 {
   400  	if y < x {
   401  		return y
   402  	}
   403  	return x
   404  }
   405  
   406  // GetMarketDepth builds up the structure to be sent out to any market depth listeners.
   407  func (mdb *MarketDepthBuilder) GetMarketDepth(ctx context.Context, market string, limit uint64) (*types.MarketDepth, error) {
   408  	mdb.mu.RLock()
   409  	defer mdb.mu.RUnlock()
   410  	md, ok := mdb.marketDepths[market]
   411  	if !ok || md == nil {
   412  		// When a market is new with no orders there will not be any market depth/order book
   413  		// so we do not need to try and calculate the depth cumulative volumes etc
   414  		return &types.MarketDepth{
   415  			MarketId: market,
   416  			Buy:      []*ptypes.PriceLevel{},
   417  			Sell:     []*ptypes.PriceLevel{},
   418  		}, nil
   419  	}
   420  
   421  	buyLimit := uint64(len(md.buySide))
   422  	sellLimit := uint64(len(md.sellSide))
   423  	if limit > 0 {
   424  		buyLimit = min(buyLimit, limit)
   425  		sellLimit = min(sellLimit, limit)
   426  	}
   427  
   428  	buyPtr := make([]*types.PriceLevel, buyLimit)
   429  	sellPtr := make([]*types.PriceLevel, sellLimit)
   430  
   431  	// Copy the data across
   432  	for index, pl := range md.buySide[:buyLimit] {
   433  		buyPtr[index] = &types.PriceLevel{
   434  			Volume:         pl.totalVolume,
   435  			NumberOfOrders: pl.totalOrders,
   436  			Price:          pl.price.Clone(),
   437  		}
   438  	}
   439  
   440  	for index, pl := range md.sellSide[:sellLimit] {
   441  		sellPtr[index] = &types.PriceLevel{
   442  			Volume:         pl.totalVolume,
   443  			NumberOfOrders: pl.totalOrders,
   444  			Price:          pl.price.Clone(),
   445  		}
   446  	}
   447  
   448  	return &types.MarketDepth{
   449  		MarketId:       market,
   450  		Buy:            types.PriceLevels(buyPtr).IntoProto(),
   451  		Sell:           types.PriceLevels(sellPtr).IntoProto(),
   452  		SequenceNumber: md.sequenceNumber,
   453  	}, nil
   454  }
   455  
   456  /*****************************************************************************/
   457  /*                 FUNCTIONS TO HELP WITH UNIT TESTING                       */
   458  /*****************************************************************************/
   459  
   460  func (mdb *MarketDepthBuilder) GetAllOrders(market string) map[string]*types.Order {
   461  	if md := mdb.marketDepths[market]; md != nil {
   462  		return md.liveOrders
   463  	}
   464  	return nil
   465  }
   466  
   467  // GetOrderCount returns the number of live orders for the given market.
   468  func (mdb *MarketDepthBuilder) GetOrderCount(market string) int64 {
   469  	var (
   470  		liveOrders int64
   471  		bookOrders uint64
   472  	)
   473  	if md := mdb.marketDepths[market]; md != nil {
   474  		liveOrders = int64(len(md.liveOrders))
   475  
   476  		for _, pl := range md.buySide {
   477  			bookOrders += pl.totalOrders
   478  		}
   479  
   480  		for _, pl := range md.sellSide {
   481  			bookOrders += pl.totalOrders
   482  		}
   483  
   484  		if liveOrders != int64(bookOrders) {
   485  			return -1
   486  		}
   487  		return liveOrders
   488  	}
   489  	return 0
   490  }
   491  
   492  // GetVolumeAtPrice returns the order volume at the given price level.
   493  func (mdb *MarketDepthBuilder) GetVolumeAtPrice(market string, side types.Side, price uint64) uint64 {
   494  	if md := mdb.marketDepths[market]; md != nil {
   495  		pl := md.getPriceLevel(side, num.NewUint(price))
   496  		if pl == nil {
   497  			return 0
   498  		}
   499  		return pl.totalVolume
   500  	}
   501  	return 0
   502  }
   503  
   504  // GetTotalVolume returns the total volume in the order book.
   505  func (mdb *MarketDepthBuilder) GetTotalVolume(market string) int64 {
   506  	var volume int64
   507  	if md := mdb.marketDepths[market]; md != nil {
   508  		for _, pl := range md.buySide {
   509  			volume += int64(pl.totalVolume)
   510  		}
   511  
   512  		for _, pl := range md.sellSide {
   513  			volume += int64(pl.totalVolume)
   514  		}
   515  		return volume
   516  	}
   517  	return 0
   518  }
   519  
   520  // GetOrderCountAtPrice returns the number of orders at the given price level.
   521  func (mdb *MarketDepthBuilder) GetOrderCountAtPrice(market string, side types.Side, price uint64) uint64 {
   522  	if md := mdb.marketDepths[market]; md != nil {
   523  		pl := md.getPriceLevel(side, num.NewUint(price))
   524  		if pl == nil {
   525  			return 0
   526  		}
   527  		return pl.totalOrders
   528  	}
   529  	return 0
   530  }
   531  
   532  // GetPriceLevels returns the number of non empty price levels.
   533  func (mdb *MarketDepthBuilder) GetPriceLevels(market string) int {
   534  	return mdb.GetBuyPriceLevels(market) + mdb.GetSellPriceLevels(market)
   535  }
   536  
   537  // GetBestBidPrice returns the highest bid price in the book.
   538  func (mdb *MarketDepthBuilder) GetBestBidPrice(market string) *num.Uint {
   539  	md := mdb.marketDepths[market]
   540  	if md != nil {
   541  		if len(md.buySide) > 0 {
   542  			return md.buySide[0].price.Clone()
   543  		}
   544  	}
   545  	return num.UintZero()
   546  }
   547  
   548  // GetBestAskPrice returns the highest bid price in the book.
   549  func (mdb *MarketDepthBuilder) GetBestAskPrice(market string) *num.Uint {
   550  	md := mdb.marketDepths[market]
   551  	if md != nil {
   552  		if len(md.sellSide) > 0 {
   553  			return md.sellSide[0].price.Clone()
   554  		}
   555  	}
   556  	return num.UintZero()
   557  }
   558  
   559  // GetBuyPriceLevels returns the number of non empty buy price levels.
   560  func (mdb *MarketDepthBuilder) GetBuyPriceLevels(market string) int {
   561  	if md := mdb.marketDepths[market]; md != nil {
   562  		return len(md.buySide)
   563  	}
   564  	return 0
   565  }
   566  
   567  // GetSellPriceLevels returns the number of non empty sell price levels.
   568  func (mdb *MarketDepthBuilder) GetSellPriceLevels(market string) int {
   569  	if md := mdb.marketDepths[market]; md != nil {
   570  		return len(md.sellSide)
   571  	}
   572  	return 0
   573  }
   574  
   575  // Subscribe allows a client to register for updates of the market depth book.
   576  func (mdb *MarketDepthBuilder) Subscribe(updates chan<- *types.MarketDepthUpdate) uint64 {
   577  	mdb.mu.Lock()
   578  	defer mdb.mu.Unlock()
   579  
   580  	mdb.subscriberID++
   581  	mdb.subscribers[mdb.subscriberID] = updates
   582  
   583  	return mdb.subscriberID
   584  }
   585  
   586  // Unsubscribe allows the client to unregister interest in market depth updates.
   587  func (mdb *MarketDepthBuilder) Unsubscribe(id uint64) error {
   588  	mdb.mu.Lock()
   589  	defer mdb.mu.Unlock()
   590  
   591  	if len(mdb.subscribers) == 0 {
   592  		return nil
   593  	}
   594  
   595  	if _, exists := mdb.subscribers[id]; exists {
   596  		delete(mdb.subscribers, id)
   597  		return nil
   598  	}
   599  
   600  	return fmt.Errorf("subscriber to market depth updates does not exist with id: %d", id)
   601  }