ib-extensions 1.1 → 1.3
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.
- 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.
|