Skip to content

Commit

Permalink
Merge pull request ib-ruby#51 from arvicco/master
Browse files Browse the repository at this point in the history
FLEX report example
  • Loading branch information
arvicco committed Oct 24, 2012
2 parents 816ae25 + edc3753 commit 9b48dc2
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ tmtags
*.iml

## PROJECT::GENERAL
config/flex.yml
coverage
data
rdoc
Expand Down
1 change: 0 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ rescue LoadError => e
puts "gem install standalone_migrations to get db:migrate:* tasks! (Error: #{e})"
end


# rake db:redo DB=test"
namespace :db do
desc "Remake db from scratch: $ rake db:redo DB=test"
Expand Down
2 changes: 1 addition & 1 deletion bin/scaffold.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
#
# This script converts given migration file into rails scaffold command
# This script converts given migration file into a Rails scaffold command

output = STDOUT
ARGV.each do |file_name|
Expand Down
87 changes: 87 additions & 0 deletions example/flex_report
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env ruby
#
# FLEX is a web-based service from IB that helps you to retrieve your activity,
# trades and positions. It is working independently from TWS or Gateway, using your
# internet connection directly. See /misc/flex for extended FLEX documentation.
#
# In order to use this service, activate it and configure your token first.
# Your Token is located at Account Management->Reports->Delivery Settings->Flex Web Service.
# You need to activate Flex Web Service and generate new token(s) there.
# Your Flex Query Ids are in Account Management->Reports->Activity->Flex Queries.
# Create new Flex query and make sure to set its output format to XML.
#
# This script retrieves your pre-defined FLEX report from IB using 'hands-on' approach
# where you control all the low-level details of the communication with FLEX service.

require 'rubygems'
require 'net/http'
require 'net/https'
require 'xmlsimple'
require 'yaml'

if File.exists? "config/flex.yml"
# You may want to put your favorite FLEX queries info into a separate config file
query_name = ARGV[0] || 'default'
config = YAML::load_file('config/flex.yml')[query_name]
raise "FLEX error: no config for #{query_name} in 'config/flex.yml'" unless config
query_id = config[:query_id]
token = config[:token]
raise "FLEX error: no token or query_id for #{query_name}" unless token && query_id
else
# ... or just hardcode your token and query_id here:
query_id = ARGV[0] || 11111 # CHANGE to actual query id!
token = 1111111111111111111111111111111111 # CHANGE to your actual token!
end

# Helper method to get and parse XML responses from IB Flex Web Service
def get_xml address, fields
uri = URI("#{address}?" + fields.map { |k, v| "#{k}=#{URI.encode(v.to_s)}" }.join('&'))

server = Net::HTTP.new(uri.host, uri.port)
server.use_ssl = (uri.scheme == 'https')
server.verify_mode = OpenSSL::SSL::VERIFY_NONE if server.use_ssl? # Avoid OpenSSL failures

resp = server.start do |http|
req = Net::HTTP::Get.new(uri.request_uri)
http.request(req)
end

raise "FLEX error: URI responded with #{resp.code}" unless resp.code.to_i == 200
raise "FLEX error: Expected xml, got #{resp.content_type}" unless resp.content_type == 'text/xml'

XmlSimple.xml_in(resp.body, :ForceArray => false)
end

# Initiate FLEX request at a known FLEX Web Service URI
flex_uri = 'https://www.interactivebrokers.com/Universal/servlet/FlexStatementService.SendRequest'
resp = get_xml flex_uri, :t => token, :q => query_id, :v => 3

raise "FLEX error #{resp['ErrorCode']}: #{resp['ErrorMessage']}" if resp['Status'] == 'Fail'

reference_code = resp['ReferenceCode']
report_uri = resp['Url']

# Retrieve the FLEX report
report = nil
until report do
report = get_xml report_uri, :t => token, :q => reference_code, :v => 3

# If Status is specified, xml contains only error message, not actual report
if report['Status'] == 'Fail'
error_code = report['ErrorCode'].to_i
error_message = "FLEX error #{error_code}: #{report['ErrorMessage']}"

case error_code
when 1001..1009, 1018, 1019, 1021
# Report is just not ready yet, wait and retry
puts error_message
report = nil
sleep 1
else # Fatal error
raise error_message
end
end
end

# Now you have to extract all the data you need from the report
p report
6 changes: 3 additions & 3 deletions example/fundamental_data
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ require 'ib-ruby'
require 'xmlsimple'
require 'pp'


ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS

ib.subscribe(:Alert) { |msg| puts msg.to_human }

# Fundamental Data will arrive as XML, parse it
ib.subscribe(:FundamentalData) { |msg| @xml = XmlSimple.xml_in(msg.data) }
# Fundamental Data will arrive in XML format, we need to parse it
ib.subscribe(:FundamentalData) { |msg| @xml = XmlSimple.xml_in(msg.data, :ForceArray => false) }

ibm = IB::Contract.new :symbol => 'IBM',
:exchange => 'NYSE',
Expand All @@ -36,4 +35,5 @@ ib.send_message :RequestFundamentalData,
# Needs some time to receive and parse XML. Standard timeout of 1 sec is just too low.
ib.wait_for(30) { @xml}

# Now just extract and use all the fundamental data you needed
pp @xml
11 changes: 9 additions & 2 deletions lib/ib/messages/outgoing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ module Outgoing
:account_code)

# data => { :id => request_id (int), :contract => Contract }
#
# Special case for options: "wildcards" in the Contract fields retrieve Option chains
# strike = 0 means all strikes
# right = "" meanns both call and put
# expiry = "" means all expiries
# expiry = "2013" means all expiries in 2013
# expiry = "201311" means all expiries in Nov 2013
# You'll get several ContractData (10) messages back if there is more than one match.
# When all the matches are delivered you'll get ContractDataEnd (52) message.
RequestContractDetails = RequestContractData =
def_message([9, 6],
[:contract, :serialize_short, [:con_id, :include_expired, :sec_id]])
Expand All @@ -84,8 +93,6 @@ module Outgoing
[:contract, :serialize_short, []],
:num_rows)

### Defining (complex) Outgoing Message classes for IB:

# When this message is sent, TWS responds with ExecutionData messages, each
# containing the execution report that meets the specified criteria.
# @data={:id => int: :request_id,
Expand Down
Binary file added misc/flex/Flex1.pdf
Binary file not shown.
Binary file added misc/flex/Flex2.pdf
Binary file not shown.
Binary file added misc/flex/Flex3.pdf
Binary file not shown.
Binary file added misc/flex/Flex4.pdf
Binary file not shown.
File renamed without changes.
1 change: 1 addition & 0 deletions tasks/gem.rake
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace :gem do

desc "Build and push gem to Gemcutter"
task :release => [:build, 'git:tag'] do
require 'openssl' if RUBY_ENGINE =~ /jruby/
puts "Pushing gem to Gemcutter"
system "gem push #{PKG_PATH}/#{gem_file}"
end
Expand Down

0 comments on commit 9b48dc2

Please sign in to comment.