Skip to content

Commit

Permalink
Refactor to observer pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
peterkeen committed Dec 10, 2013
1 parent 73e893a commit 69a51bc
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 16 deletions.
16 changes: 12 additions & 4 deletions bin/trading
Expand Up @@ -10,12 +10,20 @@ rescue LoadError
require 'trading'
end

class LoggingObserver
def trade(obj)
puts obj
end

def order(obj)
puts obj
end
end

engine = Trading::Engine.new
engine.add_observer(LoggingObserver.new)

ARGF.each do |line|
order = Trading::Order.parse(line.trim)
result = engine.submit_order(order)
if result
puts result
end
engine.submit_order(order)
end
21 changes: 18 additions & 3 deletions lib/trading/engine.rb
Expand Up @@ -6,15 +6,30 @@ class Trading::Engine

def initialize
@order_book = {}
@observers = []
end

def submit_order(order)
notify_observers(:order, order)

book = (order_book[order.commodity] ||= Trading::OrderBook.new)
book.submit_order(order)
if book.match?
return book.trade!
else
return false
trade = book.trade!
notify_observers(:trade, trade)
end
end

def add_observer(observer)
@observers << observer
end

private

def notify_observers(event, payload)
@observers.each do |observer|
observer.send(event, payload)
end
end

end
4 changes: 4 additions & 0 deletions lib/trading/order.rb
Expand Up @@ -35,6 +35,10 @@ def <=>(other)
return time_e
end

def to_s
[time, order_type, price, commodity, quantity].join("\t")
end

def split(amount)
if amount >= quantity
raise "Invalid split: desired amount #{amount} greater than available amount #{quantity}"
Expand Down
31 changes: 22 additions & 9 deletions spec/engine_spec.rb
Expand Up @@ -3,45 +3,58 @@
describe 'Trading::Engine' do
before do
@engine = Trading::Engine.new
@observer = TestObserver.new
@engine.add_observer @observer
end

describe '#submit_order' do
it "should return false for no match" do
order = Trading::Order.parse("2013-12-01T16:19:00Z\tBUY\tBTC\t100.000\t100")

@engine.submit_order(order).should eq(false)
@engine.submit_order(order)
@observer.trades.length.should eq(0)
end

it "should return a pair of orders for a match" do
buy = Trading::Order.parse("2013-12-01T16:19:00Z\tBUY\tBTC\t100.000\t100")
sell = Trading::Order.parse("2013-12-01T16:20:00Z\tSELL\tBTC\t100.000\t100")

@engine.submit_order(buy).should eq(false)
@engine.submit_order(sell).should eq(Trading::Trade.new(buy, sell))
@engine.submit_order(buy)
@observer.trades.length.should eq(0)

@engine.submit_order(sell)
@observer.trades.length.should eq(1)
@observer.trades.first.should eq(Trading::Trade.new(buy, sell))
end

it "should not match differing commodities" do
buy = Trading::Order.parse("2013-12-01T16:19:00Z\tBUY\tBTC\t100.000\t100")
sell = Trading::Order.parse("2013-12-01T16:20:00Z\tSELL\tUSD\t100.000\t100")

@engine.submit_order(buy).should eq(false)
@engine.submit_order(sell).should eq(false)
@engine.submit_order(buy)
@observer.trades.length.should eq(0)
@engine.submit_order(sell)
@observer.trades.length.should eq(0)
end

it "should not match differing prices" do
buy = Trading::Order.parse("2013-12-01T16:19:00Z\tBUY\tBTC\t100.000\t100")
sell = Trading::Order.parse("2013-12-01T16:20:00Z\tSELL\tBTC\t100.001\t100")

@engine.submit_order(buy).should eq(false)
@engine.submit_order(sell).should eq(false)
@engine.submit_order(buy)
@observer.trades.length.should eq(0)
@engine.submit_order(sell)
@observer.trades.length.should eq(0)
end

it "should not match differing quantities" do
buy = Trading::Order.parse("2013-12-01T16:19:00Z\tBUY\tBTC\t100.000\t100")
sell = Trading::Order.parse("2013-12-01T16:20:00Z\tSELL\tBTC\t100.000\t200")

@engine.submit_order(buy).should eq(false)
@engine.submit_order(sell).should eq(false)
@engine.submit_order(buy)
@observer.trades.length.should eq(0)
@engine.submit_order(sell)
@observer.trades.length.should eq(0)
end
end
end
18 changes: 18 additions & 0 deletions spec/spec_helper.rb
@@ -1 +1,19 @@
require_relative '../lib/trading'

class TestObserver

attr_reader :orders, :trades

def initialize
@orders = []
@trades = []
end

def trade(obj)
@trades << obj
end

def order(obj)
@orders << obj
end
end

0 comments on commit 69a51bc

Please sign in to comment.