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.
- 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,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
|