code.vegaprotocol.io/vega@v0.79.0/core/execution/spot/auction.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 spot
    17  
    18  import (
    19  	"context"
    20  	"time"
    21  
    22  	"code.vegaprotocol.io/vega/core/execution/common"
    23  	"code.vegaprotocol.io/vega/core/types"
    24  	"code.vegaprotocol.io/vega/libs/num"
    25  	"code.vegaprotocol.io/vega/logging"
    26  )
    27  
    28  func (m *Market) checkAuction(ctx context.Context, now time.Time, idgen common.IDGenerator) {
    29  	if !m.as.InAuction() {
    30  		if m.as.AuctionStart() {
    31  			m.enterAuction(ctx)
    32  		}
    33  		return
    34  	}
    35  
    36  	if m.mkt.State == types.MarketStateSuspendedViaGovernance {
    37  		if endTS := m.as.ExpiresAt(); endTS != nil && endTS.Before(now) {
    38  			m.as.ExtendAuctionSuspension(types.AuctionDuration{Duration: int64(m.minDuration.Seconds())})
    39  		}
    40  	}
    41  
    42  	// here we are in auction, we'll want to check
    43  	// the triggers if we are leaving
    44  	defer func() {
    45  		m.triggerStopOrders(ctx, idgen)
    46  	}()
    47  
    48  	indicativeUncrossingPrice := num.UintZero()
    49  
    50  	checkExceeded := m.mkt.State == types.MarketStatePending
    51  	// as soon as we have an indicative uncrossing price in opening auction it needs to be passed into the price monitoring engine so statevar calculation can start
    52  	isOpening := m.as.IsOpeningAuction()
    53  	if isOpening && !m.pMonitor.Initialised() {
    54  		indicativeUncrossingPrice = m.matching.OrderBook.GetIndicativePrice()
    55  
    56  		if !indicativeUncrossingPrice.IsZero() {
    57  			// pass the first uncrossing price to price monitoring engine so state variables depending on it can be initialised
    58  			m.pMonitor.ResetPriceHistory(indicativeUncrossingPrice)
    59  			m.OnOpeningAuctionFirstUncrossingPrice()
    60  		}
    61  		if checkExceeded && m.as.ExceededMaxOpening(now) {
    62  			m.closeSpotMarket(ctx)
    63  			return
    64  		}
    65  	}
    66  
    67  	if endTS := m.as.ExpiresAt(); endTS == nil || !endTS.Before(now) {
    68  		if checkExceeded && isOpening && m.as.ExceededMaxOpening(now) {
    69  			m.closeSpotMarket(ctx)
    70  		}
    71  		return
    72  	}
    73  	if indicativeUncrossingPrice.IsZero() {
    74  		indicativeUncrossingPrice = m.matching.OrderBook.GetIndicativePrice()
    75  	}
    76  
    77  	// opening auction
    78  	if isOpening {
    79  		if indicativeUncrossingPrice.IsZero() {
    80  			if checkExceeded && m.as.ExceededMaxOpening(now) {
    81  				m.closeSpotMarket(ctx)
    82  			}
    83  			return
    84  		}
    85  
    86  		// opening auction period has expired, and we have trades, we should be ready to leave
    87  		// other requirements still need to be checked downstream though
    88  		m.as.SetReadyToLeave()
    89  
    90  		// if we don't have yet consensus for the floating point parameters, stay in the opening auction
    91  		if !m.CanLeaveOpeningAuction() {
    92  			m.log.Info("cannot leave opening auction - waiting for floating point to complete the first round")
    93  			return
    94  		}
    95  		m.log.Info("leaving opening auction for market", logging.String("market-id", m.mkt.ID))
    96  		m.leaveAuction(ctx, now)
    97  
    98  		m.equityShares.OpeningAuctionEnded()
    99  		// start the market fee window
   100  		m.feeSplitter.TimeWindowStart(now)
   101  
   102  		// reset SLA epoch
   103  		m.liquidity.OnEpochStart(ctx,
   104  			m.timeService.GetTimeNow(),
   105  			m.getCurrentMarkPrice(),
   106  			m.midPrice(),
   107  			m.getTargetStake(),
   108  			m.positionFactor,
   109  		)
   110  
   111  		return
   112  	}
   113  
   114  	if m.as.Trigger() == types.AuctionTriggerLongBlock || m.as.ExtensionTrigger() == types.AuctionTriggerLongBlock ||
   115  		m.as.Trigger() == types.AuctionTriggerAutomatedPurchase || m.as.ExtensionTrigger() == types.AuctionTriggerAutomatedPurchase {
   116  		if endTS := m.as.ExpiresAt(); endTS != nil && endTS.Before(now) {
   117  			m.as.SetReadyToLeave()
   118  		}
   119  	}
   120  
   121  	isPrice := m.as.IsPriceAuction() || m.as.IsPriceExtension()
   122  	if isPrice || m.as.CanLeave() {
   123  		m.pMonitor.CheckPrice(ctx, m.as, indicativeUncrossingPrice, true, true)
   124  	}
   125  	end := m.as.CanLeave()
   126  	if evt := m.as.AuctionExtended(ctx, m.timeService.GetTimeNow()); evt != nil {
   127  		m.broker.Send(evt)
   128  		end = false
   129  	}
   130  	// price monitoring engine and liquidity monitoring engine both indicated auction can end
   131  	if end {
   132  		// can we leave based on the book state?
   133  		m.leaveAuction(ctx, now)
   134  	}
   135  }