Sure, let’s start by implementing Version 1 of the trading exchange in Go. We’ll follow the steps outlined in your initial requirements.
Version 1: Simplistic Logic
Step 1.1: Matching Algorithm for Same Amount Only with Price Priority, Time Priority
We’ll create a basic structure to represent orders and a matching engine that matches orders based on price and time priority.
Step 1.2: Provide Current Market Price
We’ll maintain the last deal price to represent the current market price.
Step 1.3: Store Unmatched Orders in Memory
We’ll use an in-memory data structure to store unmatched orders.
Step 1.4: Improve Matching Algorithm to Consider Amounts
We’ll enhance the matching algorithm to handle partial matches.
Let’s start with the basic structure and matching logic.
package main
import (
"fmt"
"sort"
"time"
)
// OrderType represents the type of order, either Buy or Sell.
type OrderType string
const (
Buy OrderType = "BUY"
Sell OrderType = "SELL"
)
// Order represents a trading order.
type Order struct {
ID int
Type OrderType
Price float64
Amount int
Timestamp time.Time
}
// OrderBook keeps track of all buy and sell orders.
type OrderBook struct {
BuyOrders []*Order
SellOrders []*Order
LastPrice float64
OrderID int
}
// NewOrderBook creates a new OrderBook.
func NewOrderBook() *OrderBook {
return &OrderBook{
BuyOrders: []*Order{},
SellOrders: []*Order{},
}
}
// AddOrder adds a new order to the order book.
func (ob *OrderBook) AddOrder(orderType OrderType, price float64, amount int) {
order := &Order{
ID: ob.OrderID,
Type: orderType,
Price: price,
Amount: amount,
Timestamp: time.Now(),
}
ob.OrderID++
if orderType == Buy {
ob.BuyOrders = append(ob.BuyOrders, order)
sort.Slice(ob.BuyOrders, func(i, j int) bool {
if ob.BuyOrders[i].Price == ob.BuyOrders[j].Price {
return ob.BuyOrders[i].Timestamp.Before(ob.BuyOrders[j].Timestamp)
}
return ob.BuyOrders[i].Price > ob.BuyOrders[j].Price
})
} else {
ob.SellOrders = append(ob.SellOrders, order)
sort.Slice(ob.SellOrders, func(i, j int) bool {
if ob.SellOrders[i].Price == ob.SellOrders[j].Price {
return ob.SellOrders[i].Timestamp.Before(ob.SellOrders[j].Timestamp)
}
return ob.SellOrders[i].Price < ob.SellOrders[j].Price
})
}
ob.matchOrders()
}
// matchOrders matches buy and sell orders based on price and time priority.
func (ob *OrderBook) matchOrders() {
for len(ob.BuyOrders) > 0 && len(ob.SellOrders) > 0 {
buyOrder := ob.BuyOrders[0]
sellOrder := ob.SellOrders[0]
if buyOrder.Price >= sellOrder.Price {
matchAmount := min(buyOrder.Amount, sellOrder.Amount)
buyOrder.Amount -= matchAmount
sellOrder.Amount -= matchAmount
ob.LastPrice = sellOrder.Price
fmt.Printf("Matched Order: Buy ID %d with Sell ID %d, Price: %.2f, Amount: %d\n",
buyOrder.ID, sellOrder.ID, sellOrder.Price, matchAmount)
if buyOrder.Amount == 0 {
ob.BuyOrders = ob.BuyOrders[1:]
}
if sellOrder.Amount == 0 {
ob.SellOrders = ob.SellOrders[1:]
}
} else {
break
}
}
}
// min returns the smaller of two integers.
func min(a, b int) int {
if a < b {
return a
}
return b
}
// GetCurrentMarketPrice returns the last deal price.
func (ob *OrderBook) GetCurrentMarketPrice() float64 {
return ob.LastPrice
}
func main() {
orderBook := NewOrderBook()
orderBook.AddOrder(Buy, 100.0, 10)
orderBook.AddOrder(Sell, 99.0, 5)
orderBook.AddOrder(Sell, 98.0, 10)
orderBook.AddOrder(Buy, 101.0, 15)
fmt.Printf("Current Market Price: %.2f\n", orderBook.GetCurrentMarketPrice())
}
Explanation
- Order and OrderType: We define the structure of an order and the type of order (Buy or Sell).
- OrderBook: This structure holds the buy and sell orders, the last matched price, and an auto-incrementing order ID.
- AddOrder: Adds a new order to the order book and sorts the orders based on price and timestamp.
- matchOrders: Matches buy and sell orders based on price and time priority. It handles partial matches and updates the order amounts.
- GetCurrentMarketPrice: Returns the last matched price.
This code provides a basic implementation of a trading exchange with simplistic logic. You can run the main
function to see how orders are added and matched.
Next steps would be to persist this data into an Oracle database (Version 2), use Redis for matching (Version 3), and integrate RabbitMQ/Kafka for asynchronous messaging (Version 4 and 5). Let me know how you’d like to proceed!
Let’s implement a trading exchange in go, shall we? we will have three versions at least.
Version 1. simplistic logic to do the job:
-1.1 matching algo for same amount only with price priority, time priority.
-1.2 provide current market price, that is of the last deal price.
-1.3 unmatched order stored in memory.
-At last improve 1.1 to a proper matching that has amount consideration, can match a portion of orders of each directions.
Version 2. Store the above into Oracle.
Version 3. Use Redis to do the matching.
Version 4. Use RabbitMQ/Kafka to send async message that store matched deal, to be later stored in Oracle, a suitable tablename.
Version 5. The Sender also need to have RabbitMQ/Kafka, for reliable message queueing to send to our exchange.
More waiting for my further insturctions