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