github.com/frankrap/okex-api@v1.0.4/orderbook.go (about)

     1  package okex
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/MauriceGit/skiplist"
     6  	"strconv"
     7  	"time"
     8  )
     9  
    10  const (
    11  	ActionDepthL2Partial = "partial"
    12  	ActionDepthL2Update  = "update"
    13  )
    14  
    15  type Item struct {
    16  	Price  float64
    17  	Amount float64
    18  }
    19  
    20  func (e Item) ExtractKey() float64 {
    21  	return e.Price
    22  }
    23  
    24  func (e Item) String() string {
    25  	return fmt.Sprintf("%.8f", e.Price)
    26  }
    27  
    28  type OrderBook struct {
    29  	InstrumentID string `json:"instrument_id"`
    30  	Asks         []Item `json:"asks"`
    31  	Bids         []Item `json:"bids"`
    32  }
    33  
    34  type DepthOrderBook struct {
    35  	instrumentID string // BTC-USD-SWAP
    36  	asks         skiplist.SkipList
    37  	bids         skiplist.SkipList
    38  }
    39  
    40  func (d *DepthOrderBook) GetInstrumentID() string {
    41  	return d.instrumentID
    42  }
    43  
    44  func (d *DepthOrderBook) Update(action string, data *WSDepthL2Tbt) {
    45  	if action == ActionDepthL2Partial {
    46  		d.asks = skiplist.NewSeedEps(time.Now().UTC().UnixNano(), 0.00000001)
    47  		d.bids = skiplist.NewSeedEps(time.Now().UTC().UnixNano(), 0.00000001)
    48  		//d.asks = skiplist.New()
    49  		//d.bids = skiplist.New()
    50  		// 举例: ["411.8", "10", "1", "4"]
    51  		// 411.8为深度价格,10为此价格的合约张数,1为此价格的强平单个数,4为此价格的订单个数。
    52  		for _, ask := range data.Asks {
    53  			price, _ := strconv.ParseFloat(ask[0], 64)
    54  			amount, _ := strconv.ParseFloat(ask[1], 64)
    55  			d.asks.Insert(Item{
    56  				Price:  price,
    57  				Amount: amount,
    58  			})
    59  		}
    60  		for _, bid := range data.Bids {
    61  			price, _ := strconv.ParseFloat(bid[0], 64)
    62  			amount, _ := strconv.ParseFloat(bid[1], 64)
    63  			d.bids.Insert(Item{
    64  				Price:  price,
    65  				Amount: amount,
    66  			})
    67  		}
    68  		return
    69  	}
    70  
    71  	if action == ActionDepthL2Update {
    72  		for _, ask := range data.Asks {
    73  			price, _ := strconv.ParseFloat(ask[0], 64)
    74  			amount, _ := strconv.ParseFloat(ask[1], 64)
    75  			if amount == 0 {
    76  				d.asks.Delete(Item{
    77  					Price:  price,
    78  					Amount: amount,
    79  				})
    80  			} else {
    81  				item := Item{
    82  					Price:  price,
    83  					Amount: amount,
    84  				}
    85  				elem, ok := d.asks.Find(item)
    86  				if ok {
    87  					d.asks.ChangeValue(elem, item)
    88  				} else {
    89  					d.asks.Insert(item)
    90  				}
    91  			}
    92  		}
    93  		for _, bid := range data.Bids {
    94  			price, _ := strconv.ParseFloat(bid[0], 64)
    95  			amount, _ := strconv.ParseFloat(bid[1], 64)
    96  			if amount == 0 {
    97  				d.bids.Delete(Item{
    98  					Price:  price,
    99  					Amount: amount,
   100  				})
   101  			} else {
   102  				item := Item{
   103  					Price:  price,
   104  					Amount: amount,
   105  				}
   106  				elem, ok := d.bids.Find(item)
   107  				if ok {
   108  					d.bids.ChangeValue(elem, item)
   109  				} else {
   110  					d.bids.Insert(item)
   111  				}
   112  			}
   113  		}
   114  	}
   115  }
   116  
   117  func (d *DepthOrderBook) GetOrderBook(depth int) (result OrderBook) {
   118  	result.InstrumentID = d.instrumentID
   119  	smallest := d.asks.GetSmallestNode()
   120  	if smallest != nil {
   121  		result.Asks = append(result.Asks, smallest.GetValue().(Item))
   122  		count := 1
   123  		node := smallest
   124  		for count < depth {
   125  			node = d.asks.Next(node)
   126  			if node == nil {
   127  				break
   128  			}
   129  			result.Asks = append(result.Asks, node.GetValue().(Item))
   130  			count++
   131  		}
   132  	}
   133  
   134  	largest := d.bids.GetLargestNode()
   135  	if largest != nil {
   136  		result.Bids = append(result.Bids, largest.GetValue().(Item))
   137  		count := 1
   138  		node := largest
   139  		for count < depth {
   140  			node = d.bids.Prev(node)
   141  			if node == nil {
   142  				break
   143  			}
   144  			result.Bids = append(result.Bids, node.GetValue().(Item))
   145  			count++
   146  		}
   147  	}
   148  	return
   149  }
   150  
   151  func NewDepthOrderBook(instrumentID string) *DepthOrderBook {
   152  	return &DepthOrderBook{
   153  		instrumentID: instrumentID,
   154  		asks:         skiplist.New(),
   155  		bids:         skiplist.New(),
   156  	}
   157  }