ib-extensions 1.2 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,46 @@
1
+ module IB
2
+
3
+ #Combo-Orders are used for NonGuaranteed Orders only.
4
+ #»Normal« Option-Spreads are transmited by ordinary Limit-Orders
5
+ module Combo
6
+ ### Basic Order Prototype: Combo with two limits
7
+ extend OrderPrototype
8
+ class << self
9
+ def defaults
10
+ ## todo implement serialisation of key/tag Hash to camelCased-keyValue-List
11
+ # super.merge order_type: :limit , combo_params: { non_guaranteed: true}
12
+ # for the time being, we use the array representation
13
+ super.merge order_type: :limit , combo_params: [ ['NonGuaranteed', true] ]
14
+ end
15
+
16
+
17
+ def requirements
18
+ Limit.requirements
19
+ end
20
+
21
+ def aliases
22
+ Limit.aliases
23
+ end
24
+
25
+
26
+ def summary
27
+ <<-HERE
28
+ Create combination orders. It is constructed through options, stock and futures legs
29
+ (stock legs can be included if the order is routed through SmartRouting).
30
+
31
+ Although a combination/spread order is constructed of separate legs, it is executed
32
+ as a single transaction if it is routed directly to an exchange. For combination orders
33
+ that are SmartRouted, each leg may be executed separately to ensure best execution.
34
+
35
+ The »NonGuaranteed«-Flag is set to "false". A Pair of two securites should always be
36
+ routed »Guaranteed«, otherwise separate orders are prefered.
37
+
38
+ If a Bag-Order with »NonGuarateed :true« should be submitted, the Order-Type would be
39
+ REL+MKT, LMT+MKT, or REL+LMT
40
+ --------
41
+ Products: Options, Stocks, Futures
42
+ HERE
43
+ end # def
44
+ end # class
45
+ end # module combo
46
+ end # module ib
@@ -0,0 +1,60 @@
1
+ require 'distribution'
2
+ require 'gnuplot'
3
+
4
+ ## source: ChatGpt
5
+ # Set the variables
6
+ s = 100 # current stock price
7
+ k = 110 # strike price
8
+ t = 0.5 # time to expiry (in years)
9
+ r = 0.02 # risk-free interest rate
10
+ sigma = 0.2 # implied volatility
11
+ p = 0.7 # probability
12
+
13
+ # Calculate d1 and d2
14
+ d1 = (Math.log(s/k) + (r + 0.5*sigma**2)*t) / (sigma * Math.sqrt(t))
15
+ d2 = d1 - sigma * Math.sqrt(t)
16
+
17
+ # Calculate the Z-score for the desired probability
18
+ z_score = Distribution::Normal.inv_cdf(p + (1-p)/2)
19
+
20
+ # Calculate the upper and lower bounds of the 70% probability range
21
+ upper_bound = s * Math.exp((r - 0.5*sigma**2)*t + sigma*Math.sqrt(t)*z_score)
22
+ lower_bound = s * Math.exp((r - 0.5*sigma**2)*t + sigma*Math.sqrt(t)*(-z_score))
23
+
24
+ # Create the plot
25
+ Gnuplot.open do |gp|
26
+ Gnuplot::Plot.new(gp) do |plot|
27
+ plot.title 'Probability Density Function with 70% probability range'
28
+ plot.xlabel 'Stock Price'
29
+ plot.ylabel 'Probability Density'
30
+
31
+ # Set the x-axis range
32
+ plot.xrange "[#{s*0.6}:#{s*1.4}]"
33
+
34
+ # Plot the probability density function
35
+ x = (s*0.6..s*1.4).step(0.1).to_a
36
+ y = x.map { |xi| Distribution::Normal.pdf((Math.log(xi/s) + (r - 0.5*sigma**2)*t) / (sigma * Math.sqrt(t))) / (xi*sigma*Math.sqrt(t)) }
37
+ plot.data << Gnuplot::DataSet.new([x, y]) do |ds|
38
+ ds.with = 'lines'
39
+ ds.linewidth = 2
40
+ ds.linecolor = 'blue'
41
+ end
42
+
43
+ # Plot the upper and lower bounds of the 70% probability range
44
+ plot.data << Gnuplot::DataSet.new([lower_bound, 0]) do |ds|
45
+ ds.with = 'lines'
46
+ ds.linewidth = 2
47
+ ds.linecolor = 'red'
48
+ end
49
+ plot.data << Gnuplot::DataSet.new([upper_bound, 0]) do |ds|
50
+ ds.with = 'lines'
51
+ ds.linewidth = 2
52
+ ds.linecolor = 'red'
53
+ end
54
+ plot.data << Gnuplot::DataSet.new([[lower_bound, upper_bound], [0, 0]]) do |ds|
55
+ ds.with = 'filledcurve x1=1 x2=2'
56
+ ds.fillcolor = 'red'
57
+ ds.fillstyle = 'transparent solid 0.2'
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,109 @@
1
+ module IB
2
+ module ProbabilityOfExpiring
3
+
4
+ # Use by calling
5
+ # a = Stock.new symbol: 'A'
6
+ #
7
+ require 'prime'
8
+ require 'distribution'
9
+
10
+
11
+
12
+ def probability_of_assignment **args
13
+ ( probability_of_expiring(**args) - 1 ).abs
14
+ end
15
+ def probability_of_expiring **args
16
+ @probability_of_expiring = calculate_probability_of_expiring(**args) if @probability_of_expiring.nil? || ! args.empty?
17
+ @probability_of_expiring
18
+ end
19
+
20
+ private
21
+ =begin
22
+ Here are the steps to calculate the probability of expiry cone for a stock in
23
+ the next six months using the Black-Scholes model:
24
+
25
+ * Determine the current stock price and the strike price for the option you
26
+ are interested in. Let's say the current stock price is $100 and the strike
27
+ price is $110. * Determine the time to expiry. In this case, we are
28
+ interested in the next six months, so the time to expiry is 0.5 years. *
29
+ Determine the implied volatility of the stock. Implied volatility is a measure
30
+ of the expected volatility of the stock over the life of the option, and can be
31
+ estimated from the option prices in the market.
32
+
33
+ * Use the Black-Scholes formula to calculate the probability of the stock
34
+ expiring within the range of prices that make up the expiry cone. The formula
35
+ is:
36
+
37
+ P = N(d2)
38
+
39
+ Where P is the probability of the stock expiring within the expiry cone, and
40
+ N is the cumulative distribution function of the standard normal
41
+ distribution. d2 is calculated as:
42
+
43
+ d2 = (ln(S/K) + (r - 0.5 * σ^2) * T) / (σ * sqrt(T))
44
+
45
+ Where S is the current stock price, K is the strike price, r is the risk-free
46
+ interest rate, σ is the implied volatility, and T is the time to expiry.
47
+
48
+ Look up the value of N(d2) in a standard normal distribution table, or use a
49
+ calculator or spreadsheet program that can calculate cumulative distribution
50
+ functions.
51
+
52
+ The result is the probability of the stock expiring within the expiry cone.
53
+ For example, if N(d2) is 0.35, then the probability of the stock expiring
54
+ within the expiry cone is 35%.
55
+
56
+ (ChatGPT)
57
+ =end
58
+ def calculate_probability_of_expiring price: nil,
59
+ interest: 0.03,
60
+ iv: nil,
61
+ strike: nil,
62
+ expiry: nil,
63
+ ref_date: Date.today
64
+
65
+ if iv.nil? && self.respond_to?( :greek )
66
+ IB::Connection.current.logger.info "Probability_of_expiring: using current IV and Underlying-Price for calculation"
67
+ request_greeks if greek.nil?
68
+ iv = greek.implied_volatility
69
+ price = greek.under_price if price.nil?
70
+ end
71
+ error "ProbabilityOfExpiringCone needs iv as input" if iv.nil? || iv.zero?
72
+
73
+ if price.nil?
74
+ price = if self.strike.to_i.zero?
75
+ market_price
76
+ else
77
+ underlying.market_price
78
+ end
79
+ end
80
+ error "ProbabilityOfExpiringCone needs price as input" if price.to_i.zero?
81
+
82
+
83
+ strike ||= self.strike
84
+ error "ProbabilityOfExpiringCone needs strike as input" if strike.to_i.zero?
85
+
86
+ if expiry.nil?
87
+ if last_trading_day == ''
88
+ error "ProbabilityOfExpiringCone needs expiry as input"
89
+ else
90
+ expiry = last_trading_day
91
+ end
92
+ end
93
+ time_to_expiry = ( Date.parse( expiry.to_s ) - ref_date ).to_i
94
+
95
+ # # Calculate d1 and d2
96
+ d1 = (Math.log(price/strike.to_f) + (interest + 0.5*iv**2)*time_to_expiry) / (iv * Math.sqrt(time_to_expiry))
97
+ d2 = d1 - iv * Math.sqrt(time_to_expiry)
98
+ #
99
+ # # Calculate the probability of expiry cone
100
+ Distribution::Normal.cdf(d2)
101
+
102
+ end
103
+ end
104
+
105
+ class Contract
106
+ include ProbabilityOfExpiring
107
+ end
108
+
109
+ end
@@ -24,6 +24,7 @@ module IB
24
24
 
