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
         |