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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +6 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +9 -0
  7. data/Gemfile.lock +112 -0
  8. data/Guardfile +24 -0
  9. data/README.md +99 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +96 -0
  12. data/bin/console.yml +3 -0
  13. data/bin/gateway.rb +97 -0
  14. data/bin/setup +8 -0
  15. data/changelog.md +31 -0
  16. data/examples/cancel_orders +74 -0
  17. data/examples/eod +35 -0
  18. data/examples/input.rb +475 -0
  19. data/examples/market_price +57 -0
  20. data/examples/option_chain +67 -0
  21. data/examples/place_and_modify_order +162 -0
  22. data/examples/place_bracket_order +62 -0
  23. data/examples/place_butterfly_order +104 -0
  24. data/examples/place_combo_order +70 -0
  25. data/examples/place_limit_order +82 -0
  26. data/examples/place_the_limit_order +145 -0
  27. data/examples/volatility_research +139 -0
  28. data/examples/what_if_order +90 -0
  29. data/ib-extensions.gemspec +37 -0
  30. data/lib/ib-gateway.rb +5 -0
  31. data/lib/ib/alerts/base-alert.rb +128 -0
  32. data/lib/ib/alerts/gateway-alerts.rb +15 -0
  33. data/lib/ib/alerts/order-alerts.rb +68 -0
  34. data/lib/ib/eod.rb +152 -0
  35. data/lib/ib/extensions.rb +9 -0
  36. data/lib/ib/extensions/contract.rb +37 -0
  37. data/lib/ib/extensions/version.rb +5 -0
  38. data/lib/ib/flex.rb +150 -0
  39. data/lib/ib/gateway.rb +425 -0
  40. data/lib/ib/gateway/account-infos.rb +115 -0
  41. data/lib/ib/gateway/order-handling.rb +150 -0
  42. data/lib/ib/market-price.rb +134 -0
  43. data/lib/ib/models/account.rb +329 -0
  44. data/lib/ib/models/spread.rb +159 -0
  45. data/lib/ib/option-chain.rb +198 -0
  46. data/lib/ib/option-greeks.rb +88 -0
  47. data/lib/ib/order-prototypes.rb +110 -0
  48. data/lib/ib/order_prototypes/abstract.rb +67 -0
  49. data/lib/ib/order_prototypes/combo.rb +46 -0
  50. data/lib/ib/order_prototypes/forex.rb +40 -0
  51. data/lib/ib/order_prototypes/limit.rb +177 -0
  52. data/lib/ib/order_prototypes/market.rb +116 -0
  53. data/lib/ib/order_prototypes/pegged.rb +173 -0
  54. data/lib/ib/order_prototypes/premarket.rb +31 -0
  55. data/lib/ib/order_prototypes/stop.rb +202 -0
  56. data/lib/ib/order_prototypes/volatility.rb +39 -0
  57. data/lib/ib/spread-prototypes.rb +62 -0
  58. data/lib/ib/spread_prototypes/butterfly.rb +79 -0
  59. data/lib/ib/spread_prototypes/calendar.rb +85 -0
  60. data/lib/ib/spread_prototypes/stock-spread.rb +48 -0
  61. data/lib/ib/spread_prototypes/straddle.rb +75 -0
  62. data/lib/ib/spread_prototypes/strangle.rb +96 -0
  63. data/lib/ib/spread_prototypes/vertical.rb +84 -0
  64. data/lib/ib/verify.rb +226 -0
  65. metadata +206 -0