25
25
  def initialize_spread ref_contract = nil, **attributes
26
26
  error "Initializing of Spread failed – contract is missing" unless ref_contract.is_a?(IB::Contract)
27
+ # make sure that :exchange, :symbol and :currency are present
27
28
  the_contract = ref_contract.merge( **attributes ).verify.first
28
29
  error "Underlying for Spread is not valid: #{ref_contract.to_human}" if the_contract.nil?
29
30
  the_spread= IB::Spread.new the_contract.attributes.slice( :exchange, :symbol, :currency )
@@ -25,8 +25,7 @@ module IB
25
25
  error "fabrication is based on a master option. Please specify as first argument" unless master.is_a?(IB::Option)
26
26
  strike = master.strike
27
27
  master.right = :put unless master.right == :call
28
- l=[] ; master.verify{|x| x.contract_detail= nil; l << x }
29
- # puts "master: #{master.attributes.inspect}"
28
+ l= master.verify
30
29
  if l.empty?
31
30
  error "Invalid Parameters. No Contract found #{master.to_human}"
32
31
  elsif l.size > 1
@@ -43,7 +42,7 @@ module IB
43
42
  strikes = [front, master.strike, back]
44
43
  strikes.zip([1, -2, 1]).each do |strike, ratio|
45
44
  action = ratio >0 ? :buy : :sell
