github.com/InjectiveLabs/sdk-go@v1.53.0/chain/exchange/types/orderbook.go (about)

     1  package types
     2  
     3  import (
     4  	"os"
     5  	"sort"
     6  	"strings"
     7  
     8  	"cosmossdk.io/math"
     9  	"github.com/ethereum/go-ethereum/common"
    10  	"github.com/olekukonko/tablewriter"
    11  )
    12  
    13  func NewOrderbook(marketID common.Hash) *Orderbook {
    14  	return &Orderbook{
    15  		MarketId:   marketID.Bytes(),
    16  		BuyLevels:  make([]*Level, 0),
    17  		SellLevels: make([]*Level, 0),
    18  	}
    19  }
    20  
    21  func NewOrderbookWithLevels(marketID common.Hash, buyLevels, sellLevels []*Level) *Orderbook {
    22  	return &Orderbook{
    23  		MarketId:   marketID.Bytes(),
    24  		BuyLevels:  buyLevels,
    25  		SellLevels: sellLevels,
    26  	}
    27  }
    28  
    29  func (o *Orderbook) AppendLevel(isBuy bool, level *Level) {
    30  	if isBuy {
    31  		o.BuyLevels = append(o.BuyLevels, level)
    32  		return
    33  	}
    34  	o.SellLevels = append(o.SellLevels, level)
    35  }
    36  
    37  func (o *Orderbook) IsCrossed() bool {
    38  	if len(o.BuyLevels) == 0 || len(o.SellLevels) == 0 {
    39  		return false
    40  	}
    41  
    42  	highestBuyLevel := o.BuyLevels[len(o.BuyLevels)-1]
    43  
    44  	if highestBuyLevel.Q.IsZero() {
    45  		return false
    46  	}
    47  
    48  	lowestSellPrice := math.LegacyZeroDec()
    49  
    50  	isQuantityAllZero := true
    51  
    52  	for _, level := range o.SellLevels {
    53  		if level.Q.IsZero() {
    54  			continue
    55  		}
    56  		lowestSellPrice = level.P
    57  		isQuantityAllZero = false
    58  		break
    59  	}
    60  
    61  	if isQuantityAllZero {
    62  		return false
    63  	}
    64  
    65  	return highestBuyLevel.P.GTE(lowestSellPrice)
    66  }
    67  
    68  // PrintDisplay is a helper function to print the orderbook in a human readable format for debugging purposes
    69  func (o *Orderbook) PrintDisplay() {
    70  	PrintDisplayLevels(o.BuyLevels, o.SellLevels)
    71  }
    72  
    73  // PrintDisplayLevels is a helper function to print the orderbook in a human readable format for debugging purposes
    74  func PrintDisplayLevels(buyLevels, sellLevels []*Level) {
    75  	buyLevelsSorted := make([]*Level, len(buyLevels))
    76  	copy(buyLevelsSorted, buyLevels)
    77  	sellLevelsSorted := make([]*Level, len(sellLevels))
    78  	copy(sellLevelsSorted, sellLevels)
    79  	if len(buyLevels) > 1 {
    80  		sort.SliceStable(buyLevelsSorted, func(i, j int) bool {
    81  			return buyLevelsSorted[i].GetPrice().GT(buyLevelsSorted[j].GetPrice())
    82  		})
    83  	}
    84  	if len(sellLevelsSorted) > 1 {
    85  		sort.SliceStable(sellLevelsSorted, func(i, j int) bool {
    86  			return sellLevelsSorted[i].GetPrice().LT(sellLevelsSorted[j].GetPrice())
    87  		})
    88  	}
    89  
    90  	table := tablewriter.NewWriter(os.Stdout)
    91  	table.SetHeader([]string{"Buy Price", "Buy Quantity", "Sell Price", "Sell Quantity"})
    92  
    93  	maxLength := len(buyLevelsSorted)
    94  	if len(sellLevelsSorted) > maxLength {
    95  		maxLength = len(sellLevelsSorted)
    96  	}
    97  
    98  	for idx := 0; idx < maxLength; idx++ {
    99  		row := make([]string, 0)
   100  		if idx < len(buyLevelsSorted) {
   101  			row = append(row, getReadableDec(buyLevelsSorted[idx].P), getReadableDec(buyLevelsSorted[idx].Q))
   102  		} else {
   103  			row = append(row, "-", "-")
   104  		}
   105  		if idx < len(sellLevelsSorted) {
   106  			row = append(row, getReadableDec(sellLevelsSorted[idx].P), getReadableDec(sellLevelsSorted[idx].Q))
   107  		} else {
   108  			row = append(row, "-", "-")
   109  		}
   110  		table.Append(row)
   111  	}
   112  	table.Render()
   113  }
   114  
   115  func (o *Orderbook) Equals(other *Orderbook) bool {
   116  	if len(o.BuyLevels) != len(other.BuyLevels) || len(o.SellLevels) != len(other.SellLevels) {
   117  		return false
   118  	}
   119  	for i, level := range o.BuyLevels {
   120  		metaLevel := other.BuyLevels[i]
   121  		if !level.Q.Equal(metaLevel.Q) || !level.P.Equal(metaLevel.P) {
   122  			return false
   123  		}
   124  	}
   125  	return true
   126  }
   127  
   128  // getReadableDec is a test utility function to return a readable representation of decimal strings
   129  func getReadableDec(d math.LegacyDec) string {
   130  	if d.IsNil() {
   131  		return d.String()
   132  	}
   133  	dec := strings.TrimRight(d.String(), "0")
   134  	if len(dec) < 2 {
   135  		return dec
   136  	}
   137  
   138  	if dec[len(dec)-1:] == "." {
   139  		return dec + "0"
   140  	}
   141  	return dec
   142  }
   143  
   144  func NewLevel(price, quantity math.LegacyDec) *Level {
   145  	return &Level{
   146  		P: price,
   147  		Q: quantity,
   148  	}
   149  }
   150  
   151  func (l *Level) GetPrice() math.LegacyDec {
   152  	return l.P
   153  }
   154  
   155  func (l *Level) GetQuantity() math.LegacyDec {
   156  	return l.Q
   157  }