ib_ruby_proxy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +77 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +143 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +7 -0
  8. data/Gemfile +10 -0
  9. data/Gemfile.lock +74 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +130 -0
  12. data/Rakefile +12 -0
  13. data/bin/console +14 -0
  14. data/bin/generate_ruby_classes +13 -0
  15. data/bin/ibproxy +32 -0
  16. data/bin/setup +8 -0
  17. data/docs/diagrams.key +0 -0
  18. data/docs/images/architecture.png +0 -0
  19. data/examples/common.rb +14 -0
  20. data/examples/plain_req_historical_ticks.rb +19 -0
  21. data/examples/req_contract_details.rb +9 -0
  22. data/examples/req_historical_bars_data.rb +10 -0
  23. data/examples/req_historical_ticks.rb +10 -0
  24. data/examples/req_tick_by_tick_data.rb +9 -0
  25. data/ib_ruby_proxy.gemspec +43 -0
  26. data/lib/ib_ruby_proxy.rb +35 -0
  27. data/lib/ib_ruby_proxy/client/callbacks_response_handler.rb +135 -0
  28. data/lib/ib_ruby_proxy/client/client.rb +69 -0
  29. data/lib/ib_ruby_proxy/client/ib/bar.rb +36 -0
  30. data/lib/ib_ruby_proxy/client/ib/combo_leg.rb +36 -0
  31. data/lib/ib_ruby_proxy/client/ib/contract.rb +56 -0
  32. data/lib/ib_ruby_proxy/client/ib/contract_details.rb +100 -0
  33. data/lib/ib_ruby_proxy/client/ib/delta_neutral_contract.rb +26 -0
  34. data/lib/ib_ruby_proxy/client/ib/historical_tick.rb +26 -0
  35. data/lib/ib_ruby_proxy/client/ib/historical_tick_bid_ask.rb +32 -0
  36. data/lib/ib_ruby_proxy/client/ib/historical_tick_last.rb +32 -0
  37. data/lib/ib_ruby_proxy/client/ib/order.rb +262 -0
  38. data/lib/ib_ruby_proxy/client/ib/tick_attrib_bid_ask.rb +24 -0
  39. data/lib/ib_ruby_proxy/client/ib/tick_attrib_last.rb +24 -0
  40. data/lib/ib_ruby_proxy/client/ib_callbacks_observer.rb +25 -0
  41. data/lib/ib_ruby_proxy/config.yml +43 -0
  42. data/lib/ib_ruby_proxy/server/ext/array.rb +22 -0
  43. data/lib/ib_ruby_proxy/server/ext/enum.rb +20 -0
  44. data/lib/ib_ruby_proxy/server/ext/idempotent_types.rb +23 -0
  45. data/lib/ib_ruby_proxy/server/ib/bar.rb +21 -0
  46. data/lib/ib_ruby_proxy/server/ib/combo_leg.rb +21 -0
  47. data/lib/ib_ruby_proxy/server/ib/contract.rb +31 -0
  48. data/lib/ib_ruby_proxy/server/ib/contract_details.rb +53 -0
  49. data/lib/ib_ruby_proxy/server/ib/delta_neutral_contract.rb +16 -0
  50. data/lib/ib_ruby_proxy/server/ib/historical_tick.rb +16 -0
  51. data/lib/ib_ruby_proxy/server/ib/historical_tick_bid_ask.rb +19 -0
  52. data/lib/ib_ruby_proxy/server/ib/historical_tick_last.rb +19 -0
  53. data/lib/ib_ruby_proxy/server/ib/order.rb +134 -0
  54. data/lib/ib_ruby_proxy/server/ib/tick_attrib_bid_ask.rb +15 -0
  55. data/lib/ib_ruby_proxy/server/ib/tick_attrib_last.rb +15 -0
  56. data/lib/ib_ruby_proxy/server/ib_client_adapter.rb +51 -0
  57. data/lib/ib_ruby_proxy/server/ib_proxy_service.rb +85 -0
  58. data/lib/ib_ruby_proxy/server/ib_ruby_class_files_generator.rb +77 -0
  59. data/lib/ib_ruby_proxy/server/ib_ruby_class_source_generator.rb +155 -0
  60. data/lib/ib_ruby_proxy/server/ib_wrapper_adapter.rb +47 -0
  61. data/lib/ib_ruby_proxy/server/reflection/ib_class.rb +62 -0
  62. data/lib/ib_ruby_proxy/server/reflection/ib_field.rb +60 -0
  63. data/lib/ib_ruby_proxy/util/has_logger.rb +10 -0
  64. data/lib/ib_ruby_proxy/util/string_utils.rb +29 -0
  65. data/lib/ib_ruby_proxy/version.rb +3 -0
  66. data/lib/server.rb +4 -0
  67. data/sandbox/drb_performance/client.rb +46 -0
  68. data/sandbox/drb_performance/server.rb +26 -0
  69. data/vendor/TwsApi.jar +0 -0
  70. metadata +226 -0
