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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +112 -0
- data/Guardfile +24 -0
- data/README.md +99 -0
- data/Rakefile +6 -0
- data/bin/console +96 -0
- data/bin/console.yml +3 -0
- data/bin/gateway.rb +97 -0
- data/bin/setup +8 -0
- data/changelog.md +31 -0
- data/examples/cancel_orders +74 -0
- data/examples/eod +35 -0
- data/examples/input.rb +475 -0
- data/examples/market_price +57 -0
- data/examples/option_chain +67 -0
- data/examples/place_and_modify_order +162 -0
- data/examples/place_bracket_order +62 -0
- data/examples/place_butterfly_order +104 -0
- data/examples/place_combo_order +70 -0
- data/examples/place_limit_order +82 -0
- data/examples/place_the_limit_order +145 -0
- data/examples/volatility_research +139 -0
- data/examples/what_if_order +90 -0
- data/ib-extensions.gemspec +37 -0
- data/lib/ib-gateway.rb +5 -0
- data/lib/ib/alerts/base-alert.rb +128 -0
- data/lib/ib/alerts/gateway-alerts.rb +15 -0
- data/lib/ib/alerts/order-alerts.rb +68 -0
- data/lib/ib/eod.rb +152 -0
- data/lib/ib/extensions.rb +9 -0
- data/lib/ib/extensions/contract.rb +37 -0
- data/lib/ib/extensions/version.rb +5 -0
- data/lib/ib/flex.rb +150 -0
- data/lib/ib/gateway.rb +425 -0
- data/lib/ib/gateway/account-infos.rb +115 -0
- data/lib/ib/gateway/order-handling.rb +150 -0
- data/lib/ib/market-price.rb +134 -0
- data/lib/ib/models/account.rb +329 -0
- data/lib/ib/models/spread.rb +159 -0
- data/lib/ib/option-chain.rb +198 -0
- data/lib/ib/option-greeks.rb +88 -0
- data/lib/ib/order-prototypes.rb +110 -0
- data/lib/ib/order_prototypes/abstract.rb +67 -0
- data/lib/ib/order_prototypes/combo.rb +46 -0
- data/lib/ib/order_prototypes/forex.rb +40 -0
- data/lib/ib/order_prototypes/limit.rb +177 -0
- data/lib/ib/order_prototypes/market.rb +116 -0
- data/lib/ib/order_prototypes/pegged.rb +173 -0
- data/lib/ib/order_prototypes/premarket.rb +31 -0
- data/lib/ib/order_prototypes/stop.rb +202 -0
- data/lib/ib/order_prototypes/volatility.rb +39 -0
- data/lib/ib/spread-prototypes.rb +62 -0
- data/lib/ib/spread_prototypes/butterfly.rb +79 -0
- data/lib/ib/spread_prototypes/calendar.rb +85 -0
- data/lib/ib/spread_prototypes/stock-spread.rb +48 -0
- data/lib/ib/spread_prototypes/straddle.rb +75 -0
- data/lib/ib/spread_prototypes/strangle.rb +96 -0
- data/lib/ib/spread_prototypes/vertical.rb +84 -0
- data/lib/ib/verify.rb +226 -0
- metadata +206 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative 'lib/ib/extensions/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "ib-extensions"
|
5
|
+
spec.version = IB::Extensions::VERSION
|
6
|
+
spec.authors = ["Hartmut Bischoff"]
|
7
|
+
spec.email = ["topofocus@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = %q{Part of IB-Ruby. Tools to to access the tws-api comfortably.}
|
10
|
+
spec.homepage = "https://ib-ruby.github.io/ib-doc/"
|
11
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
12
|
+
|
13
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com"
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.cm/ib-ruby/ib-extensions"
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.cm/ib-ruby/ib-extensions/changelog.md"
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
|
29
|
+
spec.add_dependency "ox"
|
30
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
31
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
32
|
+
spec.add_development_dependency 'rspec-collection_matchers'
|
33
|
+
spec.add_development_dependency 'rspec-its'
|
34
|
+
|
35
|
+
spec.add_development_dependency "guard"
|
36
|
+
spec.add_development_dependency "guard-rspec"
|
37
|
+
end
|
data/lib/ib-gateway.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
module IB
|
2
|
+
class Alert
|
3
|
+
=begin
|
4
|
+
The Singleton IB::Alert handles any response to IB:Messages::Incomming:Alert
|
5
|
+
|
6
|
+
Individual methods can be defined as well as methods responding to a group of error-codes.
|
7
|
+
The default-behavior is defined in the method_missing-method. This just logs the object at the debug level.
|
8
|
+
|
9
|
+
To use the IB::Alert facility, first a logger has to be assigned to the Class.
|
10
|
+
IB::Alert.logger = Logger.new(STDOUT)
|
11
|
+
|
12
|
+
Default-wrappers to completely ignore the error-message (ignore_alert)
|
13
|
+
and to log the object in a different log-level (log_alert_in [warn,info,error] ) are defined in base_alert
|
14
|
+
Just add
|
15
|
+
module IB
|
16
|
+
class Alert
|
17
|
+
log_alert_in_warn {list of codennumbers}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
to your code
|
21
|
+
|
22
|
+
|
23
|
+
IB::Gateway calls the methods in response of subscribing to the :Alert signal by calling
|
24
|
+
IB::Alert.send("alert_#{msg.code}", msg )
|
25
|
+
|
26
|
+
To define a response to the code 134 ( Modify order failed) a method like
|
27
|
+
module IB
|
28
|
+
class Alert
|
29
|
+
def self.alert_134 msg
|
30
|
+
(your code)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
has to be written.
|
35
|
+
|
36
|
+
Important: The class is accessed asynchronically. Be careful while raising interrupts.
|
37
|
+
|
38
|
+
=end
|
39
|
+
|
40
|
+
# acts as prototype for any generated method
|
41
|
+
#require 'active_support'
|
42
|
+
|
43
|
+
mattr_accessor :logger
|
44
|
+
|
45
|
+
def self.method_missing( method_id, msg , *args, &block )
|
46
|
+
if msg.is_a? IB::Messages::Incoming::Alert
|
47
|
+
logger.debug { msg.to_human }
|
48
|
+
else
|
49
|
+
logger.error { "Argument to IB::Alert is not a IB::Messages::Incoming::Alert" }
|
50
|
+
logger.error { "The object: #{msg.inspect} " }
|
51
|
+
end
|
52
|
+
rescue NoMethodError
|
53
|
+
unless logger.nil?
|
54
|
+
logger.error { "The Argument is not a valid IB::Messages:Incoming::Alert object"}
|
55
|
+
logger.error { "The object: #{msg.inspect} " }
|
56
|
+
else
|
57
|
+
puts "No Logging-Device specified"
|
58
|
+
puts "The object: #{msg.inspect} "
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
class << self
|
65
|
+
|
66
|
+
def ignore_alert *codes
|
67
|
+
codes.each do |n|
|
68
|
+
class_eval <<-EOD
|
69
|
+
def self.alert_#{n} msg
|
70
|
+
# even the log_debug entry is suppressed
|
71
|
+
end
|
72
|
+
EOD
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def log_alert_in_info *codes
|
76
|
+
codes.each do |n|
|
77
|
+
class_eval <<-EOD
|
78
|
+
def self.alert_#{n} msg
|
79
|
+
logger.info { msg.to_human }
|
80
|
+
end
|
81
|
+
EOD
|
82
|
+
end
|
83
|
+
end
|
84
|
+
def log_alert_in_warn *codes
|
85
|
+
codes.each do |n|
|
86
|
+
class_eval <<-EOD
|
87
|
+
def self.alert_#{n} msg
|
88
|
+
logger.warn { msg.to_human }
|
89
|
+
end
|
90
|
+
EOD
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def log_alert_in_error *codes
|
95
|
+
codes.each do |n|
|
96
|
+
class_eval <<-EOD
|
97
|
+
def self.alert_#{n} msg
|
98
|
+
if msg.error_id.present? && msg.error_id > 0
|
99
|
+
logger.error { msg.message + ' id: ' + msg.error_id.to_s }
|
100
|
+
else
|
101
|
+
logger.error { msg.message }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
EOD
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
ignore_alert 200 , # is handled by IB::Contract.update_contract
|
110
|
+
2100, # API client has been unsubscribed from account data
|
111
|
+
2105,
|
112
|
+
399 # your order will not be placed at the exchange until
|
113
|
+
|
114
|
+
log_alert_in_info 1102 #Connectivity between IB and Trader Workstation has been restored
|
115
|
+
|
116
|
+
|
117
|
+
log_alert_in_error 320, 321, 323, 324, #ServerError
|
118
|
+
## 110, # The price does not conform to the minimum price variation
|
119
|
+
# 103, #duplicate order ## order-alerts
|
120
|
+
# 201, #deleted objecta ## order-alerts
|
121
|
+
326 #Unable connect as the client id is already in use
|
122
|
+
|
123
|
+
log_alert_in_warn 354 #Requested market data is not subscribed
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# These Alerts are always active
|
2
|
+
module IB
|
3
|
+
class Alert
|
4
|
+
|
5
|
+
def self.alert_2102 msg
|
6
|
+
# Connectivity between IB and Trader Workstation has been restored - data maintained.
|
7
|
+
sleep 0.1 # no need to wait too long.
|
8
|
+
if IB::Gateway.current.check_connection
|
9
|
+
IB::Gateway.logger.debug { "Alert 2102: Connection stable" }
|
10
|
+
else
|
11
|
+
IB::Gateway.current.reconnect
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module IB
|
2
|
+
class Alert
|
3
|
+
|
4
|
+
def self.alert_202 msg
|
5
|
+
# do anything in a secure mutex-synchronized-environment
|
6
|
+
any_order = IB::Gateway.current.account_data do | account |
|
7
|
+
order= account.locate_order( local_id: msg.error_id )
|
8
|
+
if order.present? && ( order.order_state.status != 'Cancelled' )
|
9
|
+
order.order_states.update_or_create( IB::OrderState.new( status: 'Cancelled',
|
10
|
+
perm_id: order.perm_id,
|
11
|
+
local_id: order.local_id ) ,
|
12
|
+
:status )
|
13
|
+
|
14
|
+
end
|
15
|
+
order # return_value
|
16
|
+
end
|
17
|
+
if any_order.compact.empty?
|
18
|
+
IB::Gateway.logger.error{"Alert 202: The deleted order was not registered: local_id #{msg.error_id}"}
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
class << self
|
25
|
+
=begin
|
26
|
+
IB::Alert#AddOrderstateAlert
|
27
|
+
|
28
|
+
The OrderState-Record is used to record the history of the order.
|
29
|
+
If selected Alert-Messages appear, they are added to the Order.order_state-Array.
|
30
|
+
The last Status is available as Order.order_state, all states are accessible by Order.order_states
|
31
|
+
|
32
|
+
The TWS-Message-text is stored to the »warning-text«-field.
|
33
|
+
The Status is always »rejected«.
|
34
|
+
If the first OrderState-object of a Order is »rejected«, the order is not placed at all.
|
35
|
+
Otherwise only the last action is not applied and the order is unchanged.
|
36
|
+
|
37
|
+
=end
|
38
|
+
def add_orderstate_alert *codes
|
39
|
+
codes.each do |n|
|
40
|
+
class_eval <<-EOD
|
41
|
+
def self.alert_#{n} msg
|
42
|
+
|
43
|
+
if msg.error_id.present?
|
44
|
+
IB::Gateway.current.account_data do | account |
|
45
|
+
order= account.locate_order( local_id: msg.error_id )
|
46
|
+
if order.present? && ( order.order_state.status != 'Rejected' )
|
47
|
+
order.order_states.update_or_create( IB::OrderState.new( status: 'Rejected' ,
|
48
|
+
perm_id: order.perm_id,
|
49
|
+
warning_text: '#{n}: '+ msg.message,
|
50
|
+
local_id: msg.error_id ), :status )
|
51
|
+
|
52
|
+
IB::Gateway.logger.error{ msg.to_human }
|
53
|
+
end # order present?
|
54
|
+
end # mutex-environment
|
55
|
+
end # branch
|
56
|
+
end # def
|
57
|
+
EOD
|
58
|
+
end # loop
|
59
|
+
end # def
|
60
|
+
end
|
61
|
+
add_orderstate_alert 103, # duplicate order
|
62
|
+
201, # deleted object
|
63
|
+
105, # Order being modified does not match original order
|
64
|
+
462, # Cannot change to the new Time in Force:GTD
|
65
|
+
329, # Cannot change to the new order type:STP
|
66
|
+
10147 # OrderId 0 that needs to be cancelled is not found.
|
67
|
+
end # class Alert
|
68
|
+
end # module IB
|
data/lib/ib/eod.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
module IB
|
2
|
+
require 'active_support/core_ext/date/calculations'
|
3
|
+
module BuisinesDays
|
4
|
+
# https://stackoverflow.com/questions/4027768/calculate-number-of-business-days-between-two-days
|
5
|
+
|
6
|
+
# Calculates the number of business days in range (start_date, end_date]
|
7
|
+
#
|
8
|
+
# @param start_date [Date]
|
9
|
+
# @param end_date [Date]
|
10
|
+
#
|
11
|
+
# @return [Fixnum]
|
12
|
+
def self.business_days_between(start_date, end_date)
|
13
|
+
days_between = (end_date - start_date).to_i
|
14
|
+
return 0 unless days_between > 0
|
15
|
+
|
16
|
+
# Assuming we need to calculate days from 9th to 25th, 10-23 are covered
|
17
|
+
# by whole weeks, and 24-25 are extra days.
|
18
|
+
#
|
19
|
+
# Su Mo Tu We Th Fr Sa # Su Mo Tu We Th Fr Sa
|
20
|
+
# 1 2 3 4 5 # 1 2 3 4 5
|
21
|
+
# 6 7 8 9 10 11 12 # 6 7 8 9 ww ww ww
|
22
|
+
# 13 14 15 16 17 18 19 # ww ww ww ww ww ww ww
|
23
|
+
# 20 21 22 23 24 25 26 # ww ww ww ww ed ed 26
|
24
|
+
# 27 28 29 30 31 # 27 28 29 30 31
|
25
|
+
whole_weeks, extra_days = days_between.divmod(7)
|
26
|
+
|
27
|
+
unless extra_days.zero?
|
28
|
+
# Extra days start from the week day next to start_day,
|
29
|
+
# and end on end_date's week date. The position of the
|
30
|
+
# start date in a week can be either before (the left calendar)
|
31
|
+
# or after (the right one) the end date.
|
32
|
+
#
|
33
|
+
# Su Mo Tu We Th Fr Sa # Su Mo Tu We Th Fr Sa
|
34
|
+
# 1 2 3 4 5 # 1 2 3 4 5
|
35
|
+
# 6 7 8 9 10 11 12 # 6 7 8 9 10 11 12
|
36
|
+
# ## ## ## ## 17 18 19 # 13 14 15 16 ## ## ##
|
37
|
+
# 20 21 22 23 24 25 26 # ## 21 22 23 24 25 26
|
38
|
+
# 27 28 29 30 31 # 27 28 29 30 31
|
39
|
+
#
|
40
|
+
# If some of the extra_days fall on a weekend, they need to be subtracted.
|
41
|
+
# In the first case only corner days can be days off,
|
42
|
+
# and in the second case there are indeed two such days.
|
43
|
+
extra_days -= if start_date.tomorrow.wday <= end_date.wday
|
44
|
+
[start_date.tomorrow.sunday?, end_date.saturday?].count(true)
|
45
|
+
else
|
46
|
+
2
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
(whole_weeks * 5) + extra_days
|
51
|
+
end
|
52
|
+
end
|
53
|
+
class Contract
|
54
|
+
# Receive EOD-Data
|
55
|
+
#
|
56
|
+
# The Enddate has to be specified (as Date Object), t
|
57
|
+
#
|
58
|
+
# The Duration can either be specified as Sting " yx D" or as Integer.
|
59
|
+
# Altenative a start date can be specified with the :start parameter.
|
60
|
+
#
|
61
|
+
# The parameter :what specified the kind of received data:
|
62
|
+
# Valid values:
|
63
|
+
# :trades, :midpoint, :bid, :ask, :bid_ask,
|
64
|
+
# :historical_volatility, :option_implied_volatility,
|
65
|
+
# :option_volume, :option_open_interest
|
66
|
+
#
|
67
|
+
# The results can be preprocessed through a block, thus
|
68
|
+
#
|
69
|
+
# puts IB::Symbols::Index::stoxx.eod( duration: '10 d')){|r| r.to_human}
|
70
|
+
# <Bar: 2019-04-01 wap 0.0 OHLC 3353.67 3390.98 3353.67 3385.38 trades 1750 vol 0>
|
71
|
+
# <Bar: 2019-04-02 wap 0.0 OHLC 3386.18 3402.77 3382.84 3395.7 trades 1729 vol 0>
|
72
|
+
# <Bar: 2019-04-03 wap 0.0 OHLC 3399.93 3435.9 3399.93 3435.56 trades 1733 vol 0>
|
73
|
+
# <Bar: 2019-04-04 wap 0.0 OHLC 3434.34 3449.44 3425.19 3441.93 trades 1680 vol 0>
|
74
|
+
# <Bar: 2019-04-05 wap 0.0 OHLC 3445.05 3453.01 3437.92 3447.47 trades 1677 vol 0>
|
75
|
+
# <Bar: 2019-04-08 wap 0.0 OHLC 3446.15 3447.08 3433.47 3438.06 trades 1648 vol 0>
|
76
|
+
# <Bar: 2019-04-09 wap 0.0 OHLC 3437.07 3450.69 3416.67 3417.22 trades 1710 vol 0>
|
77
|
+
# <Bar: 2019-04-10 wap 0.0 OHLC 3418.36 3435.32 3418.36 3424.65 trades 1670 vol 0>
|
78
|
+
# <Bar: 2019-04-11 wap 0.0 OHLC 3430.73 3442.25 3412.15 3435.34 trades 1773 vol 0>
|
79
|
+
# <Bar: 2019-04-12 wap 0.0 OHLC 3432.16 3454.77 3425.84 3447.83 trades 1715 vol 0>
|
80
|
+
#
|
81
|
+
# «to_human« is not needed here because ist aliased with `to_s`
|
82
|
+
#
|
83
|
+
# puts Symbols::Stocks.wfc.eod( start: Date.new(2019,10,9), duration: 3 )
|
84
|
+
# <Bar: 2020-10-23 wap 23.3675 OHLC 23.55 23.55 23.12 23.28 trades 5778 vol 50096>
|
85
|
+
# <Bar: 2020-10-26 wap 22.7445 OHLC 22.98 22.99 22.6 22.7 trades 6873 vol 79560>
|
86
|
+
# <Bar: 2020-10-27 wap 22.086 OHLC 22.55 22.58 21.82 21.82 trades 7503 vol 97691>
|
87
|
+
|
88
|
+
# puts Symbols::Stocks.wfc.eod( to: Date.new(2019,10,9), duration: 3 )
|
89
|
+
# <Bar: 2019-10-04 wap 48.964 OHLC 48.61 49.25 48.54 49.21 trades 9899 vol 50561>
|
90
|
+
# <Bar: 2019-10-07 wap 48.9445 OHLC 48.91 49.29 48.75 48.81 trades 10317 vol 50189>
|
91
|
+
# <Bar: 2019-10-08 wap 47.9165 OHLC 48.25 48.34 47.55 47.82 trades 12607 vol 53577>
|
92
|
+
#
|
93
|
+
def eod start:nil, to: Date.today, duration: nil , what: :trades
|
94
|
+
|
95
|
+
tws = IB::Connection.current
|
96
|
+
recieved = Queue.new
|
97
|
+
r = nil
|
98
|
+
# the hole response is transmitted at once!
|
99
|
+
a= tws.subscribe(IB::Messages::Incoming::HistoricalData) do |msg|
|
100
|
+
if msg.request_id == con_id
|
101
|
+
# msg.results.each { |entry| puts " #{entry}" }
|
102
|
+
r = block_given? ? msg.results.map{|y| yield y} : msg.results
|
103
|
+
end
|
104
|
+
recieved.push Time.now
|
105
|
+
end
|
106
|
+
b = tws.subscribe( IB::Messages::Incoming::Alert) do |msg|
|
107
|
+
if [321,162,200].include? msg.code
|
108
|
+
tws.logger.info msg.message
|
109
|
+
# TWS Error 200: No security definition has been found for the request
|
110
|
+
# TWS Error 354: Requested market data is not subscribed.
|
111
|
+
# TWS Error 162 # Historical Market Data Service error
|
112
|
+
recieved =[]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
duration = if duration.present?
|
118
|
+
duration.is_a?(String) ? duration : duration.to_s + " D"
|
119
|
+
elsif start.present?
|
120
|
+
BuisinesDays.business_days_between(start, to).to_s + " D"
|
121
|
+
else
|
122
|
+
"1 D"
|
123
|
+
end
|
124
|
+
|
125
|
+
tws.send_message IB::Messages::Outgoing::RequestHistoricalData.new(
|
126
|
+
:request_id => con_id,
|
127
|
+
:contract => self,
|
128
|
+
:end_date_time => to.to_time.to_ib, # Time.now.to_ib,
|
129
|
+
:duration => duration, # ?
|
130
|
+
:bar_size => :day1, # IB::BAR_SIZES.key(:hour)?
|
131
|
+
:what_to_show => what,
|
132
|
+
:use_rth => 0,
|
133
|
+
:format_date => 2,
|
134
|
+
:keep_up_todate => 0)
|
135
|
+
|
136
|
+
Timeout::timeout(50) do # max 5 sec.
|
137
|
+
sleep 0.1
|
138
|
+
last_time = recieved.pop # blocks until a message is ready on the queue
|
139
|
+
loop do
|
140
|
+
sleep 0.1
|
141
|
+
break if recieved.empty? # finish if no more data received
|
142
|
+
end
|
143
|
+
tws.unsubscribe a
|
144
|
+
tws.unsubscribe b
|
145
|
+
|
146
|
+
r # the collected result
|
147
|
+
|
148
|
+
end
|
149
|
+
end # def
|
150
|
+
end # class
|
151
|
+
end # module
|
152
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
## require any file, except gateway and related
|
2
|
+
require "ib/extensions/version"
|
3
|
+
require "ib/verify"
|
4
|
+
require "ib/eod"
|
5
|
+
require "ib/market-price"
|
6
|
+
require "ib/option-chain"
|
7
|
+
require "ib/option-greeks"
|
8
|
+
require "ib/order-prototypes"
|
9
|
+
require "ib/spread-prototypes"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
def associate_ticdata
|
3
|
+
|
4
|
+
tws= IB::Gateway.tws # get the initialized ib-ruby instance
|
5
|
+
the_id = nil
|
6
|
+
finalize= false
|
7
|
+
# switch to delayed data
|
8
|
+
tws.send_message :RequestMarketDataType, :market_data_type => :delayed
|
9
|
+
|
10
|
+
s_id = tws.subscribe(:TickSnapshotEnd) { |msg| finalize = true if msg.ticker_id == the_id }
|
11
|
+
|
12
|
+
sub_id = tws.subscribe(:TickPrice, :TickSize, :TickGeneric, :TickOption) do |msg|
|
13
|
+
self.bars << msg.the_data if msg.ticker_id == the_id
|
14
|
+
end
|
15
|
+
|
16
|
+
# initialize »the_id« that is used to identify the received tick messages
|
17
|
+
# by firing the market data request
|
18
|
+
the_id = tws.send_message :RequestMarketData, contract: self , snapshot: true
|
19
|
+
|
20
|
+
#keep the method-call running until the request finished
|
21
|
+
#and cancel subscriptions to the message handler.
|
22
|
+
Thread.new do
|
23
|
+
i=0; loop{ i+=1; sleep 0.1; break if finalize || i > 1000 }
|
24
|
+
tws.unsubscribe sub_id
|
25
|
+
tws.unsubscribe s_id
|
26
|
+
puts "#{symbol} data gathered"
|
27
|
+
end # method returns the (running) thread
|
28
|
+
|
29
|
+
end # def
|
30
|
+
###################### private methods
|
31
|
+
|
32
|
+
end # class
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
end # module
|