ib-extensions 1.0

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