fin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.gitignore +26 -0
  2. data/HISTORY +27 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +36 -0
  5. data/Rakefile +25 -0
  6. data/VERSION +1 -0
  7. data/features/order_book.feature +9 -0
  8. data/features/step_definitions/order_book_steps.rb +0 -0
  9. data/features/support/env.rb +10 -0
  10. data/features/support/world.rb +12 -0
  11. data/lib/fin.rb +13 -0
  12. data/lib/fin/book.rb +50 -0
  13. data/lib/fin/book_manager.rb +42 -0
  14. data/lib/fin/changed_list.rb +49 -0
  15. data/lib/fin/container_list.rb +33 -0
  16. data/lib/fin/deal_list.rb +18 -0
  17. data/lib/fin/indexed_list.rb +74 -0
  18. data/lib/fin/models/deal.rb +75 -0
  19. data/lib/fin/models/instrument.rb +78 -0
  20. data/lib/fin/models/model.rb +39 -0
  21. data/lib/fin/models/money_limit.rb +81 -0
  22. data/lib/fin/models/order.rb +45 -0
  23. data/lib/fin/models/position.rb +57 -0
  24. data/lib/fin/order_list.rb +17 -0
  25. data/lib/legacy.rb +443 -0
  26. data/lib/version.rb +8 -0
  27. data/spec/fin/book_spec.rb +215 -0
  28. data/spec/fin/changed_list_spec.rb +16 -0
  29. data/spec/fin/container_list_spec.rb +63 -0
  30. data/spec/fin/deal_list_spec.rb +102 -0
  31. data/spec/fin/indexed_list_spec.rb +20 -0
  32. data/spec/fin/models/deal_spec.rb +140 -0
  33. data/spec/fin/models/instrument_spec.rb +54 -0
  34. data/spec/fin/models/model_spec.rb +109 -0
  35. data/spec/fin/models/money_limit_spec.rb +143 -0
  36. data/spec/fin/models/order_spec.rb +67 -0
  37. data/spec/fin/models/position_spec.rb +74 -0
  38. data/spec/fin/models/shared_examples.rb +5 -0
  39. data/spec/fin/order_list_spec.rb +140 -0
  40. data/spec/fin/shared_examples.rb +355 -0
  41. data/spec/spec_helper.rb +17 -0
  42. data/tasks/common.rake +18 -0
  43. data/tasks/doc.rake +14 -0
  44. data/tasks/gem.rake +40 -0
  45. data/tasks/git.rake +34 -0
  46. data/tasks/spec.rake +16 -0
  47. data/tasks/version.rake +71 -0
  48. metadata +155 -0
