code.vegaprotocol.io/vega@v0.79.0/core/execution/spot/special_orders.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  //lint:file-ignore U1000 Ignore unused functions
    17  
    18  package spot
    19  
    20  import (
    21  	"context"
    22  
    23  	"code.vegaprotocol.io/vega/core/events"
    24  	"code.vegaprotocol.io/vega/core/execution/common"
    25  	"code.vegaprotocol.io/vega/core/metrics"
    26  	"code.vegaprotocol.io/vega/core/types"
    27  	"code.vegaprotocol.io/vega/libs/num"
    28  	"code.vegaprotocol.io/vega/logging"
    29  )
    30  
    31  func (m *Market) repricePeggedOrders(ctx context.Context, changes uint8) (parked []*types.Order, toSubmit []*types.Order) {
    32  	timer := metrics.NewTimeCounter(m.mkt.ID, "market", "repricePeggedOrders")
    33  
    34  	// Go through *all* of the pegged orders and remove from the order book
    35  	// NB: this is getting all of the pegged orders that are unparked in the order book AND all
    36  	// the parked pegged orders.
    37  	allPeggedIDs := m.matching.GetActivePeggedOrderIDs()
    38  	allPeggedIDs = append(allPeggedIDs, m.peggedOrders.GetParkedIDs()...)
    39  	for _, oid := range allPeggedIDs {
    40  		var (
    41  			order *types.Order
    42  			err   error
    43  		)
    44  		if m.peggedOrders.IsParked(oid) {
    45  			order = m.peggedOrders.GetParkedByID(oid)
    46  		} else {
    47  			order, err = m.matching.GetOrderByID(oid)
    48  			if err != nil {
    49  				m.log.Panic("if order is not parked, it should be on the book", logging.OrderID(oid))
    50  			}
    51  		}
    52  		if common.OrderReferenceCheck(*order).HasMoved(changes) {
    53  			// First if the order isn't parked, then
    54  			// we will just remove if from the orderbook
    55  			if order.Status != types.OrderStatusParked {
    56  				// Remove order if any volume remains,
    57  				// otherwise it's already been popped by the matching engine.
    58  				m.releaseOrderFromHoldingAccount(ctx, order.ID, order.Party, order.Side)
    59  				cancellation, err := m.matching.CancelOrder(order)
    60  				if cancellation == nil || err != nil {
    61  					m.log.Panic("Failure after cancel order from matching engine",
    62  						logging.Order(*order),
    63  						logging.Error(err))
    64  				}
    65  			} else {
    66  				// unpark before it's reparked next eventually
    67  				m.peggedOrders.Unpark(order.ID)
    68  			}
    69  
    70  			if price, err := m.getNewPeggedPrice(order); err != nil {
    71  				// Failed to reprice, we need to park again
    72  				order.UpdatedAt = m.timeService.GetTimeNow().UnixNano()
    73  				order.Status = types.OrderStatusParked
    74  				order.Price = num.UintZero()
    75  				order.OriginalPrice = nil
    76  				m.broker.Send(events.NewOrderEvent(ctx, order))
    77  				parked = append(parked, order)
    78  			} else {
    79  				// Repriced so all good make sure status is correct
    80  				order.Price = price.Clone()
    81  				order.OriginalPrice, _ = num.UintFromDecimal(price.ToDecimal().Div(m.priceFactor))
    82  				order.Status = types.OrderStatusActive
    83  				order.UpdatedAt = m.timeService.GetTimeNow().UnixNano()
    84  				toSubmit = append(toSubmit, order)
    85  			}
    86  		}
    87  	}
    88  
    89  	timer.EngineTimeCounterAdd()
    90  	return parked, toSubmit
    91  }
    92  
    93  func (m *Market) reSubmitPeggedOrders(ctx context.Context, toSubmitOrders []*types.Order) []*types.Order {
    94  	var (
    95  		updatedOrders = []*types.Order{}
    96  		evts          = []events.Event{}
    97  	)
    98  
    99  	// Reinsert all the orders
   100  	for _, order := range toSubmitOrders {
   101  		if err := m.checkSufficientFunds(order.Party, order.Side, order.Price, order.TrueRemaining(), order.PeggedOrder != nil, types.AccountTypeGeneral); err != nil {
   102  			order.Status = types.OrderStatusStopped
   103  			m.removePeggedOrder(order)
   104  			evts = append(evts, events.NewOrderEvent(ctx, order))
   105  			continue
   106  		}
   107  		m.transferToHoldingAccount(ctx, order)
   108  		m.matching.ReSubmitSpecialOrders(order)
   109  		updatedOrders = append(updatedOrders, order)
   110  		evts = append(evts, events.NewOrderEvent(ctx, order))
   111  	}
   112  
   113  	// send new order events
   114  	m.broker.SendBatch(evts)
   115  
   116  	return updatedOrders
   117  }
   118  
   119  func (m *Market) repriceAllSpecialOrders(
   120  	ctx context.Context,
   121  	changes uint8,
   122  ) {
   123  	if changes == 0 {
   124  		// nothing to do, prices didn't move,
   125  		// no orders have been updated, there's no
   126  		// reason pegged order should get repriced or
   127  		// lp to be differnet than before
   128  		return
   129  	}
   130  
   131  	// first we get all the pegged orders to be resubmitted with a new price
   132  	var parked, toSubmit []*types.Order
   133  	if changes != 0 {
   134  		parked, toSubmit = m.repricePeggedOrders(ctx, changes)
   135  		for _, topark := range parked {
   136  			m.peggedOrders.Park(topark)
   137  		}
   138  	}
   139  
   140  	// if we needed to re-submit pegged orders,
   141  	// let's do it now
   142  	if len(toSubmit) > 0 {
   143  		m.reSubmitPeggedOrders(ctx, toSubmit)
   144  	}
   145  }
   146  
   147  func (m *Market) enterAuctionSpecialOrders(ctx context.Context) {
   148  	// first remove all GFN orders from the peg list
   149  	ordersEvts := m.peggedOrders.EnterAuction(ctx)
   150  	m.broker.SendBatch(ordersEvts)
   151  	m.parkAllPeggedOrders(ctx)
   152  }