ib-extensions 1.0

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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +6 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +9 -0
  7. data/Gemfile.lock +112 -0
  8. data/Guardfile +24 -0
  9. data/README.md +99 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +96 -0
  12. data/bin/console.yml +3 -0
  13. data/bin/gateway.rb +97 -0
  14. data/bin/setup +8 -0
  15. data/changelog.md +31 -0
  16. data/examples/cancel_orders +74 -0
  17. data/examples/eod +35 -0
  18. data/examples/input.rb +475 -0
  19. data/examples/market_price +57 -0
  20. data/examples/option_chain +67 -0
  21. data/examples/place_and_modify_order +162 -0
  22. data/examples/place_bracket_order +62 -0
  23. data/examples/place_butterfly_order +104 -0
  24. data/examples/place_combo_order +70 -0
  25. data/examples/place_limit_order +82 -0
  26. data/examples/place_the_limit_order +145 -0
  27. data/examples/volatility_research +139 -0
  28. data/examples/what_if_order +90 -0
  29. data/ib-extensions.gemspec +37 -0
  30. data/lib/ib-gateway.rb +5 -0
  31. data/lib/ib/alerts/base-alert.rb +128 -0
  32. data/lib/ib/alerts/gateway-alerts.rb +15 -0
  33. data/lib/ib/alerts/order-alerts.rb +68 -0
  34. data/lib/ib/eod.rb +152 -0
  35. data/lib/ib/extensions.rb +9 -0
  36. data/lib/ib/extensions/contract.rb +37 -0
  37. data/lib/ib/extensions/version.rb +5 -0
  38. data/lib/ib/flex.rb +150 -0
  39. data/lib/ib/gateway.rb +425 -0
  40. data/lib/ib/gateway/account-infos.rb +115 -0
  41. data/lib/ib/gateway/order-handling.rb +150 -0
  42. data/lib/ib/market-price.rb +134 -0
  43. data/lib/ib/models/account.rb +329 -0
  44. data/lib/ib/models/spread.rb +159 -0
  45. data/lib/ib/option-chain.rb +198 -0
  46. data/lib/ib/option-greeks.rb +88 -0
  47. data/lib/ib/order-prototypes.rb +110 -0
  48. data/lib/ib/order_prototypes/abstract.rb +67 -0
  49. data/lib/ib/order_prototypes/combo.rb +46 -0
  50. data/lib/ib/order_prototypes/forex.rb +40 -0
  51. data/lib/ib/order_prototypes/limit.rb +177 -0
  52. data/lib/ib/order_prototypes/market.rb +116 -0
  53. data/lib/ib/order_prototypes/pegged.rb +173 -0
  54. data/lib/ib/order_prototypes/premarket.rb +31 -0
  55. data/lib/ib/order_prototypes/stop.rb +202 -0
  56. data/lib/ib/order_prototypes/volatility.rb +39 -0
  57. data/lib/ib/spread-prototypes.rb +62 -0
  58. data/lib/ib/spread_prototypes/butterfly.rb +79 -0
  59. data/lib/ib/spread_prototypes/calendar.rb +85 -0
  60. data/lib/ib/spread_prototypes/stock-spread.rb +48 -0
  61. data/lib/ib/spread_prototypes/straddle.rb +75 -0
  62. data/lib/ib/spread_prototypes/strangle.rb +96 -0
  63. data/lib/ib/spread_prototypes/vertical.rb +84 -0
  64. data/lib/ib/verify.rb +226 -0
  65. metadata +206 -0
