add match function

This commit is contained in:
Callum Waters
2022-10-17 12:14:40 +03:00
parent 944e9ebdc0
commit 0c2483e9f3
+147 -37
View File
@@ -5,69 +5,179 @@ import (
)
type Market struct {
pair Pair // i.e. EUR/USD (a market is bidirectional)
buyingOrders HighestPriceOrderList // i.e. buying EUR for USD
sellingOrders LowestPriceOrderList // i.e. selling EUR for USD or buying USD for EUR
pair Pair // i.e. EUR/USD (a market is bidirectional)
askOrders *AskOrders // i.e. buying EUR for USD
lowestAsk float64
bidOrders *BidOrders // i.e. selling EUR for USD or buying USD for EUR
highestBid float64
}
func (m *Market) AddBid(b MsgBid) error {
return nil
func NewMarket(p Pair) *Market {
return &Market{pair: p}
}
func (m *Market) AddAsk(a MsgAsk) error {
return nil
func (m *Market) AddBid(b MsgBid) {
heap.Push(m.bidOrders, b)
if b.BidOrder.MaxPrice > m.highestBid {
m.highestBid = b.BidOrder.MaxPrice
}
}
func (m *Market) Match() (*TradeSet, error) {
return nil, nil
}
type LowestPriceOrderList []*Order
func (l LowestPriceOrderList) Less(i, j int) bool {
return l[i].MinPrice < l[j].MinPrice
func (m *Market) AddAsk(a MsgAsk) {
heap.Push(m.askOrders, a)
if a.AskOrder.AskPrice < m.lowestAsk {
m.lowestAsk = a.AskOrder.AskPrice
}
}
func (l LowestPriceOrderList) Swap(i, j int) {
l[i], l[j] = l[j], l[i]
// Match takes the set of bids and asks and matches them together.
// A bid matches an ask when the MaxPrice is greater than the AskPrice
// and the MaxQuantity is greater than the quantity.
func (m *Market) Match() *TradeSet {
if m.highestBid < m.lowestAsk {
// no orders match, we return early.
return nil
}
t := &TradeSet{Pair: &m.pair}
bids := make([]*OrderBid, 0)
asks := make([]*OrderAsk, 0)
// get all the bids that are greater than the lowest ask. In order from heighest bid to lowest bid
for bid := heap.Pop(m.bidOrders).(*OrderBid); bid.MaxPrice >= m.lowestAsk; bid = heap.Pop(m.bidOrders).(*OrderBid) {
bids = append(bids, bid)
}
// get all the asks that are lower than the highest bid in the bids set. Ordered from lowest to highest ask
for ask := heap.Pop(m.askOrders).(*OrderAsk); ask.AskPrice <= bids[0].MaxPrice; ask = heap.Pop(m.askOrders).(*OrderAsk) {
asks = append(asks, ask)
}
// this is to keep track of the index of the bids that have been matched
reserved := make(map[int]struct{})
// start from the highest ask and the highest bid and for each ask loop downwards through the slice of
// bids until one is matched
OUTER_LOOP:
for i := len(asks) - 1; i >= 0; i-- {
ask := asks[i]
// start with the highest bid and increment down since we're more likely to find a match
for j := 0 ; j < len(bids); j++ {
bid := bids[j]
if bid.MaxPrice >= ask.AskPrice {
if bid.MaxQuantity >= ask.Quantity {
// yay! we have a match
t.AddFilledOrder(ask, bid)
// reserve the bid so we don't rematch it with another ask
reserved[j] = struct{}{}
continue OUTER_LOOP
}
} else {
// once we've dropped below the ask price there are no more possible bids and so we break
break
}
}
// as we go from highest to lowest, asks that aren't matched become the new lowest ask price
m.lowestAsk = ask.AskPrice
// no match found, add the ask order back into the heap
heap.Push(m.askOrders, ask)
}
// add back the unmatched bids to the heap so they can be matched again in a later round.
// We also neeed to recalculate the new highest bid. First we tackle an edge case whereby all
// selected bids were matched. In this case we grab the next highest and set that as the new
// highest bid
m.highestBid = 0
if len(reserved) == len(bids) {
newHighestBid := heap.Pop(m.bidOrders).(*OrderBid)
m.highestBid = newHighestBid.MaxPrice
heap.Push(m.bidOrders, newHighestBid)
}
for j := 0; j < len(bids); j++ {
if _, ok := reserved[j]; !ok {
if bids[j].MaxPrice > m.highestBid {
m.highestBid = bids[j].MaxPrice
}
heap.Push(m.bidOrders, bids[j])
}
}
return t
}
func (l *LowestPriceOrderList) Push(x any) {
item := x.(*Order)
*l = append(*l, item)
func (m Market) LowestAsk() float64 {
return m.lowestAsk
}
func (l *LowestPriceOrderList) Pop() any {
old := *l
func (m Market) HighestBid() float64 {
return m.highestBid
}
// Heap ordered by lowest price
type AskOrders []*OrderAsk
var _ heap.Interface = (*AskOrders)(nil)
func (a AskOrders) Len() int { return len(a) }
func (a AskOrders) Less(i, j int) bool {
return a[i].AskPrice < a[j].AskPrice
}
func (a AskOrders) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a *AskOrders) Push(x any) {
item := x.(*OrderAsk)
*a = append(*a, item)
}
func (a *AskOrders) Pop() any {
old := *a
n := len(old)
item := old[n-1]
old[n-1] = nil
*l = old[0 : n-1]
*a = old[0 : n-1]
return item
}
type HighestPriceOrderList []*Order
// Heap ordered by highest price
type BidOrders []*OrderBid
func (l HighestPriceOrderList) Less(i, j int) bool {
return l[i].MinPrice > l[j].MinPrice
var _ heap.Interface = (*BidOrders)(nil)
func (b BidOrders) Len() int { return len(b) }
func (b BidOrders) Less(i, j int) bool {
return b[i].MaxPrice > b[j].MaxPrice
}
func (l HighestPriceOrderList) Swap(i, j int) {
l[i], l[j] = l[j], l[i]
func (b BidOrders) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
func (l *HighestPriceOrderList) Push(x any) {
item := x.(*Order)
*l = append(*l, item)
func (b *BidOrders) Push(x any) {
item := x.(*OrderBid)
*b = append(*b, item)
}
func (l *HighestPriceOrderList) Pop() any {
old := *l
func (b *BidOrders) Pop() any {
old := *b
n := len(old)
item := old[n-1]
old[n-1] = nil
*l = old[0 : n-1]
*b = old[0 : n-1]
return item
}
}
func (t *TradeSet) AddFilledOrder(ask *OrderAsk, bid *OrderBid) {
t.MatchedOrders = append(t.MatchedOrders, &MatchedOrder{
OrderAsk: ask,
OrderBid: bid,
})
}