orders 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +24 -0
- data/HISTORY +11 -0
- data/LICENSE +20 -0
- data/README.rdoc +26 -0
- data/Rakefile +25 -0
- data/VERSION +1 -0
- data/features/order_book.feature +9 -0
- data/features/step_definitions/order_book_steps.rb +0 -0
- data/features/support/env.rb +10 -0
- data/features/support/world.rb +12 -0
- data/lib/legacy.rb +443 -0
- data/lib/orders.rb +9 -0
- data/lib/orders/indexed_list.rb +44 -0
- data/lib/orders/order_book.rb +33 -0
- data/lib/orders/order_book_item.rb +19 -0
- data/lib/orders/order_list.rb +23 -0
- data/lib/version.rb +8 -0
- data/spec/orders/indexed_list_spec.rb +15 -0
- data/spec/orders/order_book_item_spec.rb +35 -0
- data/spec/orders/order_book_spec.rb +73 -0
- data/spec/orders/order_list_spec.rb +84 -0
- data/spec/orders/shared_examples.rb +106 -0
- data/spec/spec_helper.rb +17 -0
- data/tasks/common.rake +18 -0
- data/tasks/doc.rake +14 -0
- data/tasks/gem.rake +40 -0
- data/tasks/git.rake +34 -0
- data/tasks/spec.rake +16 -0
- data/tasks/version.rake +71 -0
- metadata +128 -0
data/lib/orders.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Orders
|
|
2
|
+
# Abstract (equivalent of SortedList)
|
|
3
|
+
# ������� ����� "������������� ������"
|
|
4
|
+
class IndexedList < Hash
|
|
5
|
+
|
|
6
|
+
# Returns default list index for items
|
|
7
|
+
def index item
|
|
8
|
+
item.object_id
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Adds new item to the list (replaces item with the same index)
|
|
12
|
+
def add item
|
|
13
|
+
self[index item] = item
|
|
14
|
+
self
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
alias << add
|
|
18
|
+
|
|
19
|
+
# Removes item from the list
|
|
20
|
+
def remove item
|
|
21
|
+
delete index item
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Calls #remove for each item in list
|
|
26
|
+
def clear
|
|
27
|
+
each_value { |item| remove item }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Yields list items in order of their index
|
|
31
|
+
def each
|
|
32
|
+
if block_given?
|
|
33
|
+
keys.sort.each { |key| yield self[key] }
|
|
34
|
+
else
|
|
35
|
+
ary = []
|
|
36
|
+
keys.sort.each { |key| ary << self[key] }
|
|
37
|
+
ary
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Make direct setter private
|
|
42
|
+
private :[]=
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Orders
|
|
2
|
+
# Represents DOM (OrderBook) for one security
|
|
3
|
+
# ������ ������� �� ����
|
|
4
|
+
class OrderBook < IndexedList
|
|
5
|
+
|
|
6
|
+
attr_accessor :isin_id, :changed
|
|
7
|
+
|
|
8
|
+
def initialize isin_id
|
|
9
|
+
@isin_id = isin_id
|
|
10
|
+
@changed = true
|
|
11
|
+
super()
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def index item
|
|
15
|
+
item.price
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add item
|
|
19
|
+
if item.price > 0
|
|
20
|
+
@changed = true # Marking DOM as changed
|
|
21
|
+
super
|
|
22
|
+
else
|
|
23
|
+
self
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Does not call super!
|
|
28
|
+
def remove item
|
|
29
|
+
@changed = true if delete index item # Marking DOM as changed
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Orders
|
|
2
|
+
# Represents single price level for OrderBook for one security
|
|
3
|
+
# (aggregate bid or ask with aggregate volume)
|
|
4
|
+
# // ������� "������ � �������"
|
|
5
|
+
# tOrderBookItem = record
|
|
6
|
+
# id : int64;
|
|
7
|
+
# rev : int64;
|
|
8
|
+
# price : double; // ����
|
|
9
|
+
# volume : double; // ���-��
|
|
10
|
+
# buysell : longint; // �������(1)/�������(2)
|
|
11
|
+
# order_book : tOrderBook;
|
|
12
|
+
class OrderBookItem
|
|
13
|
+
attr_accessor :isin_id, :id, :rev, :price, :volume, :buysell, :order_book
|
|
14
|
+
|
|
15
|
+
def initialize opts = {}
|
|
16
|
+
opts.each {|key, value| send "#{key}=", value}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'orders/order_book'
|
|
2
|
+
|
|
3
|
+
module Orders
|
|
4
|
+
# Represents DOM (OrderBook) for one security
|
|
5
|
+
# ������ ������� �� ����
|
|
6
|
+
class OrderList < IndexedList
|
|
7
|
+
attr_accessor :order_books
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@order_books = {}
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def index item
|
|
15
|
+
item.id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add item
|
|
19
|
+
@order_books[item.isin_id] ||= Orders::OrderBook.new item.isin_id
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/version.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'orders/shared_examples.rb'
|
|
3
|
+
|
|
4
|
+
describe Orders::IndexedList do
|
|
5
|
+
subject { Orders::IndexedList.new }
|
|
6
|
+
let(:item_index) { @item.object_id }
|
|
7
|
+
|
|
8
|
+
before(:each) do
|
|
9
|
+
@item = Object.new
|
|
10
|
+
@item1 = Object.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it_behaves_like 'index_list'
|
|
14
|
+
end
|
|
15
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Orders::OrderBookItem do
|
|
4
|
+
describe '#new with empty initializer' do
|
|
5
|
+
subject { Orders::OrderBookItem.new }
|
|
6
|
+
|
|
7
|
+
its (:isin_id) {should == nil}
|
|
8
|
+
its (:id) {should == nil}
|
|
9
|
+
its (:rev) {should == nil}
|
|
10
|
+
its (:price) {should == nil}
|
|
11
|
+
its (:volume) {should == nil}
|
|
12
|
+
its (:buysell) {should == nil}
|
|
13
|
+
its (:order_book) {should == nil}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '#new with opts' do
|
|
17
|
+
subject { Orders::OrderBookItem.new :isin_id => 1234567,
|
|
18
|
+
:id => 12,
|
|
19
|
+
:rev => 123,
|
|
20
|
+
:price => 1234,
|
|
21
|
+
:volume => 12345,
|
|
22
|
+
:buysell => 1,
|
|
23
|
+
:order_book => 123456
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
its (:isin_id) {should == 1234567}
|
|
27
|
+
its (:id) {should == 12}
|
|
28
|
+
its (:rev) {should == 123}
|
|
29
|
+
its (:price) {should == 1234}
|
|
30
|
+
its (:volume) {should == 12345}
|
|
31
|
+
its (:buysell) {should == 1}
|
|
32
|
+
its (:order_book) {should == 123456}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'orders/shared_examples.rb'
|
|
3
|
+
|
|
4
|
+
describe Orders::OrderBook do
|
|
5
|
+
subject { Orders::OrderBook.new 123456 }
|
|
6
|
+
let(:item_index) { @item.price }
|
|
7
|
+
|
|
8
|
+
before(:each) do
|
|
9
|
+
@item = Orders::OrderBookItem.new :id => 0, :price => 20
|
|
10
|
+
@item1 = Orders::OrderBookItem.new :id => 1, :price => 10
|
|
11
|
+
@zero_price_item = Orders::OrderBookItem.new :id => 2, :price => 0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it_behaves_like 'index_list'
|
|
15
|
+
|
|
16
|
+
its (:isin_id) {should == 123456}
|
|
17
|
+
its (:changed) {should == true}
|
|
18
|
+
|
|
19
|
+
describe 'adding item' do
|
|
20
|
+
before(:each) do
|
|
21
|
+
subject.add(@item).size.should == 1
|
|
22
|
+
subject.changed = false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'with zero price' do
|
|
26
|
+
it 'returns self' do
|
|
27
|
+
subject.add(@zero_price_item).should == subject
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'does not add such item to the list' do
|
|
31
|
+
subject.add(@zero_price_item)
|
|
32
|
+
subject[subject.index @zero_price_item].should == nil
|
|
33
|
+
subject.size.should == 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'does not set changed status to true' do
|
|
37
|
+
subject.add(@zero_price_item)
|
|
38
|
+
subject.changed.should == false
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'sets changed status to true if item was added' do
|
|
43
|
+
subject.add(@item1)
|
|
44
|
+
subject.changed.should == true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe 'removing item' do
|
|
50
|
+
before(:each) do
|
|
51
|
+
subject.add(@item).size.should == 1
|
|
52
|
+
subject.changed = false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'sets changed status to true if item was removed' do
|
|
56
|
+
subject.remove(@item)
|
|
57
|
+
subject.changed.should == true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'that is not in list' do
|
|
61
|
+
|
|
62
|
+
it 'returns self' do
|
|
63
|
+
subject.remove(@item1).should == subject
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'does not set changed status to true' do
|
|
67
|
+
subject.remove(@item1)
|
|
68
|
+
subject.changed.should == false
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
require 'orders/shared_examples.rb'
|
|
4
|
+
|
|
5
|
+
#noinspection RubyResolve
|
|
6
|
+
describe Orders::OrderList do
|
|
7
|
+
subject { Orders::OrderList.new }
|
|
8
|
+
let(:item_index) { @item.id }
|
|
9
|
+
|
|
10
|
+
before(:each) do
|
|
11
|
+
@item = Orders::OrderBookItem.new :id => 0, :price => 20
|
|
12
|
+
@item1 = Orders::OrderBookItem.new :id => 1, :price => 10
|
|
13
|
+
@zero_price_item = Orders::OrderBookItem.new :id => 2, :price => 0
|
|
14
|
+
@repeat_zero_price_item = Orders::OrderBookItem.new :id => 0, :price => 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it_behaves_like 'index_list'
|
|
18
|
+
|
|
19
|
+
specify { subject.order_books.should be_empty }
|
|
20
|
+
|
|
21
|
+
describe 'adding item' do
|
|
22
|
+
context 'to empty OrderList' do
|
|
23
|
+
it 'creates appropriate order book' do
|
|
24
|
+
subject.add(@item)
|
|
25
|
+
subject.order_books.should_not be_empty
|
|
26
|
+
subject.order_books[@item.isin_id].should be_an Orders::OrderBook
|
|
27
|
+
subject.order_books.should have(1).book
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context 'to non-empty OrderList' do
|
|
33
|
+
before(:each) do
|
|
34
|
+
subject.add(@item).size.should == 1
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
# context 'with zero price' do
|
|
38
|
+
# it 'returns self' do
|
|
39
|
+
# subject.add(@zero_price_item).should == subject
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# it 'does not add such item to the list' do
|
|
43
|
+
# subject.add(@zero_price_item)
|
|
44
|
+
# subject[subject.index @zero_price_item].should == nil
|
|
45
|
+
# subject.size.should == 1
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# it 'does not set changed status to true' do
|
|
49
|
+
# subject.add(@zero_price_item)
|
|
50
|
+
# subject.changed.should == false
|
|
51
|
+
# end
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
it 'sets changed status to true if item was added' do
|
|
55
|
+
subject.add(@item1)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe 'removing item' do
|
|
61
|
+
# before(:each) do
|
|
62
|
+
# subject.add(@item).size.should == 1
|
|
63
|
+
## @item.order_book?
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# it 'sets changed status to true if item was removed' do
|
|
67
|
+
# subject.remove(@item)
|
|
68
|
+
# subject.changed.should == true
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# context 'that is not in list' do
|
|
72
|
+
#
|
|
73
|
+
# it 'returns self' do
|
|
74
|
+
# subject.remove(@item1).should == subject
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# it 'does not set changed status to true' do
|
|
78
|
+
# subject.remove(@item1)
|
|
79
|
+
# subject.changed.should == false
|
|
80
|
+
# end
|
|
81
|
+
# end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
shared_examples_for 'index_list' do
|
|
2
|
+
|
|
3
|
+
describe 'items get/set' do
|
|
4
|
+
it 'returns item from list by their index' do
|
|
5
|
+
subject.add(@item)[item_index].should == @item
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it 'returns nil when item with requested index not in collection' do
|
|
9
|
+
subject[item_index].should == nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'is not possible to add item into collection directly' do
|
|
13
|
+
expect { subject[item_index] = @item }.to raise_error NoMethodError
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#index' do
|
|
18
|
+
it 'indexes arbitrary items by their index (redefined in subclasses)' do
|
|
19
|
+
subject.index(@item).should == item_index
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#add' do
|
|
24
|
+
it 'returns self for easy method chaining' do
|
|
25
|
+
subject.add(@item).should == subject
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'adds items to indexed list' do
|
|
29
|
+
subject.add(@item)
|
|
30
|
+
subject.values.should include @item
|
|
31
|
+
subject[item_index].should == @item
|
|
32
|
+
subject.size.should == 1
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'adds items to using alias <<' do
|
|
36
|
+
subject << @item
|
|
37
|
+
subject.values.should include @item
|
|
38
|
+
subject[item_index].should == @item
|
|
39
|
+
subject.size.should == 1
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#remove' do
|
|
44
|
+
before(:each) { subject.add(@item).add(@item1).size.should == 2 }
|
|
45
|
+
|
|
46
|
+
it 'returns self for easy method chaining' do
|
|
47
|
+
subject.remove(@item).should == subject
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'removes item from indexed list' do
|
|
51
|
+
subject.remove(@item)
|
|
52
|
+
subject.values.should_not include @item
|
|
53
|
+
subject[item_index].should == nil
|
|
54
|
+
subject.size.should == 1
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe '#clear' do
|
|
59
|
+
before(:each) { subject.add(@item).add(@item1) }
|
|
60
|
+
|
|
61
|
+
it 'removes all items from list' do
|
|
62
|
+
subject.clear
|
|
63
|
+
subject.should be_empty
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'ensures that #remove method is called once for each item in list' do
|
|
67
|
+
subject.should_receive(:remove).twice
|
|
68
|
+
subject.clear
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe '#each' do
|
|
73
|
+
before(:each) { subject.add(@item).add(@item1) }
|
|
74
|
+
|
|
75
|
+
it 'yields items from list in index order' do
|
|
76
|
+
@count = 0
|
|
77
|
+
subject.each do |item|
|
|
78
|
+
@count += 1
|
|
79
|
+
case @count
|
|
80
|
+
when 1
|
|
81
|
+
if subject.index(@item) < subject.index(@item1)
|
|
82
|
+
item.should == @item
|
|
83
|
+
else
|
|
84
|
+
item.should == @item1
|
|
85
|
+
end
|
|
86
|
+
when 2
|
|
87
|
+
if subject.index(@item) < subject.index(@item1)
|
|
88
|
+
item.should == @item1
|
|
89
|
+
else
|
|
90
|
+
item.should == @item
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
@count.should == 2
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'returns list item in array, sorted by their index, if no block given' do
|
|
98
|
+
if subject.index(@item) < subject.index(@item1)
|
|
99
|
+
subject.each.should == [@item, @item1]
|
|
100
|
+
else
|
|
101
|
+
subject.each.should == [@item1, @item]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|