@@ -0,0 +1,226 @@
1
+ module IB
2
+ # define a custom ErrorClass which can be fired if a verification fails
3
+ class VerifyError < StandardError
4
+ end
5
+
6
+ class Contract
7
+
8
+
9
+ # IB::Contract#Verify
10
+
11
+ # verifies the contract
12
+ #
13
+ # returns the number of contracts retured by the TWS.
14
+ #
15
+ #
16
+ # The method accepts a block. The queried contract-Object is assessible there.
17
+ # If multible contracts are specified, the block is executed with each of these contracts.
18
+ #
19
+ # Parameter: thread: (true/false)
20
+ #
21
+ # The verifiying-process ist time consuming. If multible contracts are to be verified,
22
+ # they can be queried simultaniously.
23
+ # IB::Symbols::W500.map{|c| c.verify(thread: true){ |vc| do_something }}.join
24
+ #
25
+ # A simple verification works as follows:
26
+ #
27
+ # s = IB::Stock.new symbol:"A"
28
+ # s --> <IB::Stock:0x007f3de81a4398
29
+ # @attributes= {"symbol"=>"A", "sec_type"=>"STK", "currency"=>"USD", "exchange"=>"SMART"}>
30
+ # s.verify --> 1
31
+ # # s is unchanged !
32
+ #
33
+ # s.verify{ |c| puts c.inspect }
34
+ # --> <IB::Stock:0x007f3de81a4398
35
+ # @attributes={"symbol"=>"A", "updated_at"=>2015-04-17 19:20:00 +0200,
36
+ # "sec_type"=>"STK", "currency"=>"USD", "exchange"=>"SMART",
37
+ # "con_id"=>1715006, "expiry"=>"", "strike"=>0.0, "local_symbol"=>"A",
38
+ # "multiplier"=>0, "primary_exchange"=>"NYSE"},
39
+ # @contract_detail=#<IB::ContractDetail:0x007f3de81ed7c8
40
+ # @attributes={"market_name"=>"A", "trading_class"=>"A", "min_tick"=>0.01,
41
+ # "order_types"=>"ACTIVETIM, (...),WHATIF,",
42
+ # "valid_exchanges"=>"SMART,NYSE,CBOE,ISE,CHX,(...)PSX",
43
+ # "price_magnifier"=>1, "under_con_id"=>0,
44
+ # "long_name"=>"AGILENT TECHNOLOGIES INC", "contract_month"=>"",
45
+ # "industry"=>"Industrial", "category"=>"Electronics",
46
+ # "subcategory"=>"Electronic Measur Instr", "time_zone"=>"EST5EDT",
47
+ # "trading_hours"=>"20150417:0400-2000;20150420:0400-2000",
48
+ # "liquid_hours"=>"20150417:0930-1600;20150420:0930-1600",
49
+ # "ev_rule"=>0.0, "ev_multiplier"=>"", "sec_id_list"=>{},
50
+ # "updated_at"=>2015-04-17 19:20:00 +0200, "coupon"=>0.0,
51
+ # "callable"=>false, "puttable"=>false, "convertible"=>false,
52
+ # "next_option_partial"=>false}>>
53
+ #
54
+ #
55
+ def verify thread: nil, &b
56
+ return [self] if contract_detail.present? || sec_type == :bag
57
+ _verify update: false, thread: thread, &b # returns the allocated threads
58
+ end # def
59
+
60
+ # returns a hash
61
+ def nessesary_attributes
62
+
63
+ v= { stock: { currency: 'USD', exchange: 'SMART', symbol: nil} ,
64
+ option: { currency: 'USD', exchange: 'SMART', right: 'P', expiry: nil, strike: nil, symbol: nil} ,
65
+ future: { currency: 'USD', exchange: nil, expiry: nil, symbol: nil } ,
66
+ forex: { currency: 'USD', exchange: 'IDEALPRO', symbol: nil }
67
+ }
68
+ sec_type.present? ? v[sec_type] : { con_id: nil, exchange: 'SMART' } # enables to use only con_id for verifying
69
+ # if the contract allows SMART routing
70
+ end
71
+
72
+ # Verify that the contract is a valid IB::Contract, update the Contract-Object and return it.
73
+ #
74
+ # Returns nil if the contract could not be verified.
75
+ #
76
+ # > s = Stock.new symbol: 'AA'
77
+ # => #<IB::Stock:0x0000000002626cc0
78
+ # @attributes={:symbol=>"AA", :con_id=>0, :right=>"", :include_expired=>false,
79
+ # :sec_type=>"STK", :currency=>"USD", :exchange=>"SMART"}
80
+ # > sp = s.verify! &.essential
81
+ # => #<IB::Stock:0x00000000025a3cf8
82
+ # @attributes={:symbol=>"AA", :con_id=>251962528, :exchange=>"SMART", :currency=>"USD",
83
+ # :strike=>0.0, :local_symbol=>"AA", :multiplier=>0, :primary_exchange=>"NYSE",
84
+ # :trading_class=>"AA", :sec_type=>"STK", :right=>"", :include_expired=>false}
85
+ #
86
+ # > s = Stock.new symbol: 'invalid'
87
+ # => @attributes={:symbol=>"invalid", :sec_type=>"STK", :currency=>"USD", :exchange=>"SMART"}
88
+ # > sp = s.verify! &.essential
89
+ # => nil
90
+
91
+ def verify!
92
+ return self if contract_detail.present? || sec_type == :bag
93
+ c = 0
94
+ _verify( update: true){| response | c+=1 } # wait for the returned thread to finish
95
+ IB::Connection.logger.error { "Multible Contracts detected during verify!." } if c > 1
96
+ con_id.to_i < 0 || contract_detail.is_a?(ContractDetail) ? self : nil
97
+ end
98
+
99
+ # private
100
+
101
+ # Base method to verify a contract
102
+ #
103
+ # if :thread is given, the method subscribes to messages, fires the request and returns the thread, that
104
+ # receives the exit-condition-message
105
+ #
106
+ # otherwise the method waits until the response form tws is processed
107
+ #
108
+ #
109
+ # if :update is true, the attributes of the Contract itself are apdated
110
+ #
111
+ # otherwise the Contract is untouched
112
+ def _verify thread: nil , update:, &b # :nodoc:
113
+
114
+ ib = Connection.current
115
+ # we generate a Request-Message-ID on the fly
116
+ message_id = nil
117
+ # define local vars which are updated within the query-block
118
+ exitcondition, count , queried_contract, r = false, 0, nil, []
119
+
120
+ # currently the tws-request is suppressed for bags and if the contract_detail-record is present
121
+ tws_request_not_nessesary = bag? || contract_detail.is_a?( ContractDetail )
122
+
123
+ if tws_request_not_nessesary
124
+ yield self if block_given?
125
+ count = 1
126
+ else # subscribe to ib-messages and describe what to do
127
+ a = ib.subscribe(:Alert, :ContractData, :ContractDataEnd) do |msg|
128
+ case msg
129
+ when Messages::Incoming::Alert
130
+ if msg.code == 200 && msg.error_id == message_id
131
+ ib.logger.error { "Not a valid Contract :: #{self.to_human} " }
132
+ exitcondition = true
133
+ end
134
+ when Messages::Incoming::ContractData
135
+ if msg.request_id.to_i == message_id
136
+ # if multible contracts are present, all of them are assigned
137
+ # Only the last contract is saved in self; 'count' is incremented
138
+ count +=1
139
+ ## a specified block gets the contract_object on any uniq ContractData-Event
140
+ r << if block_given?
141
+ yield msg.contract
142
+ elsif count > 1
143
+ queried_contract = msg.contract # used by the logger (below) in case of mulible contracts
144
+ else
145
+ msg.contract
146
+ end
147
+ if update
148
+ self.attributes = msg.contract.attributes
149
+ self.contract_detail = msg.contract_detail unless msg.contract_detail.nil?
150
+ end
151
+ end
152
+ when Messages::Incoming::ContractDataEnd
153
+ exitcondition = true if msg.request_id.to_i == message_id
154
+
155
+ end # case
156
+ end # subscribe
157
+
158
+ ### send the request !
159
+ # contract_to_be_queried = con_id.present? ? self : query_contract
160
+ # if no con_id is present, the given attributes are checked by query_contract
161
+ # if contract_to_be_queried.present? # is nil if query_contract fails
162
+ message_id = ib.send_message :RequestContractData, :contract => query_contract
163
+
164
+ th = Thread.new do
165
+ begin
166
+ Timeout::timeout(1) do
167
+ loop{ break if exitcondition ; sleep 0.005 }
168
+ end
169
+ rescue Timeout::Error
170
+ Connection.logger.error{ "#{to_human} --> No ContractData recieved " }
171
+ end
172
+ ib.unsubscribe a
173
+ end
174
+ if thread.nil?
175
+ th.join # wait for the thread to finish
176
+ r # return array of contracts
177
+ else
178
+ th # return active thread
179
+ end
180
+ # else
181
+ # ib.logger.error { "Not a valid Contract-spezification, #{self.to_human}" }
182
+ end
183
+ # end
184
+ end
185
+
186
+ # Generates an IB::Contract with the required attributes to retrieve a unique contract from the TWS
187
+ #
188
+ # Background: If the tws is queried with a »complete« IB::Contract, it fails occacionally.
189
+ # So – even to update its contents, a defined subset of query-parameters has to be used.
190
+ #
191
+ # The required data-fields are stored in a yaml-file and fetched by #YmlFile.
192
+ #
193
+ # If `con_id` is present, only `con_id` and `exchange` are transmitted to the tws.
194
+ # Otherwise a IB::Stock, IB::Option, IB::Future or IB::Forex-Object with necessary attributes
195
+ # to query the tws is build (and returned)
196
+ #
197
+ # If Attributes are missing, an IB::VerifyError is fired,
198
+ # This can be trapped with
199
+ # rescue IB::VerifyError do ...
200
+
201
+ def query_contract( invalid_record: true ) # :nodoc:
202
+ # don't raise a verify error at this time. Contract.new con_id= xxxx, currency = 'xyz' is also valid
203
+ ## raise VerifyError, "Querying Contract faild: Invalid Security Type" unless SECURITY_TYPES.values.include? sec_type
204
+
205
+ ## the yml contains symbol-entries
206
+ ## these are converted to capitalized strings
207
+ items_as_string = ->(i){i.map{|x,y| x.to_s.capitalize}.join(', ')}
208
+ ## here we read the corresponding attributes of the specified contract
209
+ item_values = ->(i){ i.map{|x,y| self.send(x).presence || y }}
210
+ ## and finally we create a attribute-hash to instantiate a new Contract
211
+ ## to_h is present only after ruby 2.1.0
212
+ item_attributehash = ->(i){ i.keys.zip(item_values[i]).to_h }
213
+ ## now lets proceed, but only if no con_id is present
214
+ if con_id.blank? || con_id.zero?
215
+ # if item_values[nessesary_attributes].any?( &:nil? )
216
+ # raise VerifyError, "#{items_as_string[nessesary_attributes]} are needed to retrieve Contract,
217
+ # got: #{item_values[nessesary_attributes].join(',')}"
218
+ # end
219
+ # Contract.build item_attributehash[nessesary_items].merge(:sec_type=> sec_type) # return this
220
+ Contract.build self.attributes # return this
221
+ else # its always possible, to retrieve a Contract if con_id and exchange or are present
222
+ Contract.new con_id: con_id , :exchange => exchange.presence || item_attributehash[nessesary_attributes][:exchange].presence || 'SMART' # return this
223
+ end # if
224
+ end # def
225
+ end # class
226
+ end #module
metadata ADDED
@@ -0,0 +1,206 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ib-extensions
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Hartmut Bischoff
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ox
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-collection_matchers
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-its
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description:
112
+ email:
113
+ - topofocus@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rspec"
120
+ - ".travis.yml"
121
+ - CODE_OF_CONDUCT.md
122
+ - Gemfile
123
+ - Gemfile.lock
124
+ - Guardfile
125
+ - README.md
126
+ - Rakefile
127
+ - bin/console
128
+ - bin/console.yml
129
+ - bin/gateway.rb
130
+ - bin/setup
131
+ - changelog.md
132
+ - examples/cancel_orders
133
+ - examples/eod
134
+ - examples/input.rb
135
+ - examples/market_price
136
+ - examples/option_chain
137
+ - examples/place_and_modify_order
138
+ - examples/place_bracket_order
139
+ - examples/place_butterfly_order
140
+ - examples/place_combo_order
141
+ - examples/place_limit_order
142
+ - examples/place_the_limit_order
143
+ - examples/volatility_research
144
+ - examples/what_if_order
145
+ - ib-extensions.gemspec
146
+ - lib/ib-gateway.rb
147
+ - lib/ib/alerts/base-alert.rb
148
+ - lib/ib/alerts/gateway-alerts.rb
149
+ - lib/ib/alerts/order-alerts.rb
150
+ - lib/ib/eod.rb
151
+ - lib/ib/extensions.rb
152
+ - lib/ib/extensions/contract.rb
153
+ - lib/ib/extensions/version.rb
154
+ - lib/ib/flex.rb
155
+ - lib/ib/gateway.rb
156
+ - lib/ib/gateway/account-infos.rb
157
+ - lib/ib/gateway/order-handling.rb
158
+ - lib/ib/market-price.rb
159
+ - lib/ib/models/account.rb
160
+ - lib/ib/models/spread.rb
161
+ - lib/ib/option-chain.rb
162
+ - lib/ib/option-greeks.rb
163
+ - lib/ib/order-prototypes.rb
164
+ - lib/ib/order_prototypes/abstract.rb
165
+ - lib/ib/order_prototypes/combo.rb
166
+ - lib/ib/order_prototypes/forex.rb
167
+ - lib/ib/order_prototypes/limit.rb
168
+ - lib/ib/order_prototypes/market.rb
169
+ - lib/ib/order_prototypes/pegged.rb
170
+ - lib/ib/order_prototypes/premarket.rb
171
+ - lib/ib/order_prototypes/stop.rb
172
+ - lib/ib/order_prototypes/volatility.rb
173
+ - lib/ib/spread-prototypes.rb
174
+ - lib/ib/spread_prototypes/butterfly.rb
175
+ - lib/ib/spread_prototypes/calendar.rb
176
+ - lib/ib/spread_prototypes/stock-spread.rb
177
+ - lib/ib/spread_prototypes/straddle.rb
178
+ - lib/ib/spread_prototypes/strangle.rb
179
+ - lib/ib/spread_prototypes/vertical.rb
180
+ - lib/ib/verify.rb
181
+ homepage: https://ib-ruby.github.io/ib-doc/
182
+ licenses: []
183
+ metadata:
184
+ homepage_uri: https://ib-ruby.github.io/ib-doc/
185
+ source_code_uri: https://github.cm/ib-ruby/ib-extensions
186
+ changelog_uri: https://github.cm/ib-ruby/ib-extensions/changelog.md
187
+ post_install_message:
188
+ rdoc_options: []
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: 2.6.0
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ requirements: []
202
+ rubygems_version: 3.0.4
203
+ signing_key:
204
+ specification_version: 4
205
+ summary: Part of IB-Ruby. Tools to to access the tws-api comfortably.
206
+ test_files: []