code.vegaprotocol.io/vega@v0.79.0/core/types/matching.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 types
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  	"code.vegaprotocol.io/vega/libs/ptr"
    25  	"code.vegaprotocol.io/vega/libs/stringer"
    26  	proto "code.vegaprotocol.io/vega/protos/vega"
    27  )
    28  
    29  type Order struct {
    30  	ID               string
    31  	MarketID         string
    32  	Party            string
    33  	Side             Side
    34  	Price            *num.Uint
    35  	OriginalPrice    *num.Uint
    36  	Size             uint64
    37  	Remaining        uint64
    38  	TimeInForce      OrderTimeInForce
    39  	Type             OrderType
    40  	CreatedAt        int64
    41  	Status           OrderStatus
    42  	ExpiresAt        int64
    43  	Reference        string
    44  	Reason           OrderError
    45  	UpdatedAt        int64
    46  	Version          uint64
    47  	BatchID          uint64
    48  	PeggedOrder      *PeggedOrder
    49  	PostOnly         bool
    50  	ReduceOnly       bool
    51  	extraRemaining   uint64
    52  	IcebergOrder     *IcebergOrder
    53  	GeneratedOffbook bool
    54  }
    55  
    56  func (o *Order) ReduceOnlyAdjustRemaining(extraSize uint64) {
    57  	if !o.ReduceOnly {
    58  		panic("order.ReduceOnlyAdjustSize shall be call only on reduce-only orders")
    59  	}
    60  
    61  	o.extraRemaining = extraSize
    62  	o.Remaining -= extraSize
    63  }
    64  
    65  func (o *Order) ClearUpExtraRemaining() {
    66  	// ignore for non reduce only
    67  	if !o.ReduceOnly {
    68  		return
    69  	}
    70  
    71  	o.Remaining += o.extraRemaining
    72  	o.extraRemaining = 0
    73  }
    74  
    75  // TrueRemaining is the full remaining size of an order. If this is an iceberg order
    76  // it will return the visible peak + the hidden volume.
    77  func (o *Order) TrueRemaining() uint64 {
    78  	rem := o.Remaining
    79  	if o.IcebergOrder != nil {
    80  		rem += o.IcebergOrder.ReservedRemaining
    81  	}
    82  	return rem
    83  }
    84  
    85  // IcebergNeedsRefresh returns whether the given iceberg order's visible peak has
    86  // dropped below the minimum visible size, and there is hidden volume available to
    87  // restore it.
    88  func (o *Order) IcebergNeedsRefresh() bool {
    89  	if o.IcebergOrder == nil {
    90  		// not an iceberg
    91  		return false
    92  	}
    93  
    94  	if o.IcebergOrder.ReservedRemaining == 0 {
    95  		// nothing to refresh with
    96  		return false
    97  	}
    98  
    99  	if o.Remaining >= o.IcebergOrder.MinimumVisibleSize {
   100  		// not under the minimum
   101  		return false
   102  	}
   103  
   104  	return true
   105  }
   106  
   107  // SetIcebergPeaks will restore the given iceberg orders visible size with
   108  // some of its hidden volume.
   109  func (o *Order) SetIcebergPeaks() {
   110  	if o.IcebergOrder == nil {
   111  		return
   112  	}
   113  
   114  	if o.Remaining > o.IcebergOrder.PeakSize && o.IcebergOrder.ReservedRemaining == 0 {
   115  		// iceberg is at full volume and so set its visible amount to its peak size
   116  		peak := num.MinV(o.Remaining, o.IcebergOrder.PeakSize)
   117  		o.IcebergOrder.ReservedRemaining = o.Remaining - peak
   118  		o.Remaining = peak
   119  		return
   120  	}
   121  
   122  	// calculate the refill amount
   123  	refill := o.IcebergOrder.PeakSize - o.Remaining
   124  	refill = num.MinV(refill, o.IcebergOrder.ReservedRemaining)
   125  
   126  	o.Remaining += refill
   127  	o.IcebergOrder.ReservedRemaining -= refill
   128  }
   129  
   130  func (o Order) IntoSubmission() *OrderSubmission {
   131  	sub := &OrderSubmission{
   132  		MarketID:    o.MarketID,
   133  		Size:        o.Size,
   134  		Side:        o.Side,
   135  		TimeInForce: o.TimeInForce,
   136  		ExpiresAt:   o.ExpiresAt,
   137  		Type:        o.Type,
   138  		Reference:   o.Reference,
   139  		PostOnly:    o.PostOnly,
   140  		ReduceOnly:  o.ReduceOnly,
   141  	}
   142  	if o.IcebergOrder != nil {
   143  		sub.IcebergOrder = &IcebergOrder{
   144  			PeakSize:           o.IcebergOrder.PeakSize,
   145  			MinimumVisibleSize: o.IcebergOrder.MinimumVisibleSize,
   146  		}
   147  	}
   148  	if o.Price != nil {
   149  		sub.Price = o.Price.Clone()
   150  	}
   151  	if o.PeggedOrder != nil {
   152  		sub.PeggedOrder = o.PeggedOrder.Clone()
   153  	}
   154  
   155  	return sub
   156  }
   157  
   158  func (o Order) Clone() *Order {
   159  	cpy := o
   160  	if o.Price != nil {
   161  		cpy.Price = o.Price.Clone()
   162  	} else {
   163  		cpy.Price = num.UintZero()
   164  	}
   165  	// this isn't really needed, to original order is about to be replaced, or the original price is getting reassinged
   166  	// but in case something goes wrong, we don't want a pointer to this field in 2 places
   167  	if o.OriginalPrice != nil {
   168  		cpy.OriginalPrice = o.OriginalPrice.Clone()
   169  	}
   170  	if o.PeggedOrder != nil {
   171  		cpy.PeggedOrder = o.PeggedOrder.Clone()
   172  	}
   173  	if o.IcebergOrder != nil {
   174  		cpy.IcebergOrder = o.IcebergOrder.Clone()
   175  	}
   176  	return &cpy
   177  }
   178  
   179  func (o Order) String() string {
   180  	return fmt.Sprintf(
   181  		"ID(%s) marketID(%s) party(%s) side(%s) price(%s) size(%v) remaining(%v) timeInForce(%s) type(%s) status(%s) reference(%s) reason(%s) version(%v) batchID(%v) createdAt(%v) updatedAt(%v) expiresAt(%v) originalPrice(%s) peggedOrder(%s) postOnly(%v) reduceOnly(%v) iceberg(%s)",
   182  		o.ID,
   183  		o.MarketID,
   184  		o.Party,
   185  		o.Side.String(),
   186  		num.UintToString(o.Price),
   187  		o.Size,
   188  		o.Remaining,
   189  		o.TimeInForce.String(),
   190  		o.Type.String(),
   191  		o.Status.String(),
   192  		o.Reference,
   193  		o.Reason.String(),
   194  		o.Version,
   195  		o.BatchID,
   196  		o.CreatedAt,
   197  		o.UpdatedAt,
   198  		o.ExpiresAt,
   199  		stringer.PtrToString(o.OriginalPrice),
   200  		stringer.PtrToString(o.PeggedOrder),
   201  		o.PostOnly,
   202  		o.ReduceOnly,
   203  		stringer.PtrToString(o.IcebergOrder),
   204  	)
   205  }
   206  
   207  type Orders []*Order
   208  
   209  func (o Orders) IntoProto() []*proto.Order {
   210  	out := make([]*proto.Order, 0, len(o))
   211  	for _, v := range o {
   212  		out = append(out, v.IntoProto())
   213  	}
   214  	return out
   215  }
   216  
   217  func (o *Order) IntoProto() *proto.Order {
   218  	var pegged *proto.PeggedOrder
   219  	if o.PeggedOrder != nil {
   220  		pegged = o.PeggedOrder.IntoProto()
   221  	}
   222  	var reason *OrderError
   223  	if o.Reason != OrderErrorUnspecified {
   224  		reason = ptr.From(o.Reason)
   225  	}
   226  
   227  	var iceberg *proto.IcebergOrder
   228  	if o.IcebergOrder != nil {
   229  		iceberg = o.IcebergOrder.IntoProto()
   230  	}
   231  
   232  	return &proto.Order{
   233  		Id:           o.ID,
   234  		MarketId:     o.MarketID,
   235  		PartyId:      o.Party,
   236  		Side:         o.Side,
   237  		Price:        num.UintToString(o.Price),
   238  		Size:         o.Size,
   239  		Remaining:    o.Remaining,
   240  		TimeInForce:  o.TimeInForce,
   241  		Type:         o.Type,
   242  		CreatedAt:    o.CreatedAt,
   243  		Status:       o.Status,
   244  		ExpiresAt:    o.ExpiresAt,
   245  		Reference:    o.Reference,
   246  		Reason:       reason,
   247  		UpdatedAt:    o.UpdatedAt,
   248  		Version:      o.Version,
   249  		BatchId:      o.BatchID,
   250  		PeggedOrder:  pegged,
   251  		PostOnly:     o.PostOnly,
   252  		ReduceOnly:   o.ReduceOnly,
   253  		IcebergOrder: iceberg,
   254  	}
   255  }
   256  
   257  func OrderFromProto(o *proto.Order) (*Order, error) {
   258  	var iceberg *IcebergOrder
   259  	if o.IcebergOrder != nil {
   260  		var err error
   261  		iceberg, err = NewIcebergOrderFromProto(o.IcebergOrder)
   262  		if err != nil {
   263  			return nil, err
   264  		}
   265  	}
   266  	var pegged *PeggedOrder
   267  	if o.PeggedOrder != nil {
   268  		var err error
   269  		pegged, err = NewPeggedOrderFromProto(o.PeggedOrder)
   270  		if err != nil {
   271  			return nil, err
   272  		}
   273  	}
   274  	price := num.UintZero()
   275  	if len(o.Price) > 0 {
   276  		var overflowed bool
   277  		price, overflowed = num.UintFromString(o.Price, 10)
   278  		if overflowed {
   279  			return nil, errors.New("invalid price")
   280  		}
   281  	}
   282  	reason := OrderErrorUnspecified
   283  	if o.Reason != nil {
   284  		reason = *o.Reason
   285  	}
   286  	return &Order{
   287  		ID:           o.Id,
   288  		MarketID:     o.MarketId,
   289  		Party:        o.PartyId,
   290  		Side:         o.Side,
   291  		Price:        price,
   292  		Size:         o.Size,
   293  		Remaining:    o.Remaining,
   294  		TimeInForce:  o.TimeInForce,
   295  		Type:         o.Type,
   296  		CreatedAt:    o.CreatedAt,
   297  		Status:       o.Status,
   298  		ExpiresAt:    o.ExpiresAt,
   299  		Reference:    o.Reference,
   300  		Reason:       reason,
   301  		UpdatedAt:    o.UpdatedAt,
   302  		Version:      o.Version,
   303  		BatchID:      o.BatchId,
   304  		PeggedOrder:  pegged,
   305  		PostOnly:     o.PostOnly,
   306  		ReduceOnly:   o.ReduceOnly,
   307  		IcebergOrder: iceberg,
   308  	}, nil
   309  }
   310  
   311  // Create sets the creation time (CreatedAt) to t and returns the
   312  // updated order.
   313  func (o *Order) Create(t int64) *Order {
   314  	o.CreatedAt = t
   315  	return o
   316  }
   317  
   318  // Update sets the modification time (UpdatedAt) to t and returns the
   319  // updated order.
   320  func (o *Order) Update(t time.Time) *Order {
   321  	o.UpdatedAt = t.UnixNano()
   322  	return o
   323  }
   324  
   325  // IsPersistent returns true if the order is persistent.
   326  // A persistent order is a Limit type order that might be
   327  // matched in the future.
   328  func (o *Order) IsPersistent() bool {
   329  	return (o.TimeInForce == OrderTimeInForceGTC ||
   330  		o.TimeInForce == OrderTimeInForceGTT ||
   331  		o.TimeInForce == OrderTimeInForceGFN ||
   332  		o.TimeInForce == OrderTimeInForceGFA) &&
   333  		o.Type == OrderTypeLimit &&
   334  		o.Remaining > 0
   335  }
   336  
   337  func (o *Order) IsExpireable() bool {
   338  	return (o.TimeInForce == OrderTimeInForceGFN ||
   339  		o.TimeInForce == OrderTimeInForceGTT ||
   340  		o.TimeInForce == OrderTimeInForceGFA) &&
   341  		o.ExpiresAt > 0
   342  }
   343  
   344  // IsFinished returns true if an order
   345  // is in any state different to ACTIVE and PARKED
   346  // Basically any order which is never gonna
   347  // trade anymore.
   348  func (o *Order) IsFinished() bool {
   349  	return o.Status != OrderStatusActive && o.Status != OrderStatusParked
   350  }
   351  
   352  func (o *Order) HasTraded() bool {
   353  	return o.Size != o.Remaining
   354  }
   355  
   356  func (o *Order) applyOrderAmendmentSizeIceberg(delta int64) {
   357  	// handle increase in size
   358  	if delta > 0 {
   359  		o.Size += uint64(delta)
   360  		o.IcebergOrder.ReservedRemaining += uint64(delta)
   361  		return
   362  	}
   363  
   364  	// handle decrease in size
   365  	dec := uint64(-delta)
   366  	o.Size -= dec
   367  
   368  	if o.IcebergOrder.ReservedRemaining >= dec {
   369  		o.IcebergOrder.ReservedRemaining -= dec
   370  		return
   371  	}
   372  
   373  	diff := dec - o.IcebergOrder.ReservedRemaining
   374  	if o.Remaining > diff {
   375  		o.Remaining -= dec - o.IcebergOrder.ReservedRemaining
   376  	} else {
   377  		o.Remaining = 0
   378  	}
   379  	o.IcebergOrder.ReservedRemaining = 0
   380  }
   381  
   382  func (o *Order) amendSize(size uint64) {
   383  	o.amendSizeWithDelta(int64(size) - int64(o.Size))
   384  }
   385  
   386  // amendSizeWithDelta update the orders size/remaining fields based on the size
   387  // an direction of the given delta.
   388  func (o *Order) amendSizeWithDelta(delta int64) {
   389  	if o.IcebergOrder != nil {
   390  		o.applyOrderAmendmentSizeIceberg(delta)
   391  		return
   392  	}
   393  
   394  	// handle size increase
   395  	if delta > 0 {
   396  		o.Size += uint64(delta)
   397  		o.Remaining += uint64(delta)
   398  		return
   399  	}
   400  
   401  	// handle size decrease
   402  	dec := uint64(-delta)
   403  	o.Size -= dec
   404  	if o.Remaining > dec {
   405  		o.Remaining -= dec
   406  	} else {
   407  		o.Remaining = 0
   408  	}
   409  }
   410  
   411  // ApplyOrderAmendment assumes the amendment have been validated before.
   412  func (o *Order) ApplyOrderAmendment(amendment *OrderAmendment, updatedAtNano int64, priceFactor num.Decimal) (order *Order, err error) {
   413  	order = o.Clone()
   414  	order.UpdatedAt = updatedAtNano
   415  	order.Version++
   416  
   417  	if o.PeggedOrder != nil {
   418  		order.PeggedOrder = &PeggedOrder{
   419  			Reference: o.PeggedOrder.Reference,
   420  			Offset:    o.PeggedOrder.Offset,
   421  		}
   422  	}
   423  
   424  	var amendPrice *num.Uint
   425  	if amendment.Price != nil {
   426  		amendPrice, _ = num.UintFromDecimal(amendment.Price.ToDecimal().Mul(priceFactor))
   427  	}
   428  	// apply price changes
   429  	if amendment.Price != nil && o.Price.NEQ(amendPrice) {
   430  		order.Price = amendPrice.Clone()
   431  		order.OriginalPrice = amendment.Price.Clone()
   432  	}
   433  
   434  	if amendment.Size != nil {
   435  		order.amendSize(*amendment.Size)
   436  	}
   437  
   438  	if delta := amendment.SizeDelta; delta != 0 {
   439  		order.amendSizeWithDelta(delta)
   440  	}
   441  
   442  	// apply tif
   443  	if amendment.TimeInForce != OrderTimeInForceUnspecified {
   444  		order.TimeInForce = amendment.TimeInForce
   445  		if amendment.TimeInForce != OrderTimeInForceGTT {
   446  			order.ExpiresAt = 0
   447  		}
   448  	}
   449  	if amendment.ExpiresAt != nil {
   450  		order.ExpiresAt = *amendment.ExpiresAt
   451  	}
   452  
   453  	// apply pegged order values
   454  	if order.PeggedOrder != nil {
   455  		if amendment.PeggedOffset != nil {
   456  			order.PeggedOrder.Offset = amendment.PeggedOffset.Clone()
   457  		}
   458  
   459  		if amendment.PeggedReference != PeggedReferenceUnspecified {
   460  			order.PeggedOrder.Reference = amendment.PeggedReference
   461  		}
   462  		if verr := order.ValidatePeggedOrder(); verr != OrderErrorUnspecified {
   463  			err = verr
   464  		}
   465  	}
   466  
   467  	return order, err
   468  }
   469  
   470  func (order *Order) ValidatePeggedOrder() OrderError {
   471  	if order.Type != OrderTypeLimit {
   472  		// All pegged orders must be LIMIT orders
   473  		return ErrPeggedOrderMustBeLimitOrder
   474  	}
   475  
   476  	if order.TimeInForce != OrderTimeInForceGTT && order.TimeInForce != OrderTimeInForceGTC && order.TimeInForce != OrderTimeInForceGFN {
   477  		// Pegged orders can only be GTC or GTT
   478  		return ErrPeggedOrderMustBeGTTOrGTC
   479  	}
   480  
   481  	if order.PeggedOrder.Reference == PeggedReferenceUnspecified {
   482  		// We must specify a valid reference
   483  		return ErrPeggedOrderWithoutReferencePrice
   484  	}
   485  
   486  	if order.Side == SideBuy {
   487  		switch order.PeggedOrder.Reference {
   488  		case PeggedReferenceBestAsk:
   489  			return ErrPeggedOrderBuyCannotReferenceBestAskPrice
   490  		case PeggedReferenceMid:
   491  			if order.PeggedOrder.Offset.IsZero() {
   492  				return ErrPeggedOrderOffsetMustBeGreaterThanZero
   493  			}
   494  		}
   495  	} else {
   496  		switch order.PeggedOrder.Reference {
   497  		case PeggedReferenceBestBid:
   498  			return ErrPeggedOrderSellCannotReferenceBestBidPrice
   499  		case PeggedReferenceMid:
   500  			if order.PeggedOrder.Offset.IsZero() {
   501  				return ErrPeggedOrderOffsetMustBeGreaterThanZero
   502  			}
   503  		}
   504  	}
   505  	return OrderErrorUnspecified
   506  }
   507  
   508  type PeggedOrder struct {
   509  	Reference PeggedReference
   510  	Offset    *num.Uint
   511  }
   512  
   513  func (p PeggedOrder) Clone() *PeggedOrder {
   514  	cpy := p
   515  	return &cpy
   516  }
   517  
   518  func NewPeggedOrderFromProto(p *proto.PeggedOrder) (*PeggedOrder, error) {
   519  	if p == nil {
   520  		return nil, nil
   521  	}
   522  
   523  	offset, overflowed := num.UintFromString(p.Offset, 10)
   524  	if overflowed {
   525  		return nil, errors.New("invalid offset")
   526  	}
   527  
   528  	return &PeggedOrder{
   529  		Reference: p.Reference,
   530  		Offset:    offset,
   531  	}, nil
   532  }
   533  
   534  func (p PeggedOrder) IntoProto() *proto.PeggedOrder {
   535  	return &proto.PeggedOrder{
   536  		Reference: p.Reference,
   537  		Offset:    p.Offset.String(),
   538  	}
   539  }
   540  
   541  func (p PeggedOrder) String() string {
   542  	return fmt.Sprintf(
   543  		"reference(%s) offset(%s)",
   544  		p.Reference.String(),
   545  		stringer.PtrToString(p.Offset),
   546  	)
   547  }
   548  
   549  type IcebergOrder struct {
   550  	ReservedRemaining  uint64
   551  	PeakSize           uint64
   552  	MinimumVisibleSize uint64
   553  }
   554  
   555  func (i IcebergOrder) Clone() *IcebergOrder {
   556  	cpy := i
   557  	return &cpy
   558  }
   559  
   560  func NewIcebergOrderFromProto(i *proto.IcebergOrder) (*IcebergOrder, error) {
   561  	if i == nil {
   562  		return nil, nil
   563  	}
   564  	return &IcebergOrder{
   565  		ReservedRemaining:  i.ReservedRemaining,
   566  		PeakSize:           i.PeakSize,
   567  		MinimumVisibleSize: i.MinimumVisibleSize,
   568  	}, nil
   569  }
   570  
   571  func (i IcebergOrder) IntoProto() *proto.IcebergOrder {
   572  	return &proto.IcebergOrder{
   573  		ReservedRemaining:  i.ReservedRemaining,
   574  		PeakSize:           i.PeakSize,
   575  		MinimumVisibleSize: i.MinimumVisibleSize,
   576  	}
   577  }
   578  
   579  func (i IcebergOrder) String() string {
   580  	return fmt.Sprintf(
   581  		"reserved-remaining(%d) initial-peak-size(%d) minimum-peak-size(%d)",
   582  		i.ReservedRemaining,
   583  		i.PeakSize,
   584  		i.MinimumVisibleSize,
   585  	)
   586  }
   587  
   588  type OrderConfirmation struct {
   589  	Order                 *Order
   590  	Trades                []*Trade
   591  	PassiveOrdersAffected []*Order
   592  }
   593  
   594  func (o *OrderConfirmation) IntoProto() *proto.OrderConfirmation {
   595  	return &proto.OrderConfirmation{
   596  		Order:                 o.Order.IntoProto(),
   597  		Trades:                Trades(o.Trades).IntoProto(),
   598  		PassiveOrdersAffected: Orders(o.PassiveOrdersAffected).IntoProto(),
   599  	}
   600  }
   601  
   602  func (o OrderConfirmation) TradedValue() *num.Uint {
   603  	total := num.UintZero()
   604  	for _, t := range o.Trades {
   605  		size := num.NewUint(t.Size)
   606  		total.AddSum(size.Mul(size, t.Price))
   607  	}
   608  	return total
   609  }
   610  
   611  type OrderCancellationConfirmation struct {
   612  	Order *Order
   613  }
   614  
   615  func (o *OrderCancellationConfirmation) IntoProto() *proto.OrderCancellationConfirmation {
   616  	return &proto.OrderCancellationConfirmation{
   617  		Order: o.Order.IntoProto(),
   618  	}
   619  }
   620  
   621  type Trade struct {
   622  	ID                 string
   623  	MarketID           string
   624  	Price              *num.Uint
   625  	MarketPrice        *num.Uint
   626  	Size               uint64
   627  	Buyer              string
   628  	Seller             string
   629  	Aggressor          Side
   630  	BuyOrder           string
   631  	SellOrder          string
   632  	Timestamp          int64
   633  	Type               TradeType
   634  	BuyerFee           *Fee
   635  	SellerFee          *Fee
   636  	BuyerAuctionBatch  uint64
   637  	SellerAuctionBatch uint64
   638  }
   639  
   640  func (t *Trade) SetIDs(tradeID string, aggressive, passive *Order) {
   641  	t.ID = tradeID
   642  	if aggressive.Side == SideBuy {
   643  		t.BuyOrder = aggressive.ID
   644  		t.SellOrder = passive.ID
   645  		return
   646  	}
   647  	t.SellOrder = aggressive.ID
   648  	t.BuyOrder = passive.ID
   649  }
   650  
   651  func (t *Trade) IntoProto() *proto.Trade {
   652  	var buyerFee, sellerFee *proto.Fee
   653  	if t.BuyerFee != nil {
   654  		buyerFee = t.BuyerFee.IntoProto()
   655  	}
   656  	if t.SellerFee != nil {
   657  		sellerFee = t.SellerFee.IntoProto()
   658  	}
   659  	return &proto.Trade{
   660  		Id:                 t.ID,
   661  		MarketId:           t.MarketID,
   662  		Price:              num.UintToString(t.Price),
   663  		Size:               t.Size,
   664  		Buyer:              t.Buyer,
   665  		Seller:             t.Seller,
   666  		Aggressor:          t.Aggressor,
   667  		BuyOrder:           t.BuyOrder,
   668  		SellOrder:          t.SellOrder,
   669  		Timestamp:          t.Timestamp,
   670  		Type:               t.Type,
   671  		BuyerFee:           buyerFee,
   672  		SellerFee:          sellerFee,
   673  		BuyerAuctionBatch:  t.BuyerAuctionBatch,
   674  		SellerAuctionBatch: t.SellerAuctionBatch,
   675  	}
   676  }
   677  
   678  func TradeFromProto(t *proto.Trade) *Trade {
   679  	if t == nil {
   680  		return nil
   681  	}
   682  
   683  	return &Trade{
   684  		ID:                 t.Id,
   685  		MarketID:           t.MarketId,
   686  		Price:              num.MustUintFromString(t.Price, 10),
   687  		Size:               t.Size,
   688  		Buyer:              t.Buyer,
   689  		Seller:             t.Seller,
   690  		Aggressor:          t.Aggressor,
   691  		BuyOrder:           t.BuyOrder,
   692  		SellOrder:          t.SellOrder,
   693  		Timestamp:          t.Timestamp,
   694  		Type:               t.Type,
   695  		BuyerFee:           FeeFromProto(t.BuyerFee),
   696  		SellerFee:          FeeFromProto(t.SellerFee),
   697  		BuyerAuctionBatch:  t.BuyerAuctionBatch,
   698  		SellerAuctionBatch: t.SellerAuctionBatch,
   699  	}
   700  }
   701  
   702  func (t Trade) String() string {
   703  	return fmt.Sprintf(
   704  		"ID(%s) marketID(%s) price(%s) marketPrice(%s) size(%v) buyer(%s) seller(%s) aggressor(%s) buyOrder(%s) sellOrder(%s) timestamp(%v) type(%s) buyerAuctionBatch(%v) sellerAuctionBatch(%v) buyerFee(%s) sellerFee(%s)",
   705  		t.ID,
   706  		t.MarketID,
   707  		stringer.PtrToString(t.Price),
   708  		stringer.PtrToString(t.MarketPrice),
   709  		t.Size,
   710  		t.Buyer,
   711  		t.Seller,
   712  		t.Aggressor.String(),
   713  		t.BuyOrder,
   714  		t.SellOrder,
   715  		t.Timestamp,
   716  		t.Type.String(),
   717  		t.BuyerAuctionBatch,
   718  		t.SellerAuctionBatch,
   719  		stringer.PtrToString(t.SellerFee),
   720  		stringer.PtrToString(t.BuyerFee),
   721  	)
   722  }
   723  
   724  type Trades []*Trade
   725  
   726  func (t Trades) IntoProto() []*proto.Trade {
   727  	out := make([]*proto.Trade, 0, len(t))
   728  	for _, v := range t {
   729  		out = append(out, v.IntoProto())
   730  	}
   731  	return out
   732  }
   733  
   734  type TradeType = proto.Trade_Type
   735  
   736  const (
   737  	// Default value, always invalid.
   738  	TradeTypeUnspecified TradeType = proto.Trade_TYPE_UNSPECIFIED
   739  	// Normal trading between two parties.
   740  	TradeTypeDefault TradeType = proto.Trade_TYPE_DEFAULT
   741  	// Trading initiated by the network with another party on the book,
   742  	// which helps to zero-out the positions of one or more distressed parties.
   743  	TradeTypeNetworkCloseOutGood TradeType = proto.Trade_TYPE_NETWORK_CLOSE_OUT_GOOD
   744  	// Trading initiated by the network with another party off the book,
   745  	// with a distressed party in order to zero-out the position of the party.
   746  	TradeTypeNetworkCloseOutBad TradeType = proto.Trade_TYPE_NETWORK_CLOSE_OUT_BAD
   747  )
   748  
   749  type PeggedReference = proto.PeggedReference
   750  
   751  const (
   752  	// Default value for PeggedReference, no reference given.
   753  	PeggedReferenceUnspecified PeggedReference = proto.PeggedReference_PEGGED_REFERENCE_UNSPECIFIED
   754  	// Mid price reference.
   755  	PeggedReferenceMid PeggedReference = proto.PeggedReference_PEGGED_REFERENCE_MID
   756  	// Best bid price reference.
   757  	PeggedReferenceBestBid PeggedReference = proto.PeggedReference_PEGGED_REFERENCE_BEST_BID
   758  	// Best ask price reference.
   759  	PeggedReferenceBestAsk PeggedReference = proto.PeggedReference_PEGGED_REFERENCE_BEST_ASK
   760  )
   761  
   762  type OrderStatus = proto.Order_Status
   763  
   764  const (
   765  	// Default value, always invalid.
   766  	OrderStatusUnspecified OrderStatus = proto.Order_STATUS_UNSPECIFIED
   767  	// Used for active unfilled or partially filled orders.
   768  	OrderStatusActive OrderStatus = proto.Order_STATUS_ACTIVE
   769  	// Used for expired GTT orders.
   770  	OrderStatusExpired OrderStatus = proto.Order_STATUS_EXPIRED
   771  	// Used for orders cancelled by the party that created the order.
   772  	OrderStatusCancelled OrderStatus = proto.Order_STATUS_CANCELLED
   773  	// Used for unfilled FOK or IOC orders, and for orders that were stopped by the network.
   774  	OrderStatusStopped OrderStatus = proto.Order_STATUS_STOPPED
   775  	// Used for closed fully filled orders.
   776  	OrderStatusFilled OrderStatus = proto.Order_STATUS_FILLED
   777  	// Used for orders when not enough collateral was available to fill the margin requirements.
   778  	OrderStatusRejected OrderStatus = proto.Order_STATUS_REJECTED
   779  	// Used for closed partially filled IOC orders.
   780  	OrderStatusPartiallyFilled OrderStatus = proto.Order_STATUS_PARTIALLY_FILLED
   781  	// Order has been removed from the order book and has been parked, this applies to pegged orders only.
   782  	OrderStatusParked OrderStatus = proto.Order_STATUS_PARKED
   783  )
   784  
   785  type Side = proto.Side
   786  
   787  const (
   788  	// Default value, always invalid.
   789  	SideUnspecified Side = proto.Side_SIDE_UNSPECIFIED
   790  	// Buy order.
   791  	SideBuy Side = proto.Side_SIDE_BUY
   792  	// Sell order.
   793  	SideSell Side = proto.Side_SIDE_SELL
   794  )
   795  
   796  type OrderType = proto.Order_Type
   797  
   798  const (
   799  	// Default value, always invalid.
   800  	OrderTypeUnspecified OrderType = proto.Order_TYPE_UNSPECIFIED
   801  	// Used for Limit orders.
   802  	OrderTypeLimit OrderType = proto.Order_TYPE_LIMIT
   803  	// Used for Market orders.
   804  	OrderTypeMarket OrderType = proto.Order_TYPE_MARKET
   805  	// Used for orders where the initiating party is the network (with distressed traders).
   806  	OrderTypeNetwork OrderType = proto.Order_TYPE_NETWORK
   807  )
   808  
   809  type OrderTimeInForce = proto.Order_TimeInForce
   810  
   811  const (
   812  	// Default value for TimeInForce, can be valid for an amend.
   813  	OrderTimeInForceUnspecified OrderTimeInForce = proto.Order_TIME_IN_FORCE_UNSPECIFIED
   814  	// Good until cancelled.
   815  	OrderTimeInForceGTC OrderTimeInForce = proto.Order_TIME_IN_FORCE_GTC
   816  	// Good until specified time.
   817  	OrderTimeInForceGTT OrderTimeInForce = proto.Order_TIME_IN_FORCE_GTT
   818  	// Immediate or cancel.
   819  	OrderTimeInForceIOC OrderTimeInForce = proto.Order_TIME_IN_FORCE_IOC
   820  	// Fill or kill.
   821  	OrderTimeInForceFOK OrderTimeInForce = proto.Order_TIME_IN_FORCE_FOK
   822  	// Good for auction.
   823  	OrderTimeInForceGFA OrderTimeInForce = proto.Order_TIME_IN_FORCE_GFA
   824  	// Good for normal.
   825  	OrderTimeInForceGFN OrderTimeInForce = proto.Order_TIME_IN_FORCE_GFN
   826  )
   827  
   828  type OrderError = proto.OrderError
   829  
   830  const (
   831  	// Default value, no error reported.
   832  	OrderErrorUnspecified OrderError = proto.OrderError_ORDER_ERROR_UNSPECIFIED
   833  	// Order was submitted for a market that does not exist.
   834  	OrderErrorInvalidMarketID OrderError = proto.OrderError_ORDER_ERROR_INVALID_MARKET_ID
   835  	// Order was submitted with an invalid identifier.
   836  	OrderErrorInvalidOrderID OrderError = proto.OrderError_ORDER_ERROR_INVALID_ORDER_ID
   837  	// Order was amended with a sequence number that was not previous version + 1.
   838  	OrderErrorOutOfSequence OrderError = proto.OrderError_ORDER_ERROR_OUT_OF_SEQUENCE
   839  	// Order was amended with an invalid remaining size (e.g. remaining greater than total size).
   840  	OrderErrorInvalidRemainingSize OrderError = proto.OrderError_ORDER_ERROR_INVALID_REMAINING_SIZE
   841  	// Node was unable to get Vega (blockchain) time.
   842  	OrderErrorTimeFailure OrderError = proto.OrderError_ORDER_ERROR_TIME_FAILURE
   843  	// Failed to remove an order from the book.
   844  	OrderErrorRemovalFailure OrderError = proto.OrderError_ORDER_ERROR_REMOVAL_FAILURE
   845  	// An order with `TimeInForce.TIME_IN_FORCE_GTT` was submitted or amended
   846  	// with an expiration that was badly formatted or otherwise invalid.
   847  	OrderErrorInvalidExpirationDatetime OrderError = proto.OrderError_ORDER_ERROR_INVALID_EXPIRATION_DATETIME
   848  	// Order was submitted or amended with an invalid reference field.
   849  	OrderErrorInvalidOrderReference OrderError = proto.OrderError_ORDER_ERROR_INVALID_ORDER_REFERENCE
   850  	// Order amend was submitted for an order field that cannot not be amended (e.g. order identifier).
   851  	OrderErrorEditNotAllowed OrderError = proto.OrderError_ORDER_ERROR_EDIT_NOT_ALLOWED
   852  	// Amend failure because amend details do not match original order.
   853  	OrderErrorAmendFailure OrderError = proto.OrderError_ORDER_ERROR_AMEND_FAILURE
   854  	// Order not found in an order book or store.
   855  	OrderErrorNotFound OrderError = proto.OrderError_ORDER_ERROR_NOT_FOUND
   856  	// Order was submitted with an invalid or missing party identifier.
   857  	OrderErrorInvalidParty OrderError = proto.OrderError_ORDER_ERROR_INVALID_PARTY_ID
   858  	// Order was submitted for a market that has closed.
   859  	OrderErrorMarketClosed OrderError = proto.OrderError_ORDER_ERROR_MARKET_CLOSED
   860  	// Order was submitted, but the party did not have enough collateral to cover the order.
   861  	OrderErrorMarginCheckFailed OrderError = proto.OrderError_ORDER_ERROR_MARGIN_CHECK_FAILED
   862  	// Order was submitted, but the party did not have an account for this asset.
   863  	OrderErrorMissingGeneralAccount OrderError = proto.OrderError_ORDER_ERROR_MISSING_GENERAL_ACCOUNT
   864  	// Unspecified internal error.
   865  	OrderErrorInternalError OrderError = proto.OrderError_ORDER_ERROR_INTERNAL_ERROR
   866  	// Order was submitted with an invalid or missing size (e.g. 0).
   867  	OrderErrorInvalidSize OrderError = proto.OrderError_ORDER_ERROR_INVALID_SIZE
   868  	// Order was submitted with an invalid persistence for its type.
   869  	OrderErrorInvalidPersistance OrderError = proto.OrderError_ORDER_ERROR_INVALID_PERSISTENCE
   870  	// Order was submitted with an invalid type field.
   871  	OrderErrorInvalidType OrderError = proto.OrderError_ORDER_ERROR_INVALID_TYPE
   872  	// Order was stopped as it would have traded with another order submitted from the same party.
   873  	OrderErrorSelfTrading OrderError = proto.OrderError_ORDER_ERROR_SELF_TRADING
   874  	// Order was submitted, but the party did not have enough collateral to cover the fees for the order.
   875  	OrderErrorInsufficientFundsToPayFees OrderError = proto.OrderError_ORDER_ERROR_INSUFFICIENT_FUNDS_TO_PAY_FEES
   876  	// Order was submitted with an incorrect or invalid market type.
   877  	OrderErrorIncorrectMarketType OrderError = proto.OrderError_ORDER_ERROR_INCORRECT_MARKET_TYPE
   878  	// Order was submitted with invalid time in force.
   879  	OrderErrorInvalidTimeInForce OrderError = proto.OrderError_ORDER_ERROR_INVALID_TIME_IN_FORCE
   880  	// A GFN order has got to the market when it is in auction mode.
   881  	OrderErrorCannotSendGFNOrderDuringAnAuction OrderError = proto.OrderError_ORDER_ERROR_CANNOT_SEND_GFN_ORDER_DURING_AN_AUCTION
   882  	// A GFA order has got to the market when it is in continuous trading mode.
   883  	OrderErrorGFAOrderDuringContinuousTrading OrderError = proto.OrderError_ORDER_ERROR_CANNOT_SEND_GFA_ORDER_DURING_CONTINUOUS_TRADING
   884  	// Attempt to amend order to GTT without ExpiryAt.
   885  	OrderErrorCannotAmendToGTTWithoutExpiryAt OrderError = proto.OrderError_ORDER_ERROR_CANNOT_AMEND_TO_GTT_WITHOUT_EXPIRYAT
   886  	// Attempt to amend ExpiryAt to a value before CreatedAt.
   887  	OrderErrorExpiryAtBeforeCreatedAt OrderError = proto.OrderError_ORDER_ERROR_EXPIRYAT_BEFORE_CREATEDAT
   888  	// Attempt to amend to GTC without an ExpiryAt value.
   889  	OrderErrorCannotHaveGTCAndExpiryAt OrderError = proto.OrderError_ORDER_ERROR_CANNOT_HAVE_GTC_AND_EXPIRYAT
   890  	// Amending to FOK or IOC is invalid.
   891  	OrderErrorCannotAmendToFOKOrIOC OrderError = proto.OrderError_ORDER_ERROR_CANNOT_AMEND_TO_FOK_OR_IOC
   892  	// Amending to GFA or GFN is invalid.
   893  	OrderErrorCannotAmendToGFAOrGFN OrderError = proto.OrderError_ORDER_ERROR_CANNOT_AMEND_TO_GFA_OR_GFN
   894  	// Amending from GFA or GFN is invalid.
   895  	OrderErrorCannotAmendFromGFAOrGFN OrderError = proto.OrderError_ORDER_ERROR_CANNOT_AMEND_FROM_GFA_OR_GFN
   896  	// IOC orders are not allowed during auction.
   897  	OrderErrorCannotSendIOCOrderDuringAuction OrderError = proto.OrderError_ORDER_ERROR_CANNOT_SEND_IOC_ORDER_DURING_AUCTION
   898  	// FOK orders are not allowed during auction.
   899  	OrderErrorCannotSendFOKOrderDurinAuction OrderError = proto.OrderError_ORDER_ERROR_CANNOT_SEND_FOK_ORDER_DURING_AUCTION
   900  	// Pegged orders must be LIMIT orders.
   901  	OrderErrorMustBeLimitOrder OrderError = proto.OrderError_ORDER_ERROR_MUST_BE_LIMIT_ORDER
   902  	// Pegged orders can only have TIF GTC or GTT.
   903  	OrderErrorMustBeGTTOrGTC OrderError = proto.OrderError_ORDER_ERROR_MUST_BE_GTT_OR_GTC
   904  	// Pegged order must have a reference price.
   905  	OrderErrorWithoutReferencePrice OrderError = proto.OrderError_ORDER_ERROR_WITHOUT_REFERENCE_PRICE
   906  	// Buy pegged order cannot reference best ask price.
   907  	OrderErrorBuyCannotReferenceBestAskPrice OrderError = proto.OrderError_ORDER_ERROR_BUY_CANNOT_REFERENCE_BEST_ASK_PRICE
   908  	// Pegged order offset must be >= 0.
   909  	OrderErrorOffsetMustBeGreaterOrEqualToZero OrderError = proto.OrderError_ORDER_ERROR_OFFSET_MUST_BE_GREATER_OR_EQUAL_TO_ZERO
   910  	// Sell pegged order cannot reference best bid price.
   911  	OrderErrorSellCannotReferenceBestBidPrice OrderError = proto.OrderError_ORDER_ERROR_SELL_CANNOT_REFERENCE_BEST_BID_PRICE
   912  	// Pegged order offset must be > zero.
   913  	OrderErrorOffsetMustBeGreaterThanZero OrderError = proto.OrderError_ORDER_ERROR_OFFSET_MUST_BE_GREATER_THAN_ZERO
   914  	// The party has an insufficient balance, or does not have
   915  	// a general account to submit the order (no deposits made
   916  	// for the required asset).
   917  	OrderErrorInsufficientAssetBalance OrderError = proto.OrderError_ORDER_ERROR_INSUFFICIENT_ASSET_BALANCE
   918  	// Cannot amend a non pegged orders details.
   919  	OrderErrorCannotAmendPeggedOrderDetailsOnNonPeggedOrder OrderError = proto.OrderError_ORDER_ERROR_CANNOT_AMEND_PEGGED_ORDER_DETAILS_ON_NON_PEGGED_ORDER
   920  	// We are unable to re-price a pegged order because a market price is unavailable.
   921  	OrderErrorUnableToRepricePeggedOrder OrderError = proto.OrderError_ORDER_ERROR_UNABLE_TO_REPRICE_PEGGED_ORDER
   922  	// It is not possible to amend the price of an existing pegged order.
   923  	OrderErrorUnableToAmendPriceOnPeggedOrder OrderError = proto.OrderError_ORDER_ERROR_UNABLE_TO_AMEND_PRICE_ON_PEGGED_ORDER
   924  	// An FOK, IOC, or GFN order was rejected because it resulted in trades outside the price bounds.
   925  	OrderErrorNonPersistentOrderOutOfPriceBounds OrderError = proto.OrderError_ORDER_ERROR_NON_PERSISTENT_ORDER_OUT_OF_PRICE_BOUNDS
   926  	// Unable to submit pegged order, temporarily too many pegged orders across all markets.
   927  	OrderErrorTooManyPeggedOrders                    OrderError = proto.OrderError_ORDER_ERROR_TOO_MANY_PEGGED_ORDERS
   928  	OrderErrorPostOnlyOrderWouldTrade                OrderError = proto.OrderError_ORDER_ERROR_POST_ONLY_ORDER_WOULD_TRADE
   929  	OrderErrorReduceOnlyOrderWouldNotReducePosition  OrderError = proto.OrderError_ORDER_ERROR_REDUCE_ONLY_ORDER_WOULD_NOT_REDUCE_POSITION
   930  	OrderErrorIsolatedMarginCheckFailed              OrderError = proto.OrderError_ORDER_ERROR_ISOLATED_MARGIN_CHECK_FAILED
   931  	OrderErrorPeggedOrdersNotAllowedInIsolatedMargin OrderError = proto.OrderError_ORDER_ERROR_PEGGED_ORDERS_NOT_ALLOWED_IN_ISOLATED_MARGIN_MODE
   932  	OrderErrorPriceNotInTickSize                     OrderError = proto.OrderError_ORDER_ERROR_PRICE_NOT_IN_TICK_SIZE
   933  	OrderErrorPriceLTEMaxPrice                       OrderError = proto.OrderError_ORDER_ERROR_PRICE_MUST_BE_LESS_THAN_OR_EQUAL_TO_MAX_PRICE
   934  	OrderErrorSellOrderNotAllowed                    OrderError = proto.OrderError_ORDER_ERROR_SELL_ORDER_NOT_ALLOWED
   935  )
   936  
   937  var (
   938  	ErrInvalidMarketID                             = OrderErrorInvalidMarketID
   939  	ErrInvalidOrderID                              = OrderErrorInvalidOrderID
   940  	ErrOrderOutOfSequence                          = OrderErrorOutOfSequence
   941  	ErrInvalidRemainingSize                        = OrderErrorInvalidRemainingSize
   942  	ErrOrderRemovalFailure                         = OrderErrorRemovalFailure
   943  	ErrInvalidExpirationDatetime                   = OrderErrorInvalidExpirationDatetime
   944  	ErrEditNotAllowed                              = OrderErrorEditNotAllowed
   945  	ErrOrderAmendFailure                           = OrderErrorAmendFailure
   946  	ErrOrderNotFound                               = OrderErrorNotFound
   947  	ErrInvalidPartyID                              = OrderErrorInvalidParty
   948  	ErrInvalidSize                                 = OrderErrorInvalidSize
   949  	ErrInvalidPersistence                          = OrderErrorInvalidPersistance
   950  	ErrInvalidType                                 = OrderErrorInvalidType
   951  	ErrInvalidTimeInForce                          = OrderErrorInvalidTimeInForce
   952  	ErrPeggedOrderMustBeLimitOrder                 = OrderErrorMustBeLimitOrder
   953  	ErrPeggedOrderMustBeGTTOrGTC                   = OrderErrorMustBeGTTOrGTC
   954  	ErrPeggedOrderWithoutReferencePrice            = OrderErrorWithoutReferencePrice
   955  	ErrPeggedOrderBuyCannotReferenceBestAskPrice   = OrderErrorBuyCannotReferenceBestAskPrice
   956  	ErrPeggedOrderOffsetMustBeGreaterOrEqualToZero = OrderErrorOffsetMustBeGreaterOrEqualToZero
   957  	ErrPeggedOrderSellCannotReferenceBestBidPrice  = OrderErrorSellCannotReferenceBestBidPrice
   958  	ErrPeggedOrderOffsetMustBeGreaterThanZero      = OrderErrorOffsetMustBeGreaterThanZero
   959  	ErrTooManyPeggedOrders                         = OrderErrorTooManyPeggedOrders
   960  	ErrPostOnlyOrderWouldTrade                     = OrderErrorPostOnlyOrderWouldTrade
   961  	ErrReduceOnlyOrderWouldNotReducePosition       = OrderErrorReduceOnlyOrderWouldNotReducePosition
   962  	ErrPeggedOrdersNotAllowedInIsolatedMargin      = OrderErrorPeggedOrdersNotAllowedInIsolatedMargin
   963  	ErrOrderNotInTickSize                          = OrderErrorPriceNotInTickSize
   964  	ErrSellOrderNotAllowed                         = OrderErrorSellOrderNotAllowed
   965  )
   966  
   967  func OtherSide(s Side) Side {
   968  	switch s {
   969  	case SideBuy:
   970  		return SideSell
   971  	case SideSell:
   972  		return SideBuy
   973  	}
   974  	return SideUnspecified
   975  }
   976  
   977  func IsOrderError(err error) (OrderError, bool) {
   978  	oerr, ok := err.(OrderError)
   979  	return oerr, ok
   980  }
   981  
   982  func IsStoppingOrder(o OrderError) bool {
   983  	return o == OrderErrorNonPersistentOrderOutOfPriceBounds ||
   984  		o == ErrPostOnlyOrderWouldTrade ||
   985  		o == ErrReduceOnlyOrderWouldNotReducePosition ||
   986  		o == OrderErrorIsolatedMarginCheckFailed ||
   987  		o == OrderErrorPeggedOrdersNotAllowedInIsolatedMargin
   988  }