46
- leg = IB::Option.new( master.attributes.merge( strike: strike )).verify!.essential
45
+ leg = IB::Option.new( master.attributes.merge( strike: strike )).verify.first.essential
47
46
  the_spread.add_leg leg, action: action, ratio: ratio.abs
48
47
  end
49
48
  the_spread.description = the_description( the_spread )
@@ -53,7 +52,6 @@ module IB
53
52
 
54
53
  def build from: , front:, back:, **options
55
54
  underlying_attributes = { expiry: IB::Symbols::Futures.next_expiry, right: :put }.merge( from.attributes.slice( :symbol, :currency, :exchange, :strike )).merge( options )
56
- puts underlying_attributes.inspect
57
55
  fabricate IB::Option.new( underlying_attributes), front: front, back: back
58
56
  end
59
57
 
@@ -16,16 +16,13 @@ module IB
16
16
  def fabricate master, the_other_expiry
17
17
 
18
18
  error "Argument must be a IB::Future or IB::Option" unless [:option, :future_option, :future ].include? master.sec_type
19
-
20
- initialize_spread( master ) do | the_spread |
21
- the_spread.add_leg master, action: :buy
22
-
23
- the_other_expiry = the_other_expiry.values.first if the_other_expiry.is_a?(Hash)
24
- back = the_spread.transform_distance master.expiry, the_other_expiry
25
- the_spread.add_leg master.merge(expiry: back ), action: :sell
26
- error "Initialisation of Legs failed" if the_spread.legs.size != 2
27
- the_spread.description = the_description( the_spread )
28
- end
19
+ m = master.verify.first
20
+ the_other_expiry = the_other_expiry.values.first if the_other_expiry.is_a?(Hash)
21
+ back = IB::Spread.transform_distance m.expiry, the_other_expiry
22
+ calendar = m.roll expiry: back
23
+ error "Initialisation of Legs failed" if calendar.legs.size != 2
24
+ calendar.description = the_description( calendar )
25
+ calendar # return fabricated spread
29
26
  end