@@ -0,0 +1,62 @@
1
+ module IbRubyProxy
2
+ module Server
3
+ module Reflection
4
+ # An ib class
5
+ class IbClass
6
+ include IbRubyProxy::Util::StringUtils
7
+
8
+ attr_reader :klass
9
+
10
+ # @param [Class] klass
11
+ def initialize(klass)
12
+ @klass = klass
13
+ end
14
+
15
+ # The class name without including namespaces
16
+ #
17
+ # @return [String]
18
+ def name
19
+ klass.name.split('::').last
20
+ end
21
+
22
+ # The full qualified class name including namespace
23
+ #
24
+ # @return [Object]
25
+ def full_name
26
+ klass.name
27
+ end
28
+
29
+ # List of ib fields that represent properties to interchange
30
+ #
31
+ # @return [Array<IbField>]
32
+ def java_property_fields
33
+ @java_property_fields ||= java_fields.collect { |field| IbField.new(field, self) }
34
+ end
35
+
36
+ # List of ruby properties names that correspond to {#java_property_fields}
37
+ #
38
+ # @return [Array<String>]
39
+ def ruby_property_names
40
+ @ruby_properties ||= java_property_fields.collect do |field|
41
+ to_underscore(field.name)
42
+ end
43
+ end
44
+
45
+ # Return an array of combinations of {#ruby_property_names} and #{java_property_fields}
46
+ #
47
+ # @return [Array<Array<String, IbField>>]
48
+ def zipped_ruby_and_java_properties
49
+ ruby_property_names.zip(java_property_fields)
50
+ end
51
+
52
+ private
53
+
54
+ def java_fields
55
+ @java_property_fields ||= klass.java_class.declared_fields.find_all do |field|
56
+ field.name =~ IbField::IB_FIELD_PREFIX
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,60 @@
1
+ module IbRubyProxy
2
+ module Server
3
+ module Reflection
4
+ # An {IbClass} field
5
+ class IbField
6
+ IB_FIELD_PREFIX = /^m_/.freeze
7
+
8
+ attr_reader :java_field, :ib_class
9
+
10
+ def initialize(java_field, ib_class)
11
+ @java_field = java_field
12
+ @ib_class = ib_class
13
+ end
14
+
15
+ # Default value for the field
16
+ #
17
+ # @return [Object]
18
+ def default_value
19
+ case java_field.type
20
+ when Java::int.java_class, Java::float.java_class, Java::double.java_class
21
+ 0
22
+ when Java::boolean.java_class
23
+ false
24
+ end
25
+ end
26
+
27
+ # {#default_value Default value} as a string
28
+ #
29
+ # @return [String]
30
+ def default_value_as_string
31
+ value = default_value
32
+ if value.nil?
33
+ 'nil'
34
+ else
35
+ value.to_s
36
+ end
37
+ end
38
+
39
+ # Return the name of the accessor method used to access the field
40
+ #
41
+ # @return [String]
42
+ def name
43
+ @name ||= find_name
44
+ end
45
+
46
+ private
47
+
48
+ def find_name
49
+ field_name_without_prefix = java_field.name.gsub(IB_FIELD_PREFIX, '')
50
+ matched_method = ib_class.klass.java_class.declared_instance_methods.find do |method|
51
+ method.name.downcase == field_name_without_prefix.downcase
52
+ end
53
+ raise "No method matching '#{field.name}'?" unless matched_method
54
+
55
+ matched_method.name
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,10 @@
1
+ module IbRubyProxy
2
+ module Util
3
+ # Mixin to add access to the gem logger
4
+ module HasLogger
5
+ def logger
6
+ @logger ||= IbRubyProxy.logger
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ module IbRubyProxy
2
+ module Util
3
+ # String utility methods
4
+ module StringUtils
5
+ extend self
6
+
7
+ # Makes passed string underscored and lowercase
8
+ #
9
+ # @param [String] string
10
+ #
11
+ # Implementation copied from Rails
12
+ # @see https://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-underscore
13
+ def to_underscore(string)
14
+ string.gsub(/::/, '/')
15
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
16
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
17
+ .tr('-', '_')
18
+ .downcase
19
+ end
20
+
21
+ # Converts passed string into camel case syntax
22
+ #
23
+ # @see https://stackoverflow.com/a/11411200/469697
24
+ def to_camel_case(string)
25
+ string.split('_').inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module IbRubyProxy
2
+ VERSION = '0.0.1'.freeze
3
+ end
@@ -0,0 +1,4 @@
1
+ require 'ib_ruby_proxy/version'
2
+ require_relative '../vendor/TwsApi.jar'
3
+
4
+ Dir["#{__dir__}/ib_ruby_proxy/server/**/*.rb"].each { |file| require file }
@@ -0,0 +1,46 @@
1
+ require 'drb'
2
+ require 'benchmark'
3
+
4
+ # This is a dummy performance test to have an idea of drb throughput. I got it's possible to
5
+ # process 10000 notifications per second with MRI ruby 2.5, which should be enough for real
6
+ # time tick data.
7
+ class ResultCallback
8
+ include DRbUndumped
9
+
10
+ attr_reader :total
11
+
12
+ def initialize
13
+ @total = 0
14
+ end
15
+
16
+ def update(_number1, _number2, result)
17
+ @total += result
18
+ end
19
+ end
20
+
21
+ @server = DRbObject.new(nil, 'druby://localhost:1992')
22
+ DRb.start_service
23
+
24
+ result_callback = ResultCallback.new
25
+ @server.add_observer(result_callback)
26
+
27
+ LOOP_COUNT = 10000
28
+
29
+ drb_benchmark = Benchmark.measure do
30
+ LOOP_COUNT.times do |i|
31
+ @server.add(i, i + 1)
32
+ end
33
+ end
34
+
35
+ total = 0
36
+ ruby_benchmark = Benchmark.measure do
37
+ LOOP_COUNT.times do |i|
38
+ total += (i + (i + 1))
39
+ end
40
+ end
41
+
42
+ puts "With drb: #{result_callback.total}"
43
+ puts drb_benchmark
44
+
45
+ puts "With plain ruby: #{total}"
46
+ puts ruby_benchmark
@@ -0,0 +1,26 @@
1
+ require 'drb'
2
+ require 'drb/observer'
3
+
4
+ class Server
5
+ include DRb::DRbObservable
6
+ attr_accessor :object
7
+
8
+ def initialize
9
+ @object = { id: 'from server side' }
10
+ end
11
+
12
+ def add(numnber1, number2)
13
+ changed
14
+ notify_observers(numnber1, number2, numnber1 + number2)
15
+ end
16
+ end
17
+
18
+ server = Server.new
19
+
20
+ DRb.start_service('druby://localhost:1992', server)
21
+
22
+ begin
23
+ DRb.thread.join
24
+ rescue StandardError
25
+ Process.kill('TERM', Process.pid)
26
+ end
Binary file
metadata ADDED
@@ -0,0 +1,226 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ib_ruby_proxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jorge Manrubia
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ name: awesome_print
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ name: commander
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: concurrent-ruby
48
+ prerelease: false
49
+ type: :runtime
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 2.0.1
61
+ name: bundler
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 2.0.1
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ name: impersonator
76
+ prerelease: false
77
+ type: :development
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ name: rake
90
+ prerelease: false
91
+ type: :development
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 3.8.0
103
+ name: rspec
104
+ prerelease: false
105
+ type: :development
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 3.8.0
111
+ - !ruby/object:Gem::Dependency
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ name: rspec_junit_formatter
118
+ prerelease: false
119
+ type: :development
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Invoke IB Java API from Ruby
126
+ email:
127
+ - jorge.manrubia@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".circleci/config.yml"
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".rubocop.yml"
136
+ - ".ruby-version"
137
+ - ".travis.yml"
138
+ - Gemfile
139
+ - Gemfile.lock
140
+ - LICENSE.txt
141
+ - README.md
142
+ - Rakefile
143
+ - bin/console
144
+ - bin/generate_ruby_classes
145
+ - bin/ibproxy
146
+ - bin/setup
147
+ - docs/diagrams.key
148
+ - docs/images/architecture.png
149
+ - examples/common.rb
150
+ - examples/plain_req_historical_ticks.rb
151
+ - examples/req_contract_details.rb
152
+ - examples/req_historical_bars_data.rb
153
+ - examples/req_historical_ticks.rb
154
+ - examples/req_tick_by_tick_data.rb
155
+ - ib_ruby_proxy.gemspec
156
+ - lib/ib_ruby_proxy.rb
157
+ - lib/ib_ruby_proxy/client/callbacks_response_handler.rb
158
+ - lib/ib_ruby_proxy/client/client.rb
159
+ - lib/ib_ruby_proxy/client/ib/bar.rb
160
+ - lib/ib_ruby_proxy/client/ib/combo_leg.rb
161
+ - lib/ib_ruby_proxy/client/ib/contract.rb
162
+ - lib/ib_ruby_proxy/client/ib/contract_details.rb
163
+ - lib/ib_ruby_proxy/client/ib/delta_neutral_contract.rb
164
+ - lib/ib_ruby_proxy/client/ib/historical_tick.rb
165
+ - lib/ib_ruby_proxy/client/ib/historical_tick_bid_ask.rb
166
+ - lib/ib_ruby_proxy/client/ib/historical_tick_last.rb
167
+ - lib/ib_ruby_proxy/client/ib/order.rb
168
+ - lib/ib_ruby_proxy/client/ib/tick_attrib_bid_ask.rb
169
+ - lib/ib_ruby_proxy/client/ib/tick_attrib_last.rb
170
+ - lib/ib_ruby_proxy/client/ib_callbacks_observer.rb
171
+ - lib/ib_ruby_proxy/config.yml
172
+ - lib/ib_ruby_proxy/server/ext/array.rb
173
+ - lib/ib_ruby_proxy/server/ext/enum.rb
174
+ - lib/ib_ruby_proxy/server/ext/idempotent_types.rb
175
+ - lib/ib_ruby_proxy/server/ib/bar.rb
176
+ - lib/ib_ruby_proxy/server/ib/combo_leg.rb
177
+ - lib/ib_ruby_proxy/server/ib/contract.rb
178
+ - lib/ib_ruby_proxy/server/ib/contract_details.rb
179
+ - lib/ib_ruby_proxy/server/ib/delta_neutral_contract.rb
180
+ - lib/ib_ruby_proxy/server/ib/historical_tick.rb
181
+ - lib/ib_ruby_proxy/server/ib/historical_tick_bid_ask.rb
182
+ - lib/ib_ruby_proxy/server/ib/historical_tick_last.rb
183
+ - lib/ib_ruby_proxy/server/ib/order.rb
184
+ - lib/ib_ruby_proxy/server/ib/tick_attrib_bid_ask.rb
185
+ - lib/ib_ruby_proxy/server/ib/tick_attrib_last.rb
186
+ - lib/ib_ruby_proxy/server/ib_client_adapter.rb
187
+ - lib/ib_ruby_proxy/server/ib_proxy_service.rb
188
+ - lib/ib_ruby_proxy/server/ib_ruby_class_files_generator.rb
189
+ - lib/ib_ruby_proxy/server/ib_ruby_class_source_generator.rb
190
+ - lib/ib_ruby_proxy/server/ib_wrapper_adapter.rb
191
+ - lib/ib_ruby_proxy/server/reflection/ib_class.rb
192
+ - lib/ib_ruby_proxy/server/reflection/ib_field.rb
193
+ - lib/ib_ruby_proxy/util/has_logger.rb
194
+ - lib/ib_ruby_proxy/util/string_utils.rb
195
+ - lib/ib_ruby_proxy/version.rb
196
+ - lib/server.rb
197
+ - sandbox/drb_performance/client.rb
198
+ - sandbox/drb_performance/server.rb
199
+ - vendor/TwsApi.jar
200
+ homepage: https://github.com/jorgemanrubia/ib_ruby_proxy
201
+ licenses:
202
+ - MIT
203
+ metadata:
204
+ homepage_uri: https://github.com/jorgemanrubia/ib_ruby_proxy
205
+ source_code_uri: https://github.com/jorgemanrubia/ib_ruby_proxy
206
+ post_install_message:
207
+ rdoc_options: []
208
+ require_paths:
209
+ - lib
210
+ required_ruby_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ required_rubygems_version: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ version: '0'
220
+ requirements: []
221
+ rubyforge_project:
222
+ rubygems_version: 2.7.9
223
+ signing_key:
224
+ specification_version: 4
225
+ summary: Invoke IB Java API from Ruby
226
+ test_files: []