package orderbook import ( "sort" "sync" "github.com/genex/trading-service/internal/domain/entity" ) type PriceLevel struct { Price float64 Orders []*entity.Order } type OrderBook struct { CouponID string Bids []PriceLevel // sorted desc (highest first) Asks []PriceLevel // sorted asc (lowest first) mu sync.RWMutex } func NewOrderBook(couponID string) *OrderBook { return &OrderBook{CouponID: couponID} } func (ob *OrderBook) AddOrder(order *entity.Order) { ob.mu.Lock() defer ob.mu.Unlock() if order.Side == entity.Buy { ob.addToPriceLevels(&ob.Bids, order, true) } else { ob.addToPriceLevels(&ob.Asks, order, false) } } func (ob *OrderBook) RemoveOrder(orderID string, side entity.OrderSide) bool { ob.mu.Lock() defer ob.mu.Unlock() levels := &ob.Bids if side == entity.Sell { levels = &ob.Asks } for i, level := range *levels { for j, o := range level.Orders { if o.ID == orderID { level.Orders = append(level.Orders[:j], level.Orders[j+1:]...) if len(level.Orders) == 0 { *levels = append((*levels)[:i], (*levels)[i+1:]...) } else { (*levels)[i] = level } return true } } } return false } func (ob *OrderBook) BestBid() *PriceLevel { ob.mu.RLock() defer ob.mu.RUnlock() if len(ob.Bids) == 0 { return nil } return &ob.Bids[0] } func (ob *OrderBook) BestAsk() *PriceLevel { ob.mu.RLock() defer ob.mu.RUnlock() if len(ob.Asks) == 0 { return nil } return &ob.Asks[0] } func (ob *OrderBook) Snapshot(depth int) (bids []PriceLevel, asks []PriceLevel) { ob.mu.RLock() defer ob.mu.RUnlock() bidDepth := min(depth, len(ob.Bids)) askDepth := min(depth, len(ob.Asks)) bids = make([]PriceLevel, bidDepth) copy(bids, ob.Bids[:bidDepth]) asks = make([]PriceLevel, askDepth) copy(asks, ob.Asks[:askDepth]) return } func (ob *OrderBook) addToPriceLevels(levels *[]PriceLevel, order *entity.Order, descending bool) { for i, level := range *levels { if level.Price == order.Price { (*levels)[i].Orders = append((*levels)[i].Orders, order) return } } *levels = append(*levels, PriceLevel{Price: order.Price, Orders: []*entity.Order{order}}) sort.Slice(*levels, func(i, j int) bool { if descending { return (*levels)[i].Price > (*levels)[j].Price } return (*levels)[i].Price < (*levels)[j].Price }) } func min(a, b int) int { if a < b { return a } return b }