ib-extensions 1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|