Skip to content

Commit

Permalink
option_data script now working
Browse files Browse the repository at this point in the history
  • Loading branch information
arvicco committed Sep 19, 2011
1 parent 9656f3a commit cecade4
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 36 deletions.
4 changes: 4 additions & 0 deletions HISTORY
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,7 @@
== 0.4.16 / 2011-09-19

* Execution Model added

== 0.4.17 / 2011-09-19

* option_data script now working
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.16
0.4.17
2 changes: 2 additions & 0 deletions bin/contract_details
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ require 'ib-ruby'
# corresponds to what symbol ourselves, because the ticks don't include any other
# identifying information. The choice of ticker ids is, as far as I can tell, arbitrary.
@market = {123 => IB::Symbols::Stocks[:wfc],
125 => IB::Symbols::Options[:wfc15],
129 => IB::Symbols::Stocks[:wrong]}

# Connect to IB TWS.
Expand All @@ -27,6 +28,7 @@ ib.subscribe(IB::Messages::Incoming::Alert) { |msg| puts msg.to_human }
# message as its argument. In this case, we just print out the data.
ib.subscribe(IB::Messages::Incoming::ContractData) do |msg|
puts msg.contract.inspect

end

# Now we actually request historical data for the symbols we're interested in. TWS will
Expand Down
59 changes: 59 additions & 0 deletions bin/option_data
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env ruby
#
# This script connects to IB API and subscribes to market data for specific symbols

require 'pathname'
LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
$LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)

require 'rubygems'
require 'bundler/setup'
require 'ib-ruby'

# Definition of what we want market data for. We have to keep track of what ticker id
# corresponds to what symbol ourselves, because the ticks don't include any other
# identifying information. The choice of ticker ids is, as far as I can tell, arbitrary.
@market = {123 => IB::Symbols::Options[:wfc20],
125 => IB::Symbols::Options[:z50]}

# First, connect to IB TWS.
ib = IB::Connection.new

## Subscribe to TWS alerts/errors
ib.subscribe(IB::Messages::Incoming::Alert) { |msg| puts msg.to_human }

# Subscribe to TickerPrice and TickerSize events. The code passed in the block will
# be executed when a message of that type is received, with the received message as its
# argument. In this case, we just print out the tick.
#
# Note that we have to look the ticker id of each incoming message
# up in local memory to figure out what it's for.
#
# (N.B. The description field is not from IB TWS. It is defined
# locally in forex.rb, and is just arbitrary text.)
ib.subscribe(IB::Messages::Incoming::TickPrice) do |msg|
puts @market[msg.data[:id]].description + ": " + msg.to_human
end

ib.subscribe(IB::Messages::Incoming::TickSize) do |msg|
puts @market[msg.data[:id]].description + ": " + msg.to_human
end

ib.subscribe(IB::Messages::Incoming::TickOption) do |msg|
puts @market[msg.data[:id]].description + ": " + msg.to_human
end

# Now we actually request market data for the symbols we're interested in.
@market.each_pair do |id, contract|
ib.send IB::Messages::Outgoing::RequestMarketData.new :id => id,
:contract => contract
end

puts "\nSubscribed to market data"
puts "\n******** Press <Enter> to cancel... *********\n\n"
gets
puts "Cancelling market data subscription.."

@market.each_pair do |id, contract|
ib.send IB::Messages::Outgoing::CancelMarketData.new :id => id
end
5 changes: 3 additions & 2 deletions lib/ib-ruby/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,9 @@ def reader
msg_id = @server[:socket].read_int

# Debug:
puts "Got message #{msg_id} (#{Messages::Incoming::Table[msg_id]})" unless [1, 2, 4, 6, 7, 8, 9, 53].include? msg_id

unless [1, 2, 4, 6, 7, 8, 9, 21, 53].include? msg_id
puts "Got message #{msg_id} (#{Messages::Incoming::Table[msg_id]})"
end

# Create a new instance of the appropriate message type, and have it read the message.
# NB: Failure here usually means unsupported message type received
Expand Down
62 changes: 29 additions & 33 deletions lib/ib-ruby/messages/incoming.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,24 @@ def load_map(*map)
end
end # class AbstractMessage

class AbstractTick < AbstractMessage
# Returns Symbol with a meaningful name for received tick type
def type
TICK_TYPES[@data[:tick_type]]
end

def to_human
"<#{self.class.to_s.split('::').last} #{type}:" +
@data.map do |key, value|
" #{key} #{value}" unless [:version, :id, :tick_type].include?(key)
end.compact.join(',') + " >"
end
end

