ib-api icon indicating copy to clipboard operation
ib-api copied to clipboard

Don't try to compare if decimal value is nil.

Open metrix78 opened this issue 3 years ago • 7 comments

Gem fails reading opton greeks if a decimal value is empty. Modified code to check for nils before running a comparison.

Error:

Traceback (most recent call last): > 12: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:381:in block in start_reader' 11: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:297:in process_messages' 10: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:401:in process_message' 9: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/socket.rb:101:in decode_message' 8: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:413:in block in process_message' 7: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:413:in new' 6: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:41:in initialize' 5: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:63:in load' 4: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:52:in simple_load' 3: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:73:in load_map' 2: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:73:in each' 1: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:96:in block in load_map' /home/metrix/.gems/gems/ib-api-972.5/lib/ib/support.rb:38:in read_decimal_limit_2': undefined method <=' for nil:NilClass (NoMethodError) 13: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:381:in block in start_reader' 12: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:297:in process_messages' 11: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:401:in process_message' 10: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/socket.rb:101:in decode_message' 9: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:413:in block in process_message' 8: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/connection.rb:413:in new' 7: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:41:in initialize' 6: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:63:in load' 5: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:52:in simple_load' 4: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:73:in load_map' 3: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:73:in each' 2: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:95:in block in load_map' 1: from /home/metrix/.gems/gems/ib-api-972.5/lib/ib/messages/incoming/abstract_message.rb:98:in rescue in block in load_map' /home/metrix/.gems/gems/ib-api-972.5/lib/ib/errors.rb:43:in error': Reading IB::Messages::Incoming::TickOption: NoMethodError: undefined method `<=' for nil:NilClass --> Instruction: vega (IB::TransmissionError)

metrix78 avatar Jul 19 '22 04:07 metrix78

Hi, thanks for exploring this.

Question? Why returned read_float nil? Does this indicate a read-error? Then it should raise a IB::TransmissionError! If the tws may return nil on this field, I prefer to extend read_float to accept nil-values, ie. create a method read_float_or_nil.

topofocus avatar Jul 20 '22 07:07 topofocus

Does this indicate a read-error? Then it should raise a IB::TransmissionError!

These are valid option contracts from TWS that are causing the library to crash.

I prefer to extend read_float to accept nil-values, ie. create a method read_float_or_nil.

I can do that, but it looks like empty values are returned for every location that uses decimal_limit. See below:

Uses of decimal_limit_1:

rg decimal_limit_1 support.rb 41: def read_decimal_limit_1

messages/incoming/ticks.rb 121: %i[implied_volatility decimal_limit_1], # -1 and below 123: %i[option_price decimal_limit_1], # -1 -"- 124: %i[pv_dividend decimal_limit_1], # -1 -"- 128: %i[under_price decimal_limit_1]) do

Uses of decimal_limit_2:

rg decimal_limit_2 support.rb 50: def read_decimal_limit_2

messages/incoming/ticks.rb 122: %i[delta decimal_limit_2], # -2 and below 125: %i[gamma decimal_limit_2], # -2 -"- 126: %i[vega decimal_limit_2], # -2 -"- 127: %i[theta decimal_limit_2], # -2 -"-

Example message parsed into a hash: {:class_name=>"TickOption", :class_name_full=>"IB::Messages::Incoming::TickOption", :type=>:delayed_bid_option, :ticker_id=>18, :tick_type=>80, :the_data=>{:tick_type=>80, :implied_volatility=>nil, :delta=>nil, :option_price=>nil, :pv_dividend=>0.0, :gamma=>nil, :vega=>nil, :theta=>nil, :under_price=>7.234678745269775}, :symbol=>"INTT", :expiry=>"20221216", :strike=>10.0, :right=>:call, :greek=>nil, :time=>1658298775}

Every call to decimal_limit_1 or decimal_limit_2 can be empty

metrix78 avatar Jul 20 '22 16:07 metrix78

After re-reading your comment, I think I see what you're saying.

You would like read_float to return a valid integer other than blank if the data is valid?

In this case I would l think an empty string, or nil would be the best option. It wouldn't make sense to return a 0 for a greek.
My point of view is that nil is the correct value to respond with as we don't know what the value is.

metrix78 avatar Jul 20 '22 16:07 metrix78

if nil (or blank) is a valid data received from the tws, read_float is the wrong method to capture the input. Then I see two options: use a different read_xyz method or use read_float and handle IB::TransmissionError in the calling method. read_xyz are low-level methods to capture the datastream. We are dealing with uncertain WAN-data. On this level the flexibility of ruby is an disadvantage.

Can you write a small test to work on this feature? (or explain the error on detail, then I write it ) Could be a hidden runtime-error of ib-api.

topofocus avatar Jul 20 '22 16:07 topofocus

What interface do you need data for a test? Directly from the TCPSocket? or data formatted between a specific method call. I'll see if I can find a way to capture a message from the TCP socket today or tomorrow.

I was fixing this bug for a bit of understanding on how the development process works on this project. I've found a bigger issue that will cause the application to crash when two messages are ready to read from the TCPSocket recvfrom method. I have a proof of concept to fix it, but it really needs some more work.

metrix78 avatar Jul 21 '22 13:07 metrix78

If you want, lets focus on the issues together. Either by mail ([email protected]) or via signal +49 176 47279326. I'm free this evening (european time).

topofocus avatar Jul 21 '22 13:07 topofocus

There are a few in-situ message tests in spec/ib/messages. They may act as prototype.

topofocus avatar Jul 22 '22 03:07 topofocus