@@ -0,0 +1,26 @@
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
+ config
19
+ rdoc
20
+ pkg
21
+ log
22
+ tmp
23
+ .idea
24
+ .bundle
25
+
26
+ ## PROJECT::SPECIFIC
data/HISTORY ADDED
@@ -0,0 +1,27 @@
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
12
+
13
+ == 0.0.3 / 2011-03-19
14
+
15
+ * Feature-parity with legacy code
16
+
17
+ == 0.0.4 / 2011-03-21
18
+
19
+ * Item#to_s added
20
+
21
+ == 0.0.5 / 2011-03-21
22
+
23
+ * Iteration-safety added
24
+
25
+ == 0.1.0 / 2011-04-10
26
+
27
+ * Namespace renamed to Fin
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.
@@ -0,0 +1,36 @@
1
+ = fin
2
+ by:: Arvicco
3
+ url:: http://github.com/arvicco/fin
4
+
5
+ == DESCRIPTION:
6
+
7
+ Domain models to represent Financial/DataFeed entities and basic data structures used
8
+ to store and access them. Initial project scope is only limited to representation of
9
+ RTS Plaza2 domain models. Next step will be generalization of domain models to encompass
10
+ other markets and other data feed types.
11
+
12
+ == FEATURES/PROBLEMS:
13
+
14
+ Domain models represent distinct individual entities that appear in market data feeds
15
+ (such as Quote, Order, Deal, Instrument, Position and whatnot). Intention is to keep
16
+ model API very similar to ActiveModel, with a goal of full ActiveModel compatibility
17
+ in the near future.
18
+
19
+ Enclosed data structures (Lists and such) are effectively containers for domain objects.
20
+ They are used to accumulate, analyse and visualize sets of domain objects, received from
21
+ market data feeds (such as RTS Plaza2 replication streams). These containers are required
22
+ by client and gateway components (data adapters) that deal with actual market data feeds
23
+ (DataStreams). In addition, they may be used downstream by intermediary and endpoint
24
+ data analysers for storage and retrieval of domain objects passing through them.
25
+
26
+ Ideally, container data structures need to be:
27
+ 1) memory-efficient
28
+ 2) thread-safe (without too much synchronization penalty)
29
+ 3) iteration-safe (adding new element while iterating should not raise exception)
30
+
31
+ == INSTALL:
32
+
33
+ $ sudo gem install fin
34
+
35
+ == LICENSE:
36
+ Copyright (c) 2011 Arvicco. See LICENSE for details.
@@ -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 = 'fin'
20
+ CLASS_NAME = Fin
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.1.0
@@ -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
@@ -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)
@@ -0,0 +1,13 @@
1
+ require 'version'
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ Bundler.require(:default)
5
+
6
+ require 'fin/container_list'
7
+ require 'fin/order_list'
8
+ require 'fin/deal_list'
9
+ require 'fin/models/deal'
10
+ require 'fin/models/order'
11
+ require 'fin/models/instrument'
12
+ require 'fin/models/position'
13
+ require 'fin/models/money_limit'
@@ -0,0 +1,50 @@
1
+ require 'fin/container_list'
2
+
3
+ module Fin
4
+ # Represents Book (OrderBook, DealBook, etc...) for one security(isin)
5
+ # It is used as additional index by BookedList subclass (OrderList, DealList)
6
+ class Book < ContainerList
7
+
8
+ attr_reader :isin_id
9
+ alias isin isin_id
10
+
11
+ def initialize opts = {}
12
+ @isin_id = opts[:isin_id]
13
+ @book_index = opts[:book_index]
14
+ @book_condition = opts[:book_condition]
15
+ raise "No isin_id given for #{self}" unless @isin_id
16
+ super
17
+ end
18
+
19
+ # Validation of the item being included
20
+ def check item
21
+ if item.is_a?(@item_type) && item.isin_id == isin_id
22
+ @book_condition ? @book_condition.call(item) : true
23
+ else
24
+ false
25
+ end
26
+ end
27
+
28
+ def index item
29
+ if @book_index
30
+ @book_index.call(item)
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def add? item
37
+ if super
38
+ item.book = self
39
+ item
40
+ end
41
+ end
42
+
43
+ def remove? item
44
+ if super
45
+ item.book = nil
46
+ item
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ require 'fin/book'
2
+ require 'fin/container_list'
3
+
4
+ module Fin
5
+ # Adds to including List a set of @books, each related to a single security(isin).
6
+ # @books is effectively an additional index in a List, a set of containers for
7
+ # its items, grouped by item's isin_id.
8
+ # For example: OrderBook, DealBook
9
+ #
10
+ module BookManager
11
+
12
+ def books
13
+ @books ||= Hash.new do |hash, key|
14
+ hash[key] = Book.new :isin_id => key,
15
+ :item_type => @item_type,
16
+ :book_index => @book_index,
17
+ :book_condition => @book_condition
18
+ hash[key]
19
+ end
20
+ end
21
+
22
+ # Overwrites/removes existing item with the same index
23
+ def add? item
24
+ if check item
25
+ old_item = self[index item]
26
+ remove old_item if old_item # Remove old item with the same index(id)
27
+ if super
28
+ books[item.isin_id].add item # Add item to appropriate order book
29
+ item
30
+ end
31
+ end
32
+ end
33
+
34
+ def remove? item
35
+ if super
36
+ # Removing item from appropriate order book when it's deleted from order list
37
+ books[item.isin_id].remove item
38
+ item
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,49 @@
1
+ require 'fin/indexed_list'
2
+
3
+ module Fin
4
+ # Represents IndexedList that tracks its own changes (dirty-tracking),
5
+ # and updates (series of changes resulting in a consistent state)
6
+ class ChangedList < IndexedList
7
+
8
+ # Changed attribute is set automatically, whenever item is actually added
9
+ # or deleted from list (please note, change may leave data in inconsistent state!)
10
+ attr_accessor :changed
11
+
12
+ # Number of changes (successful item additions or removals)
13
+ attr_accessor :change_count
14
+
15
+ # Updated attribute should be set EXTERNALLY - only when data update
16
+ # transaction is completed, and list data is known to be consistent
17
+ # (e.g., when onStreamDataEnd event fires for DataStream)
18
+ attr_accessor :updated
19
+
20
+ def initialize
21
+ @updated = true
22
+ @changed = true
23
+ @change_count = 0
24
+ super
25
+ end
26
+
27
+ def add? item
28
+ if super
29
+ @changed = true # Mark List as changed
30
+ @change_count += 1
31
+ item
32
+ end
33
+ end
34
+
35
+ def remove? item
36
+ if super
37
+ @changed = true # Mark List as changed
38
+ @change_count += 1
39
+ item
40
+ end
41
+ end
42
+
43
+ # Observers inform list that it's recent changes are reflected
44
+ def update_noted
45
+ @updated = false
46
+ @changed = false
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,33 @@
1
+ require 'fin/changed_list'
2
+
3
+ module Fin
4
+ # Represents Container that holds Model objects (items) of only ONE specific type
5
+ # TODO: In future, merge ChangedList and ContainerList to flatten class hierarchy
6
+ class ContainerList < ChangedList
7
+
8
+ attr_reader :item_type
9
+
10
+ def initialize opts = {}
11
+ @item_type = opts[:item_type]
12
+ raise "Item type not given for #{self}" unless @item_type
13
+ super()
14
+ end
15
+
16
+ def check item
17
+ item.is_a?(@item_type) && item.index
18
+ end
19
+
20
+ def index item
21
+ item.index if check item
22
+ end
23
+
24
+ def add_record rec
25
+ add? @item_type.from_record(rec)
26
+ end
27
+
28
+ def remove_record rec, id
29
+ index = @item_type.index_for rec
30
+ remove? self[index]
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ require 'fin/models/deal'
2
+ require 'fin/book_manager'
3
+
4
+ module Fin
5
+ # Represents list of ALL Orders, indexed by id (replId)
6
+ # Its @books is a set of OrderBooks by isin. Each OrderBook lists Orders by price.
7
+ class DealList < ContainerList
8
+
9
+ include BookManager
10
+
11
+ def initialize
12
+ super :item_type => Fin::Deal
13
+ @book_index = proc { |item| item.deal_id }
14
+ end
15
+
16
+ end
17
+ end
18
+
@@ -0,0 +1,74 @@
1
+ module Fin
2
+ # Abstract (equivalent of SortedList)
3
+ # ������� ����� "������������� ������"
4
+ class IndexedList < Hash
5
+
6
+ def initialize
7
+ @iteration_mutex = Mutex.new
8
+ super
9
+ end
10
+
11
+ # Returns default list index for items
12
+ def index item
13
+ item.object_id
14
+ end
15
+
16
+ # Determines if item is worthy to be included in the list
17
+ def check item
18
+ true
19
+ end
20
+
21
+ # Adds new item to the list if it passes check
22
+ # (replaces item with the same index)
23
+ def add? item
24
+ # Checks that the item given looks like proper item first
25
+ self[index item] = item if check item
26
+ end
27
+
28
+ # Adds new item to the list, returning self for easy chaining
29
+ def add item
30
+ add? item
31
+ self
32
+ end
33
+
34
+ alias << add
35
+
36
+ # Removes item from the list, returns nil if nothing removed
37
+ def remove? item
38
+ # Checks that the item given looks like proper item first
39
+ delete(index(item)) if check item
40
+ end
41
+
42
+ # Removes item from the list
43
+ def remove item
44
+ remove? item
45
+ self
46
+ end
47
+
48
+ # Removes item with given index from the list
49
+ def delete_by_index index
50
+ remove self[index] if self[index]
51
+ end
52
+
53
+ # Removes either all items, or items for which given block returns trueish value
54
+ def clear
55
+ if block_given?
56
+ each { |item| remove item if yield item }
57
+ else
58
+ each { |item| remove item }
59
+ end
60
+ end
61
+
62
+ # Yields list items (but NOT keys!) in order of their index
63
+ def each
64
+ if block_given?
65
+ keys.sort.each { |key| yield self[key] }
66
+ else
67
+ keys.sort.map { |key| self[key] }
68
+ end
69
+ end
70
+
71
+ # Make direct setter private
72
+ private :[]=
73
+ end
74
+ end