ib-extensions 1.1 → 1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -3
- data/Gemfile.lock +26 -26
- data/README.md +56 -10
- data/bin/console +10 -3
- data/bin/gateway +14 -9
- data/changelog.md +54 -0
- data/ib-extensions.gemspec +6 -4
- data/lib/ib/alerts/base-alert.rb +10 -13
- data/lib/ib/eod.rb +254 -125
- data/lib/ib/extensions/contract.rb +2 -30
- data/lib/ib/extensions/version.rb +1 -1
- data/lib/ib/extensions.rb +5 -0
- data/lib/ib/gateway/account-infos.rb +74 -47
- data/lib/ib/gateway/order-handling.rb +57 -25
- data/lib/ib/gateway.rb +45 -31
- data/lib/ib/market-price.rb +108 -97
- data/lib/ib/models/account.rb +178 -145
- data/lib/ib/models/bag.rb +19 -0
- data/lib/ib/models/contract.rb +16 -0
- data/lib/ib/models/future.rb +20 -0
- data/lib/ib/models/option.rb +20 -13
- data/lib/ib/option-chain.rb +36 -63
- data/lib/ib/option-greeks.rb +36 -33
- data/lib/ib/order_prototypes/all-in-one.rb +46 -0
- data/lib/ib/plot-poec.rb +60 -0
- data/lib/ib/probability_of_expiring.rb +109 -0
- data/lib/ib/spread-prototypes.rb +1 -0
- data/lib/ib/spread_prototypes/butterfly.rb +2 -4
- data/lib/ib/spread_prototypes/calendar.rb +25 -23
- data/lib/ib/spread_prototypes/straddle.rb +3 -3
- data/lib/ib/spread_prototypes/strangle.rb +8 -9
- data/lib/ib/spread_prototypes/vertical.rb +6 -7
- data/lib/ib/verify.rb +34 -39
- data/lib/ib-gateway.rb +12 -0
- metadata +53 -5
@@ -60,15 +60,14 @@ module IB
|
|
60
60
|
end
|
61
61
|
kind = { :p => fields.delete(:p), :c => fields.delete(:c) }
|
62
62
|
initialize_spread( underlying ) do | the_spread |
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
.merge( local_symbol: "" )
|
63
|
+
leg_prototype = IB::Option.new from.attributes
|
64
|
+
.slice( :currency, :symbol, :exchange)
|
65
|
+
.merge(defaults)
|
66
|
+
.merge( fields )
|
68
67
|
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
leg_prototype.sec_type = 'FOP' if underlying.is_a?(IB::Future)
|
69
|
+
the_spread.add_leg leg_prototype.merge( right: :put, strike: kind[:p] ).verify.first
|
70
|
+
the_spread.add_leg leg_prototype.merge( right: :call, strike: kind[:c] ).verify.first
|
72
71
|
error "Initialisation of Legs failed" if the_spread.legs.size != 2
|
73
72
|
the_spread.description = the_description( the_spread )
|
74
73
|
end
|
@@ -88,7 +87,7 @@ module IB
|
|
88
87
|
|
89
88
|
|
90
89
|
def the_description spread
|
91
|
-
|
90
|
+
"<Strangle #{spread.symbol}(#{spread.legs.map(&:strike).join(",")})[#{Date.parse(spread.legs.first.last_trading_day).strftime("%b %Y")}]>"
|
92
91
|
end
|
93
92
|
|
94
93
|
end # class
|
@@ -20,8 +20,8 @@ module IB
|
|
20
20
|
buy = master.strike if buy.zero?
|
21
21
|
sell = master.strike if sell.zero?
|
22
22
|
initialize_spread( master ) do | the_spread |
|
23
|
-
|
24
|
-
|
23
|
+
the_spread.add_leg master.merge(strike: sell).verify.first, action: :sell
|
24
|
+
the_spread.add_leg master.merge(strike: buy).verify.first, action: :buy
|
25
25
|
error "Initialisation of Legs failed" if the_spread.legs.size != 2
|
26
26
|
the_spread.description = the_description( the_spread )
|
27
27
|
end
|
@@ -54,16 +54,15 @@ module IB
|
|
54
54
|
from
|
55
55
|
end
|
56
56
|
kind = { :buy => fields.delete(:buy), :sell => fields.delete(:sell) }
|
57
|
-
error "
|
57
|
+
error "Specification of :buy and :sell necessary, got: #{kind.inspect}" if kind.values.any?(nil)
|
58
58
|
initialize_spread( underlying ) do | the_spread |
|
59
|
-
leg_prototype =
|
59
|
+
leg_prototype = Option.new underlying.attributes
|
60
60
|
.slice( :currency, :symbol, :exchange)
|
61
61
|
.merge(defaults)
|
62
62
|
.merge( fields )
|
63
|
-
.merge( local_symbol: "" )
|
64
63
|
leg_prototype.sec_type = 'FOP' if underlying.is_a?(IB::Future)
|
65
|
-
|
66
|
-
|
64
|
+
the_spread.add_leg leg_prototype.merge(strike: kind[:sell]).verify.first, action: :sell
|
65
|
+
the_spread.add_leg leg_prototype.merge(strike: kind[:buy] ).verify.first, action: :buy
|
67
66
|
error "Initialisation of Legs failed" if the_spread.legs.size != 2
|
68
67
|
the_spread.description = the_description( the_spread )
|
69
68
|
end
|
data/lib/ib/verify.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module IB
|
2
2
|
# define a custom ErrorClass which can be fired if a verification fails
|
3
|
-
|
3
|
+
class VerifyError < StandardError
|
4
|
+
|
5
|
+
end
|
4
6
|
# end
|
5
7
|
|
6
8
|
class Contract
|
@@ -49,12 +51,15 @@ module IB
|
|
49
51
|
# IB::Symbols::W500.map{|c| c.verify(thread: true){ |vc| do_something }}.join
|
50
52
|
|
51
53
|
def verify thread: nil, &b
|
52
|
-
|
53
|
-
|
54
|
+
if thread
|
55
|
+
Thread.new { _verify &b }
|
56
|
+
else
|
57
|
+
_verify &b
|
58
|
+
end
|
54
59
|
end # def
|
55
60
|
|
56
61
|
# returns a hash
|
57
|
-
def
|
62
|
+
def necessary_attributes
|
58
63
|
|
59
64
|
v= { stock: { currency: 'USD', exchange: 'SMART', symbol: nil},
|
60
65
|
option: { currency: 'USD', exchange: 'SMART', right: 'P', expiry: nil, strike: nil, symbol: nil},
|
@@ -70,8 +75,9 @@ module IB
|
|
70
75
|
def verify!
|
71
76
|
c = 0
|
72
77
|
IB::Connection.logger.warn "Contract.verify! is depreciated. Use \"contract = contract.verify.first\" instead"
|
73
|
-
|
74
|
-
|
78
|
+
c= verify.first
|
79
|
+
self.attributes = c.invariant_attributes
|
80
|
+
self.contract_detail = c.contract_detail
|
75
81
|
self
|
76
82
|
end
|
77
83
|
|
@@ -88,47 +94,43 @@ module IB
|
|
88
94
|
# if :update is true, the attributes of the Contract itself are adapted
|
89
95
|
#
|
90
96
|
# otherwise the Contract is untouched
|
91
|
-
def _verify
|
97
|
+
def _verify &b # :nodoc:
|
92
98
|
ib = Connection.current
|
99
|
+
error "No Connection" unless ib.is_a? Connection
|
93
100
|
# we generate a Request-Message-ID on the fly
|
94
|
-
|
101
|
+
error "Either con_id or sec_type have to be set", :verify if con_id.to_i.zero? && sec_type.blank?
|
95
102
|
# define local vars which are updated within the query-block
|
96
|
-
|
103
|
+
received_contracts = []
|
97
104
|
queue = Queue.new
|
98
|
-
|
105
|
+
message_id = nil
|
99
106
|
|
100
107
|
# a tws-request is suppressed for bags and if the contract_detail-record is present
|
101
|
-
|
108
|
+
tws_request_not_necessary = bag? || contract_detail.is_a?( ContractDetail )
|
102
109
|
|
103
|
-
if
|
110
|
+
if tws_request_not_necessary
|
104
111
|
yield self if block_given?
|
105
|
-
return self
|
112
|
+
return [self] # return an array!
|
106
113
|
else # subscribe to ib-messages and describe what to do
|
107
114
|
a = ib.subscribe(:Alert, :ContractData, :ContractDataEnd) do |msg|
|
108
115
|
case msg
|
109
116
|
when Messages::Incoming::Alert
|
117
|
+
## do not throw an error here, asynchronous operation!
|
118
|
+
## just notice failure in log and return nil instead of contract-object
|
110
119
|
if msg.code == 200 && msg.error_id == message_id
|
111
120
|
ib.logger.error { "Not a valid Contract :: #{self.to_human} " }
|
112
121
|
queue.close
|
113
122
|
end
|
114
123
|
when Messages::Incoming::ContractData
|
115
124
|
if msg.request_id.to_i == message_id
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
msg.contract
|
123
|
-
end
|
124
|
-
if update
|
125
|
-
self.attributes = msg.contract.attributes
|
126
|
-
self.contract_detail = msg.contract_detail unless msg.contract_detail.nil?
|
127
|
-
end
|
125
|
+
c = if block_given?
|
126
|
+
yield msg.contract
|
127
|
+
else
|
128
|
+
msg.contract
|
129
|
+
end
|
130
|
+
queue.push c unless c.nil?
|
128
131
|
end
|
129
132
|
when Messages::Incoming::ContractDataEnd
|
130
|
-
queue.
|
131
|
-
|
133
|
+
queue.close if msg.request_id.to_i == message_id
|
132
134
|
end # case
|
133
135
|
end # subscribe
|
134
136
|
|
@@ -138,19 +140,12 @@ module IB
|
|
138
140
|
# if contract_to_be_queried.present? # is nil if query_contract fails
|
139
141
|
message_id = ib.send_message :RequestContractData, :contract => query_contract
|
140
142
|
|
141
|
-
|
142
|
-
|
143
|
-
# j=0; loop{ sleep(0.01); j+=1; break if queue.closed? || queue.pop || j> 100; }
|
144
|
-
# ib.logger.error{ "#{to_human} --> No ContractData recieved " } if j >= 100 && !queue.closed?
|
145
|
-
ib.unsubscribe a
|
146
|
-
end
|
147
|
-
if thread.nil?
|
148
|
-
th.join # wait for the thread to finish
|
149
|
-
recieved_contracts # return queue of contracts
|
150
|
-
else
|
151
|
-
th # return active thread
|
143
|
+
while r = queue.pop
|
144
|
+
received_contracts << r
|
152
145
|
end
|
146
|
+
ib.unsubscribe a
|
153
147
|
end
|
148
|
+
received_contracts # return contracts
|
154
149
|
end
|
155
150
|
|
156
151
|
# Generates an IB::Contract with the required attributes to retrieve a unique contract from the TWS
|
@@ -189,7 +184,7 @@ module IB
|
|
189
184
|
# Contract.build item_attributehash[necessary_items].merge(:sec_type=> sec_type) # return this
|
190
185
|
Contract.build self.invariant_attributes # return this
|
191
186
|
else # its always possible, to retrieve a Contract if con_id and exchange or are present
|
192
|
-
Contract.new con_id: con_id , :exchange => exchange.presence || item_attributehash[
|
187
|
+
Contract.new con_id: con_id , :exchange => exchange.presence || item_attributehash[necessary_attributes][:exchange].presence || 'SMART' # return this
|
193
188
|
end # if
|
194
189
|
end # def
|
195
190
|
end
|
data/lib/ib-gateway.rb
CHANGED
@@ -1,5 +1,17 @@
|
|
1
|
+
require "distribution"
|
2
|
+
require "polars"
|
1
3
|
require 'ib-api'
|
2
4
|
require 'ib/verify'
|
3
5
|
require 'ib/spread-prototypes'
|
4
6
|
require 'ib/order-prototypes'
|
7
|
+
require "ib/eod"
|
8
|
+
require "ib/market-price"
|
9
|
+
require "ib/option-chain"
|
10
|
+
require "ib/option-greeks"
|
11
|
+
require "ib/models/contract.rb"
|
12
|
+
require "ib/models/bag.rb"
|
13
|
+
require "ib/models/account.rb"
|
14
|
+
require "ib/models/option.rb"
|
15
|
+
require "ib/models/future.rb"
|
16
|
+
require "ib/probability_of_expiring"
|
5
17
|
require 'ib/gateway'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ib-extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hartmut Bischoff
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ox
|
@@ -24,20 +24,62 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: prime
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: distribution
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: polars-df
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.3.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.3.1
|
27
69
|
- !ruby/object:Gem::Dependency
|
28
70
|
name: ib-api
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
30
72
|
requirements:
|
31
73
|
- - "~>"
|
32
74
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
75
|
+
version: 972.5.2
|
34
76
|
type: :runtime
|
35
77
|
prerelease: false
|
36
78
|
version_requirements: !ruby/object:Gem::Requirement
|
37
79
|
requirements:
|
38
80
|
- - "~>"
|
39
81
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
82
|
+
version: 972.5.2
|
41
83
|
- !ruby/object:Gem::Dependency
|
42
84
|
name: bundler
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -158,11 +200,15 @@ files:
|
|
158
200
|
- lib/ib/gateway/order-handling.rb
|
159
201
|
- lib/ib/market-price.rb
|
160
202
|
- lib/ib/models/account.rb
|
203
|
+
- lib/ib/models/bag.rb
|
204
|
+
- lib/ib/models/contract.rb
|
205
|
+
- lib/ib/models/future.rb
|
161
206
|
- lib/ib/models/option.rb
|
162
207
|
- lib/ib/option-chain.rb
|
163
208
|
- lib/ib/option-greeks.rb
|
164
209
|
- lib/ib/order-prototypes.rb
|
165
210
|
- lib/ib/order_prototypes/abstract.rb
|
211
|
+
- lib/ib/order_prototypes/all-in-one.rb
|
166
212
|
- lib/ib/order_prototypes/combo.rb
|
167
213
|
- lib/ib/order_prototypes/forex.rb
|
168
214
|
- lib/ib/order_prototypes/limit.rb
|
@@ -171,6 +217,8 @@ files:
|
|
171
217
|
- lib/ib/order_prototypes/premarket.rb
|
172
218
|
- lib/ib/order_prototypes/stop.rb
|
173
219
|
- lib/ib/order_prototypes/volatility.rb
|
220
|
+
- lib/ib/plot-poec.rb
|
221
|
+
- lib/ib/probability_of_expiring.rb
|
174
222
|
- lib/ib/spread-prototypes.rb
|
175
223
|
- lib/ib/spread_prototypes/butterfly.rb
|
176
224
|
- lib/ib/spread_prototypes/calendar.rb
|
@@ -200,7 +248,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
248
|
- !ruby/object:Gem::Version
|
201
249
|
version: '0'
|
202
250
|
requirements: []
|
203
|
-
rubygems_version: 3.
|
251
|
+
rubygems_version: 3.3.7
|
204
252
|
signing_key:
|
205
253
|
specification_version: 4
|
206
254
|
summary: Part of IB-Ruby. Tools to to access the tws-api comfortably.
|