Implement a limit volume tracker

Implement the limit volume tracker that keeps track of the limit
volumes and emits change events that can be used by clients to
update their copy of the order book
This commit is contained in:
Tim Kächele 2023-11-08 22:47:08 +01:00
parent b7df45794c
commit 188f45d4c4
3 changed files with 135 additions and 0 deletions

View File

@ -5,6 +5,7 @@ require_relative "book/trade"
require_relative "book/order"
require_relative "book/limit_order_book"
require_relative "book/matcher"
require_relative "book/limit_volume_tracker"
module Rex
module Book

View File

@ -0,0 +1,63 @@
module Rex
module Book
class LimitVolumeTracker
LimitVolumeChange = Struct.new(:side, :price, :new_volume)
attr_reader :volumes
def initialize
@volumes = Hash.new { 0 }
end
def add_order(order)
volumes[[order.is_buy, order.price]] += order.remaining_quantity
[
LimitVolumeChange.new(
side(order),
order.price,
volumes[[order.is_buy, order.price]]
)
]
end
def remove_order(order)
volumes[[order.is_buy, order.price]] -= order.remaining_quantity
[
LimitVolumeChange.new(
side(order),
order.price,
volumes[[order.is_buy, order.price]]
)
]
end
def process_trade(trade)
buy_order = trade.buy_order
sell_order = trade.sell_order
volumes[[buy_order.is_buy, buy_order.price]] -= trade.quantity
volumes[[sell_order.is_buy, sell_order.price]] -= trade.quantity
[
LimitVolumeChange.new(
:buy,
buy_order.price,
volumes[[buy_order.is_buy, buy_order.price]]
),
LimitVolumeChange.new(
:sell,
sell_order.price,
volumes[[sell_order.is_buy, sell_order.price]]
)
]
end
private
def side(order)
order.is_buy ? :buy : :sell
end
end
end
end

View File

@ -0,0 +1,71 @@
# frozen_string_literal: true
RSpec.describe Rex::Book::LimitVolumeTracker do
let(:instance) { described_class.new }
let(:sell_order) { build(:order, is_buy: false, price: 100, quantity: 250) }
let(:buy_order) { build(:order, is_buy: true, price: 100, quantity: 200) }
describe "#add_order" do
it "adds the quantity to the limit volume" do
expect { instance.add_order(sell_order) }.to(
change { instance.volumes[[false, 100]] }.to(250)
)
end
it "returns the changes limit volumes as a struct" do
expect(instance.add_order(sell_order)).to eq([
Rex::Book::LimitVolumeTracker::LimitVolumeChange.new(:sell, 100, 250)
])
end
end
describe "#remove_order" do
before do
instance.add_order(sell_order)
end
it "removes the quantity from the limit volume" do
expect { instance.remove_order(sell_order) }.to(
change { instance.volumes[[false, 100]] }.from(250).to(0)
)
end
it "returns the changes limit volumes as a struct" do
expect(instance.remove_order(sell_order)).to eq([
Rex::Book::LimitVolumeTracker::LimitVolumeChange.new(:sell, 100, 0)
])
end
end
describe "#process_trade" do
let(:trade) do
Rex::Book::Trade.new(
buy_order: buy_order,
sell_order: sell_order,
price: 100,
quantity: 200
)
end
before do
instance.add_order(sell_order)
instance.add_order(buy_order)
end
it "adjusts the volumes of the involved limits" do
expect { instance.process_trade(trade) }.to(
change { instance.volumes[[false, 100]] }.from(250).to(50)
.and(
change { instance.volumes[[true, 100]] }.from(200).to(0)
)
)
end
it "returns the changes limit volumes as a struct" do
expect(instance.process_trade(trade)).to eq([
Rex::Book::LimitVolumeTracker::LimitVolumeChange.new(:buy, 100, 0),
Rex::Book::LimitVolumeTracker::LimitVolumeChange.new(:sell, 100, 50)
])
end
end
end