30
27
 
31
28
 
@@ -46,25 +43,30 @@ module IB
46
43
  fields[:expiry] = from.expiry unless fields.key?(:expiry)
47
44
  fields[:trading_class] = from.trading_class unless fields.key?(:trading_class) || from.trading_class.empty?
48
45
  fields[:multiplier] = from.multiplier unless fields.key?(:multiplier) || from.multiplier.to_i.zero?
49
- details = nil; from.verify{|c| details = c.contract_detail }
46
+ details = from.verify.first.contract_detail
50
47
  IB::Contract.new( con_id: details.under_con_id,
51
- currency: from.currency)
52
- .verify!
53
- .essential
48
+ currency: from.currency).verify.first.essential
54
49
  else
55
50
  from
56
51
  end
57
52
  kind = { :front => fields.delete(:front), :back => fields.delete(:back) }
58
- error "Specifiaction of :front and :back expiries nessesary, got: #{kind.inspect}" if kind.values.any?(nil)
53
+ error "Specifiaction of :front and :back expiries necessary, got: #{kind.inspect}" if kind.values.any?(nil)
59
54
  initialize_spread( underlying ) do | the_spread |
60
- leg_prototype = IB::Option.new underlying.attributes
61
- .slice( :currency, :symbol, :exchange)
62
- .merge(defaults)
63
- .merge( fields )
64
- kind[:back] = the_spread.transform_distance kind[:front], kind[:back]
55
+ leg_prototype = IB::Option.new underlying.attributes
56
+ .slice( :currency, :symbol, :exchange)
57
+ .merge(defaults)
58
+ .merge( fields )
59
+ kind[:back] = IB::Spread.transform_distance kind[:front], kind[:back]
65
60
  leg_prototype.sec_type = 'FOP' if underlying.is_a?(IB::Future)
66
- the_spread.add_leg IB::Contract.build( leg_prototype.attributes.merge(expiry: kind[:front] )), action: :buy
67
- the_spread.add_leg IB::Contract.build( leg_prototype.attributes.merge(expiry: kind[:back])), action: :sell
61
+ leg1 = leg_prototype.merge(expiry: kind[:front] ).verify.first
62
+ leg2 = leg_prototype.merge(expiry: kind[:back] ).verify.first
63
+ unless leg2.is_a? IB::Option
64
+ leg2_trading_class = ''
65
+ leg2 = leg_prototype.merge(expiry: kind[:back] ).verify.first
66
+
67
+ end
68
+ the_spread.add_leg leg1 , action: :buy
69
+ the_spread.add_leg leg2 , action: :sell
68
70
  error "Initialisation of Legs failed" if the_spread.legs.size != 2
69
71
  the_spread.description = the_description( the_spread )
70
72
  end
@@ -78,7 +80,7 @@ module IB
78
80
 
79
81
  def the_description spread
80
82
  x= [ spread.combo_legs.map(&:weight) , spread.legs.map( &:last_trading_day )].transpose
81
- "<Calendar #{spread.symbol} #{spread.legs.first.right}(#{spread.legs.first.strike})[#{x.map{|w,l_t_d| "#{w} :#{Date.parse(l_t_d).strftime("%b %Y")} "}.join( '|+|' )} >"
83
+ "<Calendar #{spread.symbol} #{spread.legs.first.right}(#{spread.legs.first.strike})[#{x.map{|w,l_t_d| "#{w} :#{Date.parse(l_t_d).strftime("%b %Y")} "}.join( '|+|' )} >"
82
84
  end
83
85
  end # class
84
86
  end # module vertical
@@ -43,11 +43,11 @@ module IB
43
43
  leg_prototype = IB::Option.new from.attributes
44
44
  .slice( :currency, :symbol, :exchange)
45
45
  .merge(defaults)
46
- .merge( fields )
46
+ .merge( fields )
47
47
 
48
48
  leg_prototype.sec_type = 'FOP' if from.is_a?(IB::Future)
49
- the_spread.add_leg IB::Contract.build leg_prototype.attributes.merge( right: :put )
50
- the_spread.add_leg IB::Contract.build leg_prototype.attributes.merge( right: :call )
49
+ the_spread.add_leg leg_prototype.merge( right: :put ).verify.first
50
+ the_spread.add_leg leg_prototype.merge( right: :call ).verify.first
51
51
  error "Initialisation of Legs failed" if the_spread.legs.size != 2
52
52
  the_spread.description = the_description( the_spread )
53
53
  end
@@ -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
- leg_prototype = IB::Option.new underlying.attributes
64
- .slice( :currency, :symbol, :exchange)
65
- .merge(defaults)
66
- .merge( fields )
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
- leg_prototype.sec_type = 'FOP' if underlying.is_a?(IB::Future)
70
- the_spread.add_leg IB::Contract.build leg_prototype.attributes.merge( right: :put, strike: kind[:p] )
71
- the_spread.add_leg IB::Contract.build leg_prototype.attributes.merge( right: :call, strike: kind[:c] )
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
- "<Strangle #{spread.symbol}(#{spread.legs.map(&:strike).join(",")})[#{Date.parse(spread.legs.first.last_trading_day).strftime("%b %Y")}]>"
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
- the_spread.add_leg master.essential.merge(strike: sell, local_symbol: "", con_id: 0), action: :sell
24
- the_spread.add_leg master.essential.merge(strike: buy, local_symbol: "", con_id: 0), action: :buy
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 "Specifiaction of :buy and :sell nessesary, got: #{kind.inspect}" if kind.values.any?(nil)
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 = IB::Option.new underlying.attributes
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
- the_spread.add_leg leg_prototype.merge(strike: kind[:sell]), action: :sell
66
- the_spread.add_leg leg_prototype.merge(strike: kind[:buy] ), action: :buy
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
- # class VerifyError < StandardError
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
- return [self] if contract_detail.present? || sec_type == :bag
53
- _verify update: false, thread: thread, &b # returns the allocated threads
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 nessesary_attributes
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
- _verify( update: true){| response | c+=1 } # wait for the returned thread to finish
74
- IB::Connection.logger.error { "Multible Contracts detected during verify!." } if c > 1
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 thread: nil , update:, &b # :nodoc:
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
- message_id = nil
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
- recieved_contracts = []
103
+ received_contracts = []
97
104
  queue = Queue.new
98
- a = nil
105
+ message_id = nil
99
106
 
100
107
  # a tws-request is suppressed for bags and if the contract_detail-record is present
101
- tws_request_not_nessesary = bag? || contract_detail.is_a?( ContractDetail )
108
+ tws_request_not_necessary = bag? || contract_detail.is_a?( ContractDetail )
102
109
 
103
- if tws_request_not_nessesary
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
- # if multiple contracts are present, all of them are assigned
117
- # Only the last contract is saved in self; 'count' is incremented
118
- ## a specified block gets the contract_object on any unique ContractData-Event
119
- recieved_contracts << if block_given?
120
- yield msg.contract
121
- else
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.push(1) if msg.request_id.to_i == message_id
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
- th = Thread.new do
142
- queue.pop
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[nessesary_attributes][:exchange].presence || 'SMART' # return this
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'