@@ -0,0 +1,79 @@
1
+ module IB
2
+
3
+ module Butterfly
4
+
5
+ extend SpreadPrototype
6
+ class << self
7
+
8
+ # Fabricate a Butterfly from Scratch
9
+ # -----------------------------------------
10
+ #
11
+ #
12
+ #
13
+ # Call with
14
+ # IB::Butterfly.fabricate IB::Option.new( symbol: :estx50, strike: 3000, expiry:'201901'),
15
+ # front: 2850, back: 3150
16
+ #
17
+ # or
18
+ # IB::Butterfly.build from: Symbols::Index.stoxx
19
+ # strike: 3000
20
+ # expiry: '201901', front: 2850, back: 3150
21
+ #
22
+ # where :strike defines the center of the Spread.
23
+ def fabricate master, front:, back:
24
+
25
+ error "fabrication is based on a master option. Please specify as first argument" unless master.is_a?(IB::Option)
26
+ strike = master.strike
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}"
30
+ if l.empty?
31
+ error "Invalid Parameters. No Contract found #{master.to_human}"
32
+ elsif l.size > 1
33
+ error "ambigous contract-specification: #{l.map(&:to_human).join(';')}"
34
+ available_trading_classes = l.map( &:trading_class ).uniq
35
+ if available_trading_classes.size >1
36
+ error "Refine Specification with trading_class: #{available_trading_classes.join('; ')} "
37
+ else
38
+ error "Respecify expiry, verification reveals #{l.size} contracts (only 1 is allowed)"
39
+ end
40
+ end
41
+
42
+ initialize_spread( master ) do | the_spread |
43
+ strikes = [front, master.strike, back]
44
+ strikes.zip([1, -2, 1]).each do |strike, ratio|
45
+ action = ratio >0 ? :buy : :sell
46
+ leg = IB::Option.new( master.attributes.merge( strike: strike )).verify!.essential
47
+ the_spread.add_leg leg, action: action, ratio: ratio.abs
48
+ end
49
+ the_spread.description = the_description( the_spread )
50
+ the_spread.symbol = master.symbol
51
+ end
52
+ end
53
+
54
+ def build from: , front:, back:, **options
55
+ 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
+ fabricate IB::Option.new( underlying_attributes), front: front, back: back
58
+ end
59
+
60
+ def the_description spread
61
+ x= [ spread.combo_legs.map(&:weight) , spread.legs.map( &:strike )].transpose
62
+ "<Butterfly #{spread.symbol} #{spread.legs.first.right}(#{x.map{|w,strike| "#{w} :#{strike} "}.join( '|+|' )} )[#{Date.parse(spread.legs.first.last_trading_day).strftime("%b %Y")}]>"
63
+ end
64
+
65
+ def defaults
66
+ super.merge expiry: IB::Symbols::Futures.next_expiry ,
67
+ right: :put
68
+ end
69
+
70
+
71
+ def requirements
72
+ super.merge back: "the strike of the lower bougth option",
73
+ front: "the strike of the upper bougth option"
74
+
75
+ end
76
+
77
+ end # class
78
+ end # module
79
+ end # module ib
@@ -0,0 +1,85 @@
1
+ module IB
2
+
3
+ module Calendar
4
+
5
+ extend SpreadPrototype
6
+ class << self
7
+
8
+
9
+ # Fabricate a Calendar-Spread from a Master-Option
10
+ # -----------------------------------------
11
+ # If one Leg is known, the other is build by just changing the expiry
12
+ # The second leg is always SOLD !
13
+ #
14
+ # Call with
15
+ # IB::Calendar.fabricate an_option, the_other_expiry
16
+ def fabricate master, the_other_expiry
17
+
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
29
+ end
30
+
31
+
32
+ # Build Vertical out of an Underlying
33
+ # -----------------------------------------
34
+ # Needed attributes: :strikes, :expiry, right
35
+ #
36
+ # Optional: :trading_class, :multiplier
37
+ #
38
+ # Call with
39
+ # IB::Calendar.build from: IB::Contract, front: an_expiry, back: an_expiry,
40
+ # right: {put or call}, strike: a_strike
41
+ def build from:, **fields
42
+ underlying = if from.is_a? IB::Option
43
+ fields[:right] = from.right unless fields.key?(:right)
44
+ fields[:front] = from.expiry unless fields.key(:front)
45
+ fields[:strike] = from.strike unless fields.key?(:strike)
46
+ fields[:expiry] = from.expiry unless fields.key?(:expiry)
47
+ fields[:trading_class] = from.trading_class unless fields.key?(:trading_class) || from.trading_class.empty?
48
+ fields[:multiplier] = from.multiplier unless fields.key?(:multiplier) || from.multiplier.to_i.zero?
49
+ details = nil; from.verify{|c| details = c.contract_detail }
50
+ IB::Contract.new( con_id: details.under_con_id,
51
+ currency: from.currency)
52
+ .verify!
53
+ .essential
54
+ else
55
+ from
56
+ end
57
+ 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)
59
+ 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]
65
+ 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
68
+ error "Initialisation of Legs failed" if the_spread.legs.size != 2
69
+ the_spread.description = the_description( the_spread )
70
+ end
71
+ end
72
+
73
+ def defaults
74
+ super.merge expiry: IB::Symbols::Futures.next_expiry,
75
+ right: :put
76
+ end
77
+
78
+
79
+ def the_description spread
80
+ 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( '|+|' )} >"
82
+ end
83
+ end # class
84
+ end # module vertical
85
+ end # module ib
@@ -0,0 +1,48 @@
1
+ module IB
2
+
3
+ module StockSpread
4
+
5
+ extend SpreadPrototype
6
+ class << self
7
+
8
+ # Fabricate a StockSpread from Scratch
9
+ # -----------------------------------------
10
+ #
11
+ #
12
+ #
13
+ # Call with
14
+ # IB::StockSpread.fabricate 'GE','F', ratio:[1,-2]
15
+ #
16
+ # or
17
+ # IB::StockSpread.fabricate IB::Stock.new(symbol:'GE'), 'F', ratio:[1,-2]
18
+ #
19
+ def fabricate *underlying, ratio: [1,-1], **args
20
+ #
21
+ are_stocks = ->(l){ l.all?{|y| y.is_a? IB::Stock} }
22
+ legs = underlying.map{|y| y.is_a?( IB::Stock ) ? y.merge(args) : IB::Stock.new( symbol: y ).merge(args)}
23
+ error "only spreads with two underyings of type »IB::Stock« are supported" unless legs.size==2 && are_stocks[legs]
24
+ initialize_spread( legs.first ) do | the_spread |
25
+ c_l = legs.zip(ratio).map do |l,r|
26
+ action = r >0 ? :buy : :sell
27
+ the_spread.add_leg l, action: action, ratio: r.abs
28
+ end
29
+ the_spread.description = the_description( the_spread )
30
+ the_spread.symbol = legs.map( &:symbol ).sort.join(",") # alphabetical order
31
+
32
+ end
33
+ end
34
+
35
+ def the_description spread
36
+ info= spread.legs.map( &:symbol ).zip(spread.combo_legs.map( &:weight ))
37
+ "<StockSpread #{info.map{|c| c.join(":")}.join(" , ")} (#{spread.currency} )>"
38
+
39
+ end
40
+
41
+ # always route a order as NonGuaranteed
42
+ def order_requirements
43
+ { combo_params: ['NonGuaranteed', true] }
44
+ end
45
+
46
+ end # class
47
+ end # module
48
+ end # module ib
@@ -0,0 +1,75 @@
1
+ module IB
2
+
3
+ module Straddle
4
+
5
+ extend SpreadPrototype
6
+ class << self
7
+
8
+
9
+ # Fabricate a Straddle from a Master-Option
10
+ # -----------------------------------------
11
+ # If one Leg is known, the other is simply build by flipping the right
12
+ #
13
+ # Call with
14
+ # IB::Spread::Straddle.fabricate an_option
15
+ def fabricate master
16
+
17
+ flip_right = ->(the_right){ the_right == :put ? :call : :put }
18
+ error "Argument must be a IB::Option" unless [ :option, :futures_option ].include?( master.sec_type )
19
+
20
+
21
+ initialize_spread( master ) do | the_spread |
22
+ the_spread.add_leg master.essential
23
+ the_spread.add_leg( master.essential.merge( right: flip_right[master.right], local_symbol: "") )
24
+ error "Initialisation of Legs failed" if the_spread.legs.size != 2
25
+ the_spread.description = the_description( the_spread )
26
+ end
27
+ end
28
+
29
+
30
+ # Build Straddle out of an Underlying
31
+ # -----------------------------------------
32
+ # Needed attributes: :strike, :expiry
33
+ #
34
+ # Optional: :trading_class, :multiplier
35
+ #
36
+ # Call with
37
+ # IB::Spread::Straddle.build from: IB::Contract, strike: a_value, expiry: yyyymmm(dd)
38
+ def build from:, ** fields
39
+ if from.is_a? IB::Option
40
+ fabricate from.merge(fields)
41
+ else
42
+ initialize_spread( from ) do | the_spread |
43
+ leg_prototype = IB::Option.new from.attributes
44
+ .slice( :currency, :symbol, :exchange)
45
+ .merge(defaults)
46
+ .merge( fields )
47
+
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 )
51
+ error "Initialisation of Legs failed" if the_spread.legs.size != 2
52
+ the_spread.description = the_description( the_spread )
53
+ end
54
+ end
55
+ end
56
+
57
+ def defaults
58
+ super.merge expiry: IB::Symbols::Futures.next_expiry
59
+ end
60
+
61
+
62
+ def requirements
63
+ super.merge strike: "the strike of both options",
64
+ expiry: "Expiry expressed as »yyyymm(dd)« (String or Integer) )"
65
+ end
66
+
67
+
68
+ def the_description spread
69
+ "<Straddle #{spread.symbol}(#{spread.legs.first.strike})[#{Date.parse(spread.legs.first.last_trading_day).strftime("%b %Y")}]>"
70
+ end
71
+
72
+
73
+ end # class
74
+ end # module combo
75
+ end # module ib
@@ -0,0 +1,96 @@
1
+ module IB
2
+
3
+ module Strangle
4
+
5
+ extend SpreadPrototype
6
+ class << self
7
+
8
+
9
+ # Fabricate a Strangle from a Master-Option
10
+ # -----------------------------------------
11
+ # If one Leg is known, the other is build by flipping the right and adjusting the strike by distance
12
+ #
13
+ # Call with
14
+ # IB::Strangle.fabricate an_option, numeric_value
15
+ def fabricate master, distance
16
+
17
+ flip_right = ->(the_right){ the_right == :put ? :call : :put }
18
+
19
+ error "Argument must be an option" unless [:option, :futures_option].include? master.sec_type
20
+
21
+
22
+ initialize_spread( master ) do | the_spread |
23
+ the_spread.add_leg master
24
+ the_spread.add_leg( master
25
+ .essential
26
+ .merge( right: flip_right[master.right],
27
+ strike: master.strike.to_f + distance.to_f ,
28
+ local_symbol: '',
29
+ con_id: 0 ) )
30
+ error "Initialisation of Legs failed" if the_spread.legs.size != 2
31
+ the_spread.description = the_description( the_spread )
32
+ end
33
+ end
34
+
35
+
36
+ # Build Strangle out of an Underlying
37
+ # -----------------------------------------
38
+ # Needed attributes: :strike, :expiry
39
+ #
40
+ # Optional: :trading_class, :multiplier
41
+ #
42
+ # Call with
43
+ # IB::Strangle.build from: IB::Contract, p: a_value, c: a_value, expiry: yyyymm(dd)
44
+ def build from:, **fields
45
+ underlying = if from.is_a? IB::Option
46
+ fields[:p] = from.strike unless fields.key?(:p) || from.right == :call
47
+ fields[:c] = from.strike unless fields.key?(:c) || from.right == :puta
48
+ fields[:expiry] = from.expiry unless fields.key?(:expiry)
49
+ fields[:trading_class] = from.trading_class unless fields.key?(:trading_class) || from.trading_class.empty?
50
+ fields[:multiplier] = from.multiplier unless fields.key?(:multiplier) || from.multiplier.to_i.zero?
51
+
52
+ details = from.verify.first.contract_detail
53
+ IB::Contract.new( con_id: details.under_con_id,
54
+ currency: from.currency,
55
+ exchange: from.exchange)
56
+ .verify.first
57
+ .essential
58
+ else
59
+ from
60
+ end
61
+ kind = { :p => fields.delete(:p), :c => fields.delete(:c) }
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: "" )
68
+
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] )
72
+ error "Initialisation of Legs failed" if the_spread.legs.size != 2
73
+ the_spread.description = the_description( the_spread )
74
+ end
75
+ end
76
+
77
+ def defaults
78
+ super.merge expiry: IB::Symbols::Futures.next_expiry
79
+ end
80
+
81
+
82
+ def requirements
83
+ super.merge p: "the strike of the put option",
84
+ c: "the strike of the call option",
85
+ expiry: "Expiry expressed as »yyyymm(dd)« (String or Integer) )"
86
+ end
87
+
88
+
89
+
90
+ def the_description spread
91
+ "<Strangle #{spread.symbol}(#{spread.legs.map(&:strike).join(",")})[#{Date.parse(spread.legs.first.last_trading_day).strftime("%b %Y")}]>"
92
+ end
93
+
94
+ end # class
95
+ end # module combo
96
+ end # module ib
@@ -0,0 +1,84 @@
1
+ module IB
2
+
3
+ module Vertical
4
+
5
+ extend SpreadPrototype
6
+ class << self
7
+
8
+
9
+ # Fabricate a Vertical from a Master-Option
10
+ # -----------------------------------------
11
+ # If one Leg is known, the other is build by flipping the right and adjusting the strike by distance
12
+ #
13
+ # Call with
14
+ # IB::Vertical.fabricate an_option, buy: {another_strike}, (or) , :sell{another_strike}
15
+ def fabricate master, buy: 0, sell: 0
16
+
17
+ error "Argument must be an option" unless [:option, :futures_option].include? master.sec_type
18
+ error "Unable to fabricate Vertical. Either :buy or :sell must be specified " if buy.zero? && sell.zero?
19
+
20
+ buy = master.strike if buy.zero?
21
+ sell = master.strike if sell.zero?
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
25
+ error "Initialisation of Legs failed" if the_spread.legs.size != 2
26
+ the_spread.description = the_description( the_spread )
27
+ end
28
+ end
29
+
30
+
31
+ # Build Vertical out of an Underlying
32
+ # -----------------------------------------
33
+ # Needed attributes: :strikes, :expiry, right
34
+ #
35
+ # Optional: :trading_class, :multiplier
36
+ #
37
+ # Call with
38
+ # IB::Straddle.build from: IB::Contract, buy: a_strike, sell: a_stike, right: {put or call}, expiry: yyyymmm(dd)
39
+ def build from:, **fields
40
+ underlying = if from.is_a? IB::Option
41
+ fields[:right] = from.right unless fields.key?(:right)
42
+ fields[:sell] = from.strike unless fields.key(:sell)
43
+ fields[:buy] = from.strike unless fields.key?(:buy)
44
+ fields[:expiry] = from.expiry unless fields.key?(:expiry)
45
+ fields[:trading_class] = from.trading_class unless fields.key?(:trading_class) || from.trading_class.empty?
46
+ fields[:multiplier] = from.multiplier unless fields.key?(:multiplier) || from.multiplier.to_i.zero?
47
+ details = from.verify.first.contract_detail
48
+ IB::Contract.new( con_id: details.under_con_id,
49
+ currency: from.currency,
50
+ exchange: from.exchange)
51
+ .verify.first
52
+ .essential
53
+ else
54
+ from
55
+ end
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)
58
+ initialize_spread( underlying ) do | the_spread |
59
+ leg_prototype = IB::Option.new underlying.attributes
60
+ .slice( :currency, :symbol, :exchange)
61
+ .merge(defaults)
62
+ .merge( fields )
63
+ .merge( local_symbol: "" )
64
+ 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
67
+ error "Initialisation of Legs failed" if the_spread.legs.size != 2
68
+ the_spread.description = the_description( the_spread )
69
+ end
70
+ end
71
+
72
+ def defaults
73
+ super.merge expiry: IB::Symbols::Futures.next_expiry,
74
+ right: :put
75
+ end
76
+
77
+
78
+ def the_description spread
79
+ x= [ spread.combo_legs.map(&:weight) , spread.legs.map( &:strike )].transpose
80
+ "<Vertical #{spread.symbol} #{spread.legs.first.right}(#{x.map{|w,strike| "#{w} :#{strike} "}.join( '|+|' )} )[#{Date.parse(spread.legs.first.last_trading_day).strftime("%b %Y")}]>"
81
+ end
82
+ end # class
83
+ end # module vertical
84
+ end # module ib