ib-extensions 1.2 → 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.
@@ -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'