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 ADDED
@@ -0,0 +1,24 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+ log
21
+ .idea
22
+ .bundle
23
+
24
+ ## PROJECT::SPECIFIC
data/HISTORY ADDED
@@ -0,0 +1,11 @@
1
+ == 0.0.0 / 2011-03-18
2
+
3
+ * Birthday!
4
+
5
+ == 0.0.1 / 2011-03-18
6
+
7
+ * Structure created
8
+
9
+ == 0.0.2 / 2011-03-19
10
+
11
+ * Namespace renamed to Orders
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Arvicco
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,26 @@
1
+ = orders
2
+ by:: Arvicco
3
+ url:: http://github.com/arvicco/orders
4
+
5
+ == DESCRIPTION:
6
+
7
+ Basic structures used to create DOM models.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ Enclosed structures are used to accumulate, analyse and visualize streams of market
12
+ order data (either in aggregated or full order log form). They are required by the
13
+ client and gateway modules that deal with market order data streams and derived
14
+ artefacts (such as OrderBooks).
15
+
16
+ Data structures need to be:
17
+ 1) memory-efficient
18
+ 2) thread-safe (without too much synchronization penalty)
19
+ 3) iteration-safe (adding new element while iterating should not raise exception)
20
+
21
+ == INSTALL:
22
+
23
+ $ sudo gem install order_book
24
+
25
+ == LICENSE:
26
+ Copyright (c) 2011 Arvicco. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ begin
2
+ require 'rake'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rake', '~> 0.8.3.1'
6
+ require 'rake'
7
+ end
8
+
9
+ require 'pathname'
10
+
11
+ BASE_PATH = Pathname.new(__FILE__).dirname
12
+ LIB_PATH = BASE_PATH + 'lib'
13
+ PKG_PATH = BASE_PATH + 'pkg'
14
+ DOC_PATH = BASE_PATH + 'rdoc'
15
+
16
+ $LOAD_PATH.unshift LIB_PATH.to_s
17
+ require 'version'
18
+
19
+ NAME = 'orders'
20
+ CLASS_NAME = Orders
21
+
22
+ # Load rakefile tasks
23
+ Dir['tasks/*.rake'].sort.each { |file| load file }
24
+
25
+ # Project-specific tasks
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,9 @@
1
+ Feature: something something
2
+ In order to something something
3
+ A user something something
4
+ something something something
5
+
6
+ Scenario: something something
7
+ Given inspiration
8
+ When I create a sweet new gem
9
+ Then everyone should see how awesome I am
File without changes
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+
3
+ require 'pathname'
4
+ require 'bundler'
5
+ Bundler.setup
6
+ Bundler.require :cucumber
7
+
8
+ require 'order_book'
9
+
10
+ BASE_PATH = Pathname.new(__FILE__).dirname + '../..'
@@ -0,0 +1,12 @@
1
+ module SystemHelper
2
+
3
+ def windows?
4
+ RUBY_PLATFORM =~ /mswin|windows|mingw/ || cygwin?
5
+ end
6
+
7
+ def cygwin?
8
+ RUBY_PLATFORM =~ /cygwin/
9
+ end
10
+ end
11
+
12
+ World(WinGui, SystemHelper)
data/lib/legacy.rb ADDED
@@ -0,0 +1,443 @@
1
+ # Legacy VCL-based code to be converted into new efficient Ruby code
2
+
3
+ module VCL
4
+
5
+ #type
6
+ # tDuplicates = [:dup_accept, :dup_ignore, :dup_replace]
7
+ # // ������� ����� "������" � ���������� ��������������� ������������ ���������
8
+ #type CustomList = class(tList)
9
+ # procedure clear; override;
10
+ # procedure freeitem(item: pointer); virtual; abstract;
11
+ # procedure freeall; virtual;
12
+ # procedure delete(index: longint); virtual;
13
+ # procedure remove(item: pointer); virtual;
14
+ # end;
15
+ class CustomList < Array
16
+
17
+ def clear
18
+ (0...size).each { freeitem(self[i]) }
19
+ super
20
+ end
21
+
22
+ def freeall
23
+ clear
24
+ end
25
+
26
+ def freeitem item
27
+ end
28
+
29
+ # Standard #delete_at instead of #delete
30
+
31
+ # Deletes ALL items from arr that are equal to obj.?
32
+ # No, we need to remove ONE item by "pointer"
33
+ def remove item #(item: pointer)
34
+ freeitem item
35
+ delete item
36
+ end
37
+ end # class CustomList
38
+
39
+ # // ������� ����� "������������� ������"
40
+ #type tSortedList = class(CustomList)
41
+ # fDuplicates : tDuplicates;
42
+ # constructor create;
43
+ # function checkitem(item: pointer): boolean; virtual; abstract;
44
+ # function compare(item1, item2: pointer): longint; virtual; abstract;
45
+ # function search(item: pointer; var index: longint): boolean; virtual;
46
+ # procedure add(item: pointer); virtual;
47
+ # procedure insert(index: longint; item: pointer); virtual;
48
+ # end;
49
+ class SortedList < CustomList
50
+
51
+ attr_accessor :duplicates
52
+
53
+ def initialize
54
+ @duplicates = :dup_accept
55
+ super
56
+ end
57
+
58
+ # Returns true and item's index if item is in the List
59
+ # Returns false and item's index if item not found
60
+ def search item #(item: pointer; var index: longint): boolean
61
+ result = false
62
+ l = 0
63
+ h = size - 1
64
+ while (l <= h) do
65
+ i = (l + h) >> 1
66
+ case compare(self[i], item)
67
+ when -1
68
+ l = i + 1
69
+ when 1
70
+ h = i - 1
71
+ when 0
72
+ h = i - 1
73
+ result = true
74
+ l = i if @duplicates == :dup_ignore || @duplicates == :dup_replace
75
+ end
76
+ end
77
+ index = l
78
+ [result, index]
79
+ end
80
+
81
+ def add item #(item: pointer)
82
+ if checkitem(item)
83
+ result, index = search(item)
84
+ if result
85
+ case @duplicates
86
+ when :dup_accept
87
+ insert(index, item)
88
+ when :dup_ignore
89
+ freeitem(item)
90
+ when :dup_replace
91
+ freeitem(self[index])
92
+ self[index] = item
93
+ end
94
+ else
95
+ insert(index, item)
96
+ end
97
+ else
98
+ freeitem(item)
99
+ end
100
+ end
101
+
102
+ def insert index, item #(index: longint; item: pointer)
103
+ if checkitem(item)
104
+ super index, item
105
+ end
106
+ end
107
+ end # class SortedList
108
+
109
+ # // ������ ������� �� ����
110
+ #type tOrderBook = class(tSortedList)
111
+ # private
112
+ # fisin_id : longint;
113
+ # fchanged : boolean;
114
+ # public
115
+ # procedure freeitem(item: pointer); override;
116
+ # function checkitem(item: pointer): boolean; override;
117
+ # function compare(item1, item2: pointer): longint; override;
118
+ #
119
+ # procedure add(item: pointer); override;
120
+ # procedure remove(item: pointer); override;
121
+ #
122
+ # property isin_id: longint read fisin_id;
123
+ # property changed: boolean read fchanged write fchanged;
124
+ # end;
125
+ class OrderBook < SortedList
126
+ attr_accessor :isin_id, :changed
127
+
128
+ def initialize isin_id
129
+ @isin_id = isin_id
130
+ super()
131
+ end
132
+
133
+ def checkitem item #(item: pointer): boolean
134
+ item.price > 0
135
+ end
136
+
137
+ def compare item1, item2 #(item1, item2: pointer): longint
138
+ item1.price <=> item2.price
139
+ end
140
+
141
+ def add item #(item: pointer)
142
+ super item
143
+ @changed = true
144
+ end
145
+
146
+ def remove item #(item: pointer)
147
+ super item
148
+ @changed = true
149
+ end
150
+ end # class OrderBook
151
+
152
+ # // ������ ��������
153
+ #type tPriceLists = class(tSortedList)
154
+ # private
155
+ # tmp_ordbook : tOrderBook;
156
+ # public
157
+ # destructor destroy; override;
158
+ # procedure freeitem(item: pointer); override;
159
+ # function checkitem(item: pointer): boolean; override;
160
+ # function compare(item1, item2: pointer): longint; override;
161
+ # function searchadditem(isin_id: longint): tOrderBook;
162
+ # end;
163
+ #
164
+ class OrderBookList < SortedList
165
+
166
+ def checkitem item #(item: pointer): boolean
167
+ item
168
+ end
169
+
170
+ def compare(item1, item2) #(item1, item2: pointer): longint
171
+ item1.isin_id <=> item2.isin_id;
172
+ end
173
+
174
+ def searchadditem(isin_id) #(isin_id: longint): OrderBook
175
+ order_book = OrderBook.new(isin_id)
176
+ exists, idx = search(order_book)
177
+ if exists
178
+ result = self[idx]
179
+ else
180
+ result = order_book
181
+ insert(idx, result)
182
+ end
183
+ result
184
+ end
185
+
186
+ end # class OrderBook
187
+
188
+ # // ����� ������� ���������
189
+ #type OrderList = class(tSortedList)
190
+ # fOrderBooks : tPriceLists;
191
+ # constructor create;
192
+ # destructor destroy; override;
193
+ # procedure freeitem(item: pointer); override;
194
+ # function checkitem(item: pointer): boolean; override;
195
+ # function compare(item1, item2: pointer): longint; override;
196
+ # function searchadditem(isin_id: longint): tOrderBook;
197
+ # function addrecord(isin_id: longint; const id, rev: int64; const price, volume: double; buysell: longint): boolean;
198
+ # function delrecord(const id: int64): boolean;
199
+ # procedure clearbyrev(const rev: int64);
200
+ # end;
201
+ class OrderList < SortedList
202
+ attr_accessor :order_books
203
+
204
+ def initialize
205
+ super
206
+ @order_books = OrderBookList.new
207
+ end
208
+
209
+ def freeitem item #(item: pointer)
210
+ item.order_book.remove(item) if item.order_book
211
+ end
212
+
213
+ def checkitem item #(item: pointer): boolean
214
+ item
215
+ end
216
+
217
+ def compare(item1, item2) #: pointer): longint
218
+ item1.id <=> item2.id
219
+ end
220
+
221
+ def searchadditem isin_id #(isin_id: longint): OrderBook
222
+ @order_books.searchadditem(isin_id)
223
+ end
224
+
225
+ def addrecord isin_id, id, rev, price, volume, buysell #(isin_id: longint; const id, rev: int64; const price, volume: double; buysell: longint): boolean
226
+ item = OrderBookItem.new
227
+ item.id = id
228
+ result, idx = search(item)
229
+ if result
230
+ item = self[idx]
231
+
232
+ if item.price != price # �������, ��� ���� ����������
233
+ item.order_book.remove(item) if item.order_book # ������� �� �������
234
+ if price > 0
235
+ item.order_book = searchadditem(isin_id) unless item.order_book
236
+ item.order_book.add(item) if item.order_book # ��������� � ������
237
+ else
238
+ item.order_book = nil;
239
+ end
240
+ end
241
+
242
+ item.rev = rev
243
+ item.price = price
244
+ item.volume = volume
245
+ item.buysell = buysell
246
+ else
247
+ item.rev = rev
248
+ item.price = price
249
+ item.volume = volume
250
+ item.buysell = buysell
251
+
252
+ if (item.price > 0)
253
+ item.order_book = searchadditem(isin_id)
254
+ item.order_book.add(item) if item.order_book # ��������� � ������
255
+ else
256
+ item.order_book = nil
257
+ end
258
+ insert(idx, item) # ��������� � ����� �������
259
+ end
260
+ end
261
+
262
+ def delrecord id #(const id: int64): boolean
263
+ item = OrderBookItem.new
264
+ item.id = id
265
+ result, idx = search(item)
266
+ delete_at(idx) if result # ������� �� ����� �������
267
+ end
268
+
269
+ # Delete all records with rev less than given
270
+ def clearbyrev rev #(const rev: int64)
271
+ (size-1).downto(0) do |i|
272
+ delete_at(i) if self[i].rev < rev # ������� �� ����� �������
273
+ end
274
+ end
275
+
276
+ end #class OrderList
277
+
278
+ # // ������� "������ � �������"
279
+ #type pOrderBookItem = ^tOrderBookItem;
280
+ # tOrderBookItem = record
281
+ # id : int64;
282
+ # rev : int64;
283
+ # price : double; // ����
284
+ # volume : double; // ���-��
285
+ # buysell : longint; // �������(1)/�������(2)
286
+ # order_book : tOrderBook;
287
+ # end;
288
+ class OrderBookItem
289
+ attr_accessor :id, :rev, :price, :volume, :buysell, :order_book
290
+
291
+ def inspect
292
+ "#{id}:#{price}>#{volume}#{buysell == 1 ? '+' : '-'}"
293
+ end
294
+
295
+ alias to_s inspect
296
+ end
297
+
298
+ #######################
299
+ # New hierarchy:
300
+ #######################
301
+
302
+ # Abstract (equivalent of SortedList)
303
+ # ������� ����� "������������� ������"
304
+ class SortedHash < Hash
305
+
306
+ def free item
307
+ end
308
+
309
+ def check item
310
+ true
311
+ end
312
+
313
+ def index item
314
+ item.object_id
315
+ end
316
+
317
+ # Adds new item only if it passes check...
318
+ # TODO: What to do with the item it should have replaced?!
319
+ def add item
320
+ self[index item] = item if check item
321
+ # check item ? super : free key # delete key
322
+ end
323
+
324
+ def remove item
325
+ free item
326
+ delete index item
327
+ end
328
+
329
+ def clear
330
+ each_value { |item| free item }
331
+ super
332
+ end
333
+ end # SortedHash
334
+
335
+ # Represents DOM (OrderBook) for one security
336
+ # ������ ������� �� ����
337
+ class DOM < SortedHash
338
+ attr_accessor :isin_id, :changed
339
+
340
+ def initialize isin_id
341
+ @isin_id = isin_id
342
+ @changed = false
343
+ super
344
+ end
345
+
346
+ def index item
347
+ item.price
348
+ end
349
+
350
+ def check item
351
+ item.price > 0
352
+ end
353
+
354
+ def add item
355
+ @changed = true # Marking DOM as changed
356
+ super
357
+ end
358
+
359
+ def remove item
360
+ @changed = true # Marking DOM as changed
361
+ super
362
+ end
363
+ end # class DOM
364
+
365
+
366
+ # Represents Hash of DOMs (OrderBooks) indexed by isin_id
367
+ # ������ ��������
368
+ class DOMHash < SortedHash
369
+
370
+ def index item
371
+ item.isin_id
372
+ end
373
+
374
+ # Always return DOM for isin_id, create one on spot if need be
375
+ def [] isin_id
376
+ super || add(DOM.new isin_id)
377
+ end
378
+ end # class DOMHash
379
+
380
+ # Represents Hash of all aggregated orders by (repl) id
381
+ # ����� ������� ���������
382
+ class OrderHash < SortedHash
383
+ attr_accessor :order_books
384
+
385
+ def index item
386
+ item.id
387
+ end
388
+
389
+ def initialize
390
+ super
391
+ @order_books = DOMHash.new
392
+ end
393
+
394
+ # We need to clear item from its order book before scrapping it
395
+ def free item
396
+ item.order_book.remove item if item.order_book
397
+ end
398
+
399
+ # Rebooks item to a correct order book, given its price
400
+ def rebook item, book
401
+ if (item.price > 0)
402
+ # item represents new aggr_order with price
403
+ item.order_book = book unless item.order_book
404
+ book.add item # ��������� � ������
405
+ else
406
+ # item clears previous aggr_order for given price
407
+ item.order_book = nil
408
+ end
409
+ end
410
+
411
+ # process_record
412
+ def addrecord isin_id, id, rev, price, volume, buysell
413
+ item = self[id] || OrderBookItem.new
414
+
415
+ price_changed = item.price != price # �������, ��� ���� ����������
416
+
417
+ item.id = id
418
+ item.rev = rev
419
+ item.price = price
420
+ item.volume = volume
421
+ item.buysell = buysell
422
+
423
+ if price_changed
424
+ if self[id] # item is already here
425
+ item.order_book.remove item if item.order_book # free item - ������� �� �������
426
+ else # new item
427
+ add item
428
+ end
429
+ rebook item, @order_books[isin_id]
430
+ end
431
+ end
432
+
433
+ def delrecord id
434
+ remove self[id] if self[id]
435
+ end
436
+
437
+ # Clear all records with rev less than given
438
+ def clearbyrev rev #(const rev: int64)
439
+ each_value { |item| remove item if item.rev < rev } # ������� �� ����� �������
440
+ end
441
+ end # class OrderHash
442
+
443
+ end # module