ib-api 972.0 → 972.4
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 +4 -4
- data/Gemfile.lock +36 -37
- data/README.md +48 -3
- data/VERSION +1 -1
- data/api.gemspec +1 -1
- data/bin/console +4 -8
- data/changelog.md +12 -0
- data/lib/ib/base_properties.rb +3 -4
- data/lib/ib/connection.rb +18 -16
- data/lib/ib/logger.rb +1 -1
- data/lib/ib/messages/incoming.rb +1 -1
- data/lib/ib/messages/incoming/abstract_message.rb +7 -7
- data/lib/ib/messages/incoming/account_value.rb +5 -1
- data/lib/ib/messages/incoming/contract_data.rb +0 -2
- data/lib/ib/messages/incoming/historical_data.rb +25 -5
- data/lib/ib/messages/incoming/ticks.rb +21 -60
- data/lib/ib/messages/outgoing.rb +4 -2
- data/lib/ib/messages/outgoing/abstract_message.rb +3 -3
- data/lib/ib/messages/outgoing/bar_requests.rb +4 -5
- data/lib/ib/messages/outgoing/request_marketdata.rb +10 -7
- data/lib/ib/models.rb +1 -1
- data/lib/ib/support.rb +32 -15
- data/lib/logging.rb +45 -0
- data/lib/models/ib/account.rb +0 -13
- data/lib/models/ib/bag.rb +7 -1
- data/lib/models/ib/bar.rb +1 -1
- data/lib/models/ib/combo_leg.rb +22 -0
- data/lib/models/ib/contract.rb +44 -32
- data/lib/models/ib/contract_detail.rb +13 -7
- data/lib/models/ib/index.rb +1 -1
- data/lib/models/ib/option.rb +8 -2
- data/lib/models/ib/option_detail.rb +19 -3
- data/lib/models/ib/order.rb +5 -0
- data/lib/models/ib/spread.rb +168 -0
- data/lib/models/ib/stock.rb +9 -3
- data/lib/models/ib/underlying.rb +4 -1
- data/lib/requires.rb +10 -3
- metadata +9 -20
- data/example/README.md +0 -76
- data/example/account_info +0 -54
- data/example/account_positions +0 -30
- data/example/account_summary +0 -88
- data/example/cancel_orders +0 -74
- data/example/fa_accounts +0 -25
- data/example/fundamental_data +0 -40
- data/example/historic_data_cli +0 -186
- data/example/list_orders +0 -45
- data/example/portfolio_csv +0 -81
- data/example/scanner_data +0 -62
- data/example/template +0 -19
- data/example/tick_data +0 -28
data/lib/models/ib/combo_leg.rb
CHANGED
@@ -83,6 +83,28 @@ module IB
|
|
83
83
|
].flatten
|
84
84
|
end
|
85
85
|
|
86
|
+
|
87
|
+
# fields are generated by serialize(:extended)
|
88
|
+
# i.e.
|
89
|
+
# z= Strangle.build from: Symbols::Index.stoxx, p: 3700, c: 4000, expiry: 202106
|
90
|
+
# zc= z.combo_legs.serialize :extended
|
91
|
+
# => [[321584786, 1, "BUY", "DTB", 0, 0, "", -1], [321584637, 1, "BUY", "DTB", 0, 0, "", -1]]
|
92
|
+
# nz = zc.map{|o| ComboLeg.build *o }
|
93
|
+
# zc.map{|o| ComboLeg.build o } => # is equivalent
|
94
|
+
# => [#<IB::ComboLeg:0x0000000001c36bc0 @attributes={:con_id=>321584786, :ratio=>1, :side=>"B", :exchange=>"DTB", ...
|
95
|
+
# nz.first == z.combo_legs.first => true
|
96
|
+
#
|
97
|
+
def self.build *fields
|
98
|
+
self.new Hash[[:con_id,
|
99
|
+
:ratio,
|
100
|
+
:side, # reverse to_sup?
|
101
|
+
:exchange,
|
102
|
+
:open_close,
|
103
|
+
:short_sale_slot,
|
104
|
+
:designated_location,
|
105
|
+
:exempt_code].zip fields]
|
106
|
+
end
|
107
|
+
|
86
108
|
def to_human
|
87
109
|
"<ComboLeg: #{side} #{ratio} con_id #{con_id} at #{exchange}>"
|
88
110
|
end
|
data/lib/models/ib/contract.rb
CHANGED
@@ -4,7 +4,14 @@ require 'models/ib/underlying'
|
|
4
4
|
|
5
5
|
|
6
6
|
module IB
|
7
|
-
|
7
|
+
|
8
|
+
if defined?(Contract)
|
9
|
+
#Connection.current.logger.warn "Contract already a #{defined?(Contract)}"
|
10
|
+
|
11
|
+
# puts Contract.ancestors
|
12
|
+
# IB.send(:remove_const, 'Contract')
|
13
|
+
end
|
14
|
+
class Contract < IB::Model
|
8
15
|
include BaseProperties
|
9
16
|
|
10
17
|
# Fields are Strings unless noted otherwise
|
@@ -113,7 +120,7 @@ module IB
|
|
113
120
|
|
114
121
|
def default_attributes # :nodoc:
|
115
122
|
super.merge :con_id => 0,
|
116
|
-
:strike =>
|
123
|
+
:strike => "",
|
117
124
|
:right => :none, # Not an option
|
118
125
|
# :exchange => 'SMART',
|
119
126
|
:include_expired => false
|
@@ -130,13 +137,13 @@ module IB
|
|
130
137
|
|
131
138
|
def serialize *fields # :nodoc:
|
132
139
|
print_default = ->(field, default="") { field.blank? ? default : field }
|
133
|
-
print_not_zero = ->(field, default="") { field.to_i.zero? ? default : field }
|
134
140
|
[(con_id.present? && !con_id.is_a?(Symbol) && con_id.to_i > 0 ? con_id : ""),
|
135
141
|
print_default[symbol],
|
136
142
|
print_default[self[:sec_type]],
|
137
143
|
( fields.include?(:option) ?
|
138
144
|
[ print_default[expiry],
|
139
|
-
|
145
|
+
## a Zero-Strike-Option has to be defined with «strike: -1 »
|
146
|
+
strike.present? && ( strike.is_a?(Numeric) && !strike.zero? && strike > 0 ) ? strike : strike<0 ? 0 : "",
|
140
147
|
print_default[self[:right]],
|
141
148
|
print_default[multiplier]] : nil ),
|
142
149
|
print_default[exchange],
|
@@ -211,17 +218,22 @@ module IB
|
|
211
218
|
# the link to contract-details is __not__ maintained.
|
212
219
|
def essential
|
213
220
|
|
214
|
-
|
215
|
-
the_attributes = [ :symbol , :con_id, :exchange,
|
221
|
+
the_attributes = [ :sec_type, :symbol , :con_id, :exchange, :right,
|
216
222
|
:currency, :expiry, :strike, :local_symbol, :last_trading_day,
|
217
|
-
:multiplier, :primary_exchange, :trading_class ]
|
218
|
-
|
219
|
-
|
220
|
-
|
223
|
+
:multiplier, :primary_exchange, :trading_class, :description ]
|
224
|
+
new_contract= self.class.new invariant_attributes.select{|k,_| the_attributes.include? k }.compact
|
225
|
+
new_contract[:description] = if @description.present?
|
226
|
+
@description
|
227
|
+
elsif contract_detail.present?
|
228
|
+
contract_detail.long_name
|
229
|
+
else
|
230
|
+
""
|
231
|
+
end
|
232
|
+
new_contract # return contract
|
221
233
|
end
|
222
234
|
|
223
235
|
|
224
|
-
# creates a new Contract substituting attributes by the
|
236
|
+
# creates a new Contract substituting attributes by the provided key-value pairs.
|
225
237
|
#
|
226
238
|
# con_id is resetted
|
227
239
|
def merge **new_attributes
|
@@ -327,6 +339,10 @@ module IB
|
|
327
339
|
self[:sec_type] == 'IND'
|
328
340
|
end
|
329
341
|
|
342
|
+
|
343
|
+
def verify # :nodoc:
|
344
|
+
error "verify must be overloaded. Please require at least `ib/verify` from the `ib-extenstions` gem "
|
345
|
+
end
|
330
346
|
=begin
|
331
347
|
From the release notes of TWS 9.50
|
332
348
|
|
@@ -364,20 +380,33 @@ In places where these terms are used to indicate a concept, we have left them as
|
|
364
380
|
|
365
381
|
|
366
382
|
### Now let's deal with Contract subclasses
|
383
|
+
begin
|
367
384
|
|
368
|
-
|
385
|
+
require_relative 'option'
|
369
386
|
require 'models/ib/bag'
|
370
387
|
require 'models/ib/forex'
|
371
388
|
require 'models/ib/future'
|
372
389
|
require 'models/ib/stock'
|
373
390
|
require 'models/ib/index'
|
391
|
+
### walkaraound to enable spreads with orientdb
|
392
|
+
if IB::const_defined? :Spread
|
393
|
+
IB::send(:remove_const, :Spread)
|
394
|
+
#puts "Spread already defined"
|
395
|
+
#puts "erasing"
|
396
|
+
end
|
397
|
+
require 'models/ib/spread.rb'
|
398
|
+
end
|
399
|
+
|
400
|
+
|
374
401
|
|
375
402
|
class Contract
|
376
403
|
# Contract subclasses representing specialized security types.
|
404
|
+
using IBSupport
|
377
405
|
|
378
406
|
Subclasses = Hash.new(Contract)
|
379
407
|
Subclasses[:bag] = IB::Bag
|
380
408
|
Subclasses[:option] = IB::Option
|
409
|
+
Subclasses[:futures_option] = IB::FutureOption
|
381
410
|
Subclasses[:future] = IB::Future
|
382
411
|
Subclasses[:stock] = IB::Stock
|
383
412
|
Subclasses[:forex] = IB::Forex
|
@@ -385,31 +414,14 @@ In places where these terms are used to indicate a concept, we have left them as
|
|
385
414
|
|
386
415
|
|
387
416
|
# This builds an appropriate Contract subclass based on its type
|
388
|
-
|
389
|
-
|
417
|
+
#
|
418
|
+
# the method is also used to copy Contract.values to new instances
|
390
419
|
def self.build opts = {}
|
391
420
|
subclass =( VALUES[:sec_type][opts[:sec_type]] || opts['sec_type'] || opts[:sec_type]).to_sym
|
392
421
|
Contract::Subclasses[subclass].new opts
|
393
422
|
end
|
394
423
|
|
395
|
-
|
396
|
-
def self.from_ib_ruby
|
397
|
-
keys = [:con_id, :symbol, :sec_type, :expiry, :strike, :right, :multiplier,
|
398
|
-
:exchange, :primary_exchange, :currency, :local_symbol]
|
399
|
-
props = Hash[keys.zip(string.split(":"))]
|
400
|
-
props.delete_if { |k, v| v.nil? || v.empty? }
|
401
|
-
Contract.build props
|
402
|
-
end
|
424
|
+
|
403
425
|
end # class Contract
|
404
426
|
end # module IB
|
405
427
|
|
406
|
-
class String
|
407
|
-
def to_contract
|
408
|
-
keys = [:con_id, :symbol, :sec_type, :expiry, :strike, :right, :multiplier,
|
409
|
-
:exchange, :primary_exchange, :currency, :local_symbol]
|
410
|
-
props = Hash[keys.zip(split(":"))]
|
411
|
-
props.delete_if { |k, v| v.nil? || v.empty? }
|
412
|
-
IB::Contract.build props
|
413
|
-
|
414
|
-
end
|
415
|
-
end
|
@@ -95,13 +95,19 @@ module IB
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def to_human
|
98
|
-
ret = "<ContractDetails #{long_name},
|
99
|
-
ret << "
|
100
|
-
ret << "
|
101
|
-
|
102
|
-
|
103
|
-
ret <<"
|
104
|
-
ret <<"
|
98
|
+
ret = "<ContractDetails #{long_name}, "
|
99
|
+
ret << "--> #{market_name}, " if market_name.present?
|
100
|
+
ret << "/C/ #{category}, /I/ #{industry} /SC/ #{subcategory}, " if category.present?
|
101
|
+
ret << "Underlying:#{under_symbol}[#{under_sec_type}](#{under_con_id}), " unless under_con_id.zero?
|
102
|
+
ret << "ev_multiplier:#{ev_multiplier}, " if ev_multiplier.present?
|
103
|
+
ret << "convertible:#{convertible}, " if convertible
|
104
|
+
ret << "coupon:#{coupon}, " if coupon.present? && coupon > 0
|
105
|
+
ret << "md_size_multiplier:#{md_size_multiplier}, min_tick:#{min_tick}, "
|
106
|
+
ret << "next_option_partial:#{next_option_partial}, " if next_option_partial.present?
|
107
|
+
ret << "price_magnifier:#{price_magnifier}, "
|
108
|
+
ret << "puttable:#{puttable}, " if puttable.present?
|
109
|
+
ret << "sec_id-list:#{sec_id_list}, " unless sec_id_list.empty?
|
110
|
+
ret <<"valid exchanges: #{ valid_exchanges}; order types: #{order_types} >"
|
105
111
|
end
|
106
112
|
|
107
113
|
end # class ContractDetail
|
data/lib/models/ib/index.rb
CHANGED
data/lib/models/ib/option.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
#require_relative 'contract'
|
2
|
+
require_relative 'option_detail'
|
3
3
|
|
4
4
|
module IB
|
5
5
|
class Option < Contract
|
@@ -75,4 +75,10 @@ module IB
|
|
75
75
|
end
|
76
76
|
|
77
77
|
end # class Option
|
78
|
+
|
79
|
+
class FutureOption < Option
|
80
|
+
def default_attributes
|
81
|
+
super.merge :sec_type => :futures_option
|
82
|
+
end
|
83
|
+
end
|
78
84
|
end # module IB
|
@@ -17,7 +17,8 @@ module IB
|
|
17
17
|
:next_strike,
|
18
18
|
:prev_expiry,
|
19
19
|
:next_expiry,
|
20
|
-
:option_price
|
20
|
+
:option_price,
|
21
|
+
:updated_at
|
21
22
|
belongs_to :option
|
22
23
|
|
23
24
|
# returns true if all datafields are filled with reasonal data
|
@@ -32,19 +33,34 @@ module IB
|
|
32
33
|
|
33
34
|
def greeks?
|
34
35
|
fields= [ :delta, :gamma, :vega, :theta,
|
35
|
-
:implied_volatility
|
36
|
+
:implied_volatility]
|
36
37
|
|
37
38
|
!fields.detect{|y| self.send(y).nil?}
|
38
39
|
|
39
40
|
end
|
40
41
|
|
42
|
+
def prices?
|
43
|
+
fields = [:implied_volatility, :under_price, :option_price]
|
44
|
+
!fields.detect{|y| self.send(y).nil?}
|
45
|
+
end
|
46
|
+
|
47
|
+
def iv
|
48
|
+
implied_volatility
|
49
|
+
end
|
50
|
+
|
51
|
+
def spread
|
52
|
+
bid_price - ask_price
|
53
|
+
end
|
54
|
+
|
41
55
|
def to_human
|
42
56
|
outstr= ->( item ) { if item.nil? then "--" else sprintf("%g" , item) end }
|
43
57
|
att = " optionPrice: #{ outstr[ option_price ]}, UnderlyingPrice: #{ outstr[ under_price] } impl.Vola: #{ outstr[ implied_volatility ]} ; dividend: #{ outstr[ pv_dividend ]}; "
|
44
58
|
greeks = "Greeks:: delta: #{ outstr[ delta ] }; gamma: #{ outstr[ gamma ]}, vega: #{ outstr[ vega ] }; theta: #{ outstr[ theta ]}"
|
45
59
|
prices= " close: #{ outstr[ close_price ]}; bid: #{ outstr[ bid_price ]}; ask: #{ outstr[ ask_price ]} "
|
46
60
|
if complete?
|
47
|
-
|
61
|
+
"< "+ prices + "\n" + att + "\n" + greeks + " >"
|
62
|
+
elsif prices?
|
63
|
+
"< " + att + greeks + " >"
|
48
64
|
else
|
49
65
|
"< " + greeks + " >"
|
50
66
|
end
|
data/lib/models/ib/order.rb
CHANGED
@@ -514,6 +514,11 @@ Format of serialisation
|
|
514
514
|
(account ? "/#{account}" : '') +
|
515
515
|
(commission ? " fee #{commission}" : '') + ">"
|
516
516
|
end
|
517
|
+
def serialize_rabbit
|
518
|
+
{ 'Contract' => contract.present? ? contract.serialize( :option, :trading_class ): '' ,
|
519
|
+
'Order' => self,
|
520
|
+
'OrderState' => order_state}
|
521
|
+
end
|
517
522
|
|
518
523
|
end # class Order
|
519
524
|
end # module IB
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# require 'ib/verify'
|
2
|
+
module IB
|
3
|
+
if defined?(Spread)
|
4
|
+
puts "Bag already a #{defined?(Spread)}"
|
5
|
+
|
6
|
+
# puts Spread.ancestors
|
7
|
+
IB.send(:remove_const, 'Spread')
|
8
|
+
end
|
9
|
+
class Spread < Bag
|
10
|
+
has_many :legs
|
11
|
+
|
12
|
+
using IBSupport
|
13
|
+
|
14
|
+
=begin
|
15
|
+
Parameters: front: YYYMM(DD)
|
16
|
+
back: {n}w, {n}d or YYYYMM(DD)
|
17
|
+
|
18
|
+
Adds (or substracts) relative (back) measures to the front month, just passes absolute YYYYMM(DD) value
|
19
|
+
|
20
|
+
front: 201809 back: 2m (-1m) --> 201811 (201808)
|
21
|
+
front: 20180908 back: 1w (-1w) --> 20180918 (20180902)
|
22
|
+
=end
|
23
|
+
|
24
|
+
def transform_distance front, back
|
25
|
+
# Check Format of back: 201809 --> > 200.000
|
26
|
+
# 20180989 ---> 20.000.000
|
27
|
+
start_date = front.to_i < 20000000 ? Date.strptime(front.to_s,"%Y%m") : Date.strptime(front.to_s,"%Y%m%d")
|
28
|
+
nb = if back.to_i > 200000
|
29
|
+
back.to_i
|
30
|
+
elsif back[-1] == "w" && front.to_i > 20000000
|
31
|
+
start_date + (back.to_i * 7)
|
32
|
+
elsif back[-1] == "m" && front.to_i > 200000
|
33
|
+
start_date >> back.to_i
|
34
|
+
else
|
35
|
+
error "Wrong date #{back} required format YYYMM, YYYYMMDD ord {n}w or {n}m"
|
36
|
+
end
|
37
|
+
if nb.is_a?(Date)
|
38
|
+
if back[-1]=='w'
|
39
|
+
nb.strftime("%Y%m%d")
|
40
|
+
else
|
41
|
+
nb.strftime("%Y%m")
|
42
|
+
end
|
43
|
+
else
|
44
|
+
nb
|
45
|
+
end
|
46
|
+
end # def
|
47
|
+
|
48
|
+
def to_human
|
49
|
+
self.description
|
50
|
+
end
|
51
|
+
|
52
|
+
def calculate_spread_value( array_of_portfolio_values )
|
53
|
+
array_of_portfolio_values.map{|x| x.send yield }.sum if block_given?
|
54
|
+
end
|
55
|
+
|
56
|
+
def fake_portfolio_position( array_of_portfolio_values )
|
57
|
+
calculate_spread_value= ->( a_o_p_v, attribute ) do
|
58
|
+
a_o_p_v.map{|x| x.send attribute }.sum
|
59
|
+
end
|
60
|
+
ar=array_of_portfolio_values
|
61
|
+
IB::PortfolioValue.new contract: self,
|
62
|
+
average_cost: calculate_spread_value[ar, :average_cost],
|
63
|
+
market_price: calculate_spread_value[ar, :market_price],
|
64
|
+
market_value: calculate_spread_value[ar, :market_value],
|
65
|
+
unrealized_pnl: calculate_spread_value[ar, :unrealized_pnl],
|
66
|
+
realized_pnl: calculate_spread_value[ar, :realized_pnl],
|
67
|
+
position: 0
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# adds a leg to any spread
|
73
|
+
#
|
74
|
+
# Parameter:
|
75
|
+
# contract: Will be verified. Contract.essential is added to legs-array
|
76
|
+
# action: :buy or :sell
|
77
|
+
# weight:
|
78
|
+
# ratio:
|
79
|
+
#
|
80
|
+
# Default: action: :buy, weight: 1
|
81
|
+
|
82
|
+
def add_leg contract, **leg_params
|
83
|
+
evaluated_contracts = []
|
84
|
+
nc = contract.verify.first.essential
|
85
|
+
# weigth = 1 --> sets Combo.side to buy and overwrites the action statement
|
86
|
+
# leg_params[:weight] = 1 unless leg_params.key?(:weight) || leg_params.key?(:ratio)
|
87
|
+
if nc.is_a?( IB::Contract) && nc.con_id.present?
|
88
|
+
the_leg= ComboLeg.new( nc.attributes.slice( :con_id, :exchange )
|
89
|
+
.merge( leg_params ))
|
90
|
+
self.combo_legs << the_leg
|
91
|
+
self.description = "#{description.nil? ? "": description} added #{nc.to_human}" rescue "Spread: #{nc.to_human}"
|
92
|
+
self.legs << nc
|
93
|
+
end
|
94
|
+
self # return value to enable chaining
|
95
|
+
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
# removes the contract from the spread definition
|
100
|
+
#
|
101
|
+
def remove_leg contract
|
102
|
+
contract.verify do |c|
|
103
|
+
legs.delete_if { |x| x.con_id == c.con_id }
|
104
|
+
combo_legs.delete_if { |x| x.con_id == c.con_id }
|
105
|
+
self.description = description + " removed #{c.to_human}"
|
106
|
+
end
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
110
|
+
# essentail
|
111
|
+
# effectivley clones the object
|
112
|
+
#
|
113
|
+
def essential
|
114
|
+
the_es = self.class.new invariant_attributes
|
115
|
+
the_es.legs = legs.map{|y| IB::Contract.build y.invariant_attributes}
|
116
|
+
the_es.combo_legs = combo_legs.map{|y| IB::ComboLeg.new y.invariant_attributes }
|
117
|
+
the_es.description = description
|
118
|
+
the_es # return
|
119
|
+
end
|
120
|
+
|
121
|
+
def multiplier
|
122
|
+
(legs.map(&:multiplier).sum/legs.size).to_i
|
123
|
+
end
|
124
|
+
|
125
|
+
# provide a negative con_id
|
126
|
+
def con_id
|
127
|
+
if attributes[:con_id].present? && attributes[] < 0
|
128
|
+
attributes[:con_id]
|
129
|
+
else
|
130
|
+
-legs.map{ |x| x.is_a?(String) ? x.expand.con_id : x.con_id}.sum
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def non_guaranteed= x
|
136
|
+
super.merge combo_params: [ ['NonGuaranteed', x] ]
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
def non_guaranteed
|
141
|
+
combo_params['NonGuaranteed']
|
142
|
+
end
|
143
|
+
# optional: specify default order prarmeters for all spreads
|
144
|
+
# def order_requirements
|
145
|
+
# super.merge symbol: symbol
|
146
|
+
# end
|
147
|
+
|
148
|
+
|
149
|
+
def self.build_from_json container
|
150
|
+
read_leg = ->(a) do
|
151
|
+
IB::ComboLeg.new :con_id => a.read_int,
|
152
|
+
:ratio => a.read_int,
|
153
|
+
:action => a.read_string,
|
154
|
+
:exchange => a.read_string
|
155
|
+
|
156
|
+
end
|
157
|
+
object= self.new container['Spread'].clone.read_contract
|
158
|
+
object.legs = container['legs'].map{|x| IB::Contract.build x.clone.read_contract}
|
159
|
+
object.combo_legs = container['combo_legs'].map{ |x| read_leg[ x.clone ] }
|
160
|
+
object.description = container['misc'].clone.read_string
|
161
|
+
object
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
end
|