# Macro that defines short message classes using a one-liner
def self.def_message message_id, *keys
Class.new(AbstractMessage) do
base = keys.first.is_a?(Class) ? keys.shift : AbstractMessage
Class.new(base) do
@message_id = message_id

define_method(:load) do
Expand Down Expand Up @@ -230,36 +245,22 @@ def to_human
# IB then emits at most 2 events on eWrapper:
# tickPrice( tickerId, tickType, price, canAutoExecute)
# tickSize( tickerId, sizeTickType, size)
TickPrice = def_message 1, [:id, :int], # ticker_id
TickPrice = def_message 1, AbstractTick,
[:id, :int], # ticker_id
[:tick_type, :int],
[:price, :decimal],
[:size, :int],
[:can_auto_execute, :int]
class TickPrice
# Returns Symbol with a meaningful name for received tick type
def type
TICK_TYPES[@data[:tick_type]]
end

def to_human
"<Tick #{type}: price #{@data[:price]} size #{@data[:size]}>"
end
end


TickSize = def_message 2, [:id, :int], # ticker_id
TickSize = def_message 2, AbstractTick,
[:id, :int], # ticker_id
[:tick_type, :int],
[:size, :int]
class TickSize
# Returns Symbol with a meaningful name for received tick type
def type
TICK_TYPES[@data[:tick_type]]
end

def to_human
"<TickSize #{type}: size #{@data[:size]}>"
end
end
TickString = def_message 46, AbstractTick,
[:id, :int], # ticker_id
[:tick_type, :int],
[:value, :string]

# This message is received when the market in an option or its underlier moves.
# TWS’s option model volatilities, prices, and deltas, along with the present
Expand All @@ -276,11 +277,8 @@ def to_human
# :vega - The option vega value.
# :theta - The option theta value.
# :under_price - The price of the underlying.
class TickOption
# Returns Symbol with a meaningful name for received tick type
def type
TICK_TYPES[@data[:tick_type]]
end
class TickOption < AbstractTick
@message_id = 21

# Read @data[key] if it was computed (received value above limit)
# Leave @data[key] nil if received value below limit ("not yet computed" indicator)
Expand All @@ -296,10 +294,8 @@ def load
@data[:tick_type] = @socket.read_int
read_computed :implied_volatility, 0 #-1 is the "not yet computed" indicator
read_computed :delta, -1 # -2 is the "not yet computed" indicator
if type == :model_option
read_computed :option_price, 0 # -1 is the "not yet computed" indicator
read_computed :pv_dividend, 0 # -1 is the "not yet computed" indicator
end
read_computed :option_price, 0 # -1 is the "not yet computed" indicator
read_computed :pv_dividend, 0 # -1 is the "not yet computed" indicator
read_computed :gamma, -1 # -2 is the "not yet computed" indicator
read_computed :vega, -1 # -2 is the "not yet computed" indicator
read_computed :theta, -1 # -2 is the "not yet computed" indicator
Expand All @@ -319,7 +315,7 @@ def to_human
# deliver system alerts and additional (non-error) info from TWS.
# It has additional accessors: #code and #message, derived from @data
Alert = def_message 4, [:id, :int], [:code, :int], [:message, :string]
class Alert < AbstractMessage
class Alert
def code
@data && @data[:code]
end
Expand Down
1 change: 1 addition & 0 deletions lib/ib-ruby/symbols.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ module Symbols
require 'ib-ruby/symbols/forex'
require 'ib-ruby/symbols/futures'
require 'ib-ruby/symbols/stocks'
require 'ib-ruby/symbols/options'
30 changes: 30 additions & 0 deletions lib/ib-ruby/symbols/options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Stock contracts definitions
#
# Note that the :description field is particular to ib-ruby, and is NOT part of the
# standard TWS API. It is never transmitted to IB. It's purely used clientside, and
# you can store any arbitrary string that you may find useful there.

module IB
module Symbols

Options =
{:wfc20 => Models::Contract.new(:symbol => "WFC",
:exchange => "SMART",
#:currency => "USD",
:expiry => "201110",
:right => "CALL",
:strike => 20.0,
:sec_type => Models::Contract::SECURITY_TYPES[:option],
:description => "Wells Fargo 20 Call 2011-10"),
:z50 => Models::Contract.new(:symbol => "Z",
:exchange => "LIFFE",
#:currency => "USD",
:expiry => "201110",
:right => "CALL",
:strike => 50.0,
:sec_type => Models::Contract::SECURITY_TYPES[:option],
:description => " FTSE-100 index 50 Call 2011-10"),

}
end
end

0 comments on commit cecade4

Please sign in to comment.