Skip to content

Instantly share code, notes, and snippets.

@thisiscetin
Last active April 9, 2025 08:37
Show Gist options
  • Save thisiscetin/f246f8911aa1a34eebcca2885a5f3f8e to your computer and use it in GitHub Desktop.
Save thisiscetin/f246f8911aa1a34eebcca2885a5f3f8e to your computer and use it in GitHub Desktop.
Ruby Match Engine- Book Level Implementation
# frozen_string_literal: true
# Struct representing an order (limit or market)
Order = Struct.new(:uid, :user_id, :price, :quantity, :type, :side)
# Struct representing a successful match between a market and a limit order
OrderMatch = Struct.new(:uid, :limit_order_id, :market_order_id, :amount)
class Level
EPSILON = 1e-8 # Used to compare floating point numbers safely
def initialize(base_price, side = :buy, step_size = 0.01)
@base_price = base_price
@side = side
@step_size = step_size
@steps = (1.0 / @step_size).to_i
@data = Array.new(@steps) { [] }
@match_id = 0
end
# Places a limit order into its correct price bucket
def place_limit(order)
validate_order(order, expected_side: @side, expected_type: :limit)
raise ArgumentError, 'Invalid price step' unless valid_price?(order.price)
@data[price_index(order.price)] << order
end
# Matches a market order against the level's limit orders
# Depending on side, iterates from best to worst price
def match_market(order)
validate_order(order, expected_side: opposite_side, expected_type: :market)
# If this is a buy level, user is selling → start from highest bid
# If this is a sell level, user is buying → start from lowest ask
iterator = @side == :buy ? (@steps - 1).downto(0) : 0.upto(@steps - 1)
match_order(order, iterator)
end
# Returns a flat snapshot of all active limit orders in this level
# in its natural order which removes the need for sorting
def snapshot
@data.lazy.flat_map(&:itself)
end
private
# Validates order side and type before matching/placing order
def validate_order(order, expected_side:, expected_type:)
raise ArgumentError, "Invalid order side (#{order.side})" unless order.side == expected_side
raise ArgumentError, "Invalid order type (#{order.type})" unless order.type == expected_type
end
# Checks if a price is aligned with the configured step size
def valid_price?(price)
steps = (price - @base_price) / @step_size
(steps - steps.round).abs < EPSILON
end
# Calculates the array index for a given price
def price_index(price)
raise ArgumentError, "Price must be aligned with step size #{@step_size}" unless valid_price?(price)
((price - @base_price) / @step_size).round
end
# Returns the opposite order side (:buy → :sell, or vice versa)
def opposite_side
@side == :buy ? :sell : :buy
end
# Core matching logic — iterates over limit orders and creates matches
def match_order(order, iterator)
matches = []
remaining = order.quantity
iterator.each do |i|
next if @data[i].empty?
new_level_orders = []
@data[i].each do |limit_order|
break if remaining <= 0
trade_quantity = [limit_order.quantity, remaining].min
matches << OrderMatch.new(
@match_id += 1,
limit_order.uid,
order.uid,
trade_quantity
)
remaining -= trade_quantity
limit_order.quantity -= trade_quantity
new_level_orders << limit_order if limit_order.quantity > EPSILON
end
# Replace level with remaining orders (or clear it)
@data[i] = new_level_orders if new_level_orders
break if remaining <= 0
end
matches
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment