ib-symbols 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This script connects to IB API and subscribes to market data for Forex symbols.
4
+ # It then prints out all trades that exceed certain size.
5
+
6
+ require 'bundler/setup'
7
+ require 'ib/symbols'
8
+
9
+ # Define the symbols we're interested in.
10
+ @market = {
11
+ 123 => IB::Symbols::Futures[:gbp],
12
+ 234 => IB::Symbols::Futures[:jpy],
13
+ 444 => IB::Symbols::Forex[:usdjpy]
14
+ }
15
+
16
+ # First, connect to IB TWS. Arbitrary :client_id is used to identify your script
17
+ ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
18
+
19
+ # Subscribe to TWS alerts/errors
20
+ ib.subscribe(:Alert, :ManagedAccounts) { |msg| puts msg.to_human }
21
+
22
+ # This method filters out non-:last type events, and filters out any sale < MIN_SIZE.
23
+ # Note that we have to look the ticker id of each incoming message
24
+ # up in local memory to figure out what it's for.
25
+ # (N.B. The description field is not from IB TWS. It is defined
26
+ # locally in symbols/futures.rb symbols/forex.rb, and is just arbitrary text.)
27
+ def show_sales_and_size(msg)
28
+ #return if msg.type != :last_price || msg.data[:size] < MIN_SIZE
29
+ puts @market[msg.ticker_id].description + ": " +
30
+ (msg.is_a?(IB::Messages::Incoming::TickPrice) ?
31
+ "#{msg.data[:size]} at #{msg.data[:price]}" : msg.to_human)
32
+ end
33
+
34
+ # Now, subscribe to TickerPrice and TickerSize events. The code passed in the block
35
+ # will be executed when a message of that type is received, with the received message
36
+ # as its argument. In this case, we just print out the tick.
37
+ ib.subscribe(:TickPrice, :TickSize, :TickString) { |msg| show_sales_and_size(msg) }
38
+
39
+ # Now we actually request market data for the symbols we're interested in.
40
+ @market.each_pair do |id, contract|
41
+ ib.send_message :RequestMarketData, :ticker_id => id, :contract => contract
42
+ end
43
+
44
+ puts "\nSubscribed to TWS market data"
45
+ puts "\n******** Press <Enter> to cancel... *********\n\n"
46
+ STDIN.gets
47
+ puts "Unsubscribing from TWS market data.."
48
+
49
+ @market.each_pair { |id, contract| ib.send_message :CancelMarketData, :ticker_id => id }
50
+
51
+ sleep 2
@@ -0,0 +1,38 @@
1
+ require_relative 'lib/ib/symbols/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "ib-symbols"
5
+ spec.version = IB::Symbols::VERSION
6
+ spec.authors = ["Hartmut Bischoff"]
7
+ spec.email = ["topofocus@gmail.com"]
8
+
9
+ spec.summary = %q{Predefined symbols and watchlist, part of ib-ruby}
10
+ spec.description = %q{Easy access to most common contracts through templates, define watchlists to perfrom bulk operations}
11
+ spec.homepage = "https://ib-ruby.github.io/ib-doc/"
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
13
+
14
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/ib-ruby/ib-symbols"
18
+ # spec.metadata["changelog_uri"] = "https://github.com/ib-ruby/ib-symbols/changelog.md"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_dependency "ib-api"
30
+ spec.add_dependency "ox"
31
+ spec.add_development_dependency "bundler", "~> 2.0"
32
+ spec.add_development_dependency "rspec", "~> 3.0"
33
+ spec.add_development_dependency 'rspec-collection_matchers'
34
+ spec.add_development_dependency 'rspec-its'
35
+
36
+ spec.add_development_dependency "guard"
37
+ spec.add_development_dependency "guard-rspec"
38
+ end
@@ -0,0 +1,112 @@
1
+ require "ib/symbols/version"
2
+ require "ib-api"
3
+
4
+ # These modules are used to facilitate referencing of most popular IB Contracts.
5
+ # Like pages in the TWS-GUI, they can be utilised to organise trading and research.
6
+ #
7
+ # Symbol Allocations are organized as modules. They represent the contents of yaml files in
8
+ #
9
+ # /lib/symbols/
10
+ #
11
+ # Any collection is represented as simple Hash, with __key__ as qualifier and an __IB::Contract__ as value.
12
+ # The Value is either a fully prequalified Contract (Stock, Option, Future, Forex, CFD, BAG) or
13
+ # a lazy qualified Contract acting as base für further calucaltions and requests.
14
+ #
15
+ # IB::Symbols.allocate_collection :Name
16
+ #
17
+ # creates the Module and file. If a previously created file is found, its contents are read and
18
+ # the vcollection ist reestablished.
19
+ #
20
+ # IB::Symbols::Name.add_contract :wfc, IB::Stock.new( symbol: 'WFC' )
21
+ #
22
+ # adds the contract and stores it in the yaml file
23
+ #
24
+ # IB::Symbols::Name.wfc # or IB::Symbols::Name[:wfc]
25
+ #
26
+ # retrieves the contract
27
+ #
28
+ # IB::Symbols::Name.all
29
+ #
30
+ # returns an Array of stored contracts
31
+ #
32
+ # IB::Symbols::Name.remove_contract :wfc
33
+ #
34
+ # deletes the contract from the list (and the file)
35
+ #
36
+ # To finish the cycle
37
+ #
38
+ # IB::Symbols::Name.purge_collection
39
+ #
40
+ # deletes the file and erases the collection in memory.
41
+ #
42
+ # Additional methods can be introduced
43
+ # * for individual contracts on the module-level or
44
+ # * to organize the list as methods of Array in Module IB::SymbolExtention
45
+ #
46
+ #
47
+ # Contracts can be hardcoded in the required standard-collections as well.
48
+ # Note that the :description field is local to ib-ruby, and is NOT part of the standard TWS API.
49
+ # It is never transmitted to IB. It's purely used clientside, and you can store any arbitrary
50
+ # string that you may find useful there.
51
+
52
+ module IB
53
+ module Symbols
54
+ class Error < StandardError; end
55
+
56
+
57
+
58
+ def hardcoded?
59
+ !self.methods.include? :yml_file
60
+ end
61
+ def method_missing(method, *key)
62
+ if key.empty?
63
+ if contracts.has_key?(method)
64
+ contracts[method]
65
+ elsif methods.include?(:each) && each.methods.include?(method)
66
+ self.each.send method
67
+ else
68
+ error "contract #{method} not defined. Try »all« for a list of defined Contracts.", :symbol
69
+ end
70
+ else
71
+ error "method missing"
72
+ end
73
+ end
74
+
75
+ def all
76
+ contracts.keys.sort rescue contracts.keys
77
+ end
78
+ def print_all
79
+ puts contracts.sort.map{|x,y| [x,y.description].join(" -> ")}.join "\n"
80
+ end
81
+ def contracts
82
+ if @contracts.present?
83
+ @contracts
84
+ else
85
+ @contracts = Hash.new
86
+ end
87
+ end
88
+ def [] symbol
89
+ if c=contracts[symbol]
90
+ return c
91
+ else
92
+ # symbol probably has not been predefined, tell user about it
93
+ file = self.to_s.split(/::/).last.downcase
94
+ msg = "Unknown symbol :#{symbol}, please pre-define it in lib/ib/symbols/#{file}.rb"
95
+ error msg, :symbol
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+
102
+ require 'ib/symbols/forex'
103
+ require 'ib/symbols/futures'
104
+ require 'ib/symbols/stocks'
105
+ require 'ib/symbols/index'
106
+ require 'ib/symbols/cfd'
107
+ require 'ib/symbols/commodity'
108
+ require 'ib/symbols/options'
109
+ require 'ib/symbols/combo'
110
+ require 'ib/symbols/bonds'
111
+ require 'ib/symbols/abstract'
112
+
@@ -0,0 +1,137 @@
1
+ module IB
2
+
3
+ # reopen the contract-class and add yml_file
4
+ class Contract
5
+
6
+ # Reading Contract-Defaults
7
+ #
8
+ # by default, the yml-file in the base-directory (ib-ruby) is used.
9
+ # This method can be overloaded to include a file from a different location
10
+ #
11
+ # IB::Symbols::Stocks.wfc.yml_file
12
+ # => "/home/ubuntu/workspace/ib-ruby/contract_config.yml"
13
+ #
14
+ def yml_file
15
+ File.expand_path('../../../../contract_config.yml',__FILE__ )
16
+ end
17
+ end
18
+
19
+
20
+ module Symbols
21
+
22
+ =begin
23
+ Creates a Class and associates it with a filename
24
+
25
+ raises an IB::Error in case of a conflict with existing class-names
26
+ =end
27
+
28
+ # set the Pathname to "ib-api/symbols" by default
29
+ @@dir= Pathname.new File.expand_path("../../../../symbols/", __FILE__ )
30
+ def self.set_origin directory
31
+ p = Pathname.new directory
32
+ @@dir = p if p.directory?
33
+ rescue Errno::ENOENT
34
+ error "Setting up origin for symbol-files --> Directory (#{directory}) does not exist"
35
+ end
36
+
37
+ def self.allocate_collection name # name might be a string or a symbol
38
+ symbol_table = Module.new do
39
+ extend Symbols
40
+ extend Enumerable
41
+ def self.yml_file
42
+ @@dir + name.to_s.downcase.split("::").last.concat( ".yml" )
43
+ end
44
+
45
+ def self.each &b
46
+ contracts.values.each &b
47
+ end
48
+ end # module new
49
+ name = name.to_s.camelize.to_sym
50
+ the_collection = if Symbols.send :const_defined?, name
51
+ Symbols.send :const_get, name
52
+ else
53
+ Symbols.const_set name, symbol_table
54
+ end
55
+ if the_collection.is_a? Symbols
56
+ the_collection.send :read_collection if the_collection.all.empty?
57
+ the_collection # return_value
58
+ else
59
+ error "#{the_collection} is already a Class"
60
+ nil
61
+ end
62
+ end
63
+
64
+ def purge_collection
65
+ yml_file.delete
66
+ @contracts = nil
67
+ end
68
+
69
+ =begin
70
+ cuts the Collection in `bunch_count` pieces. Each bunch is delivered to the block.
71
+
72
+ Sleeps for `sleeping time` between processing bunches
73
+
74
+ Returns count of created bunches
75
+ =end
76
+ def bunch( bunch_count = 50 , sleeping_time = 1)
77
+ en = self.each
78
+ the_size = en.size
79
+ i = 0
80
+ loop do
81
+ the_start = i * bunch_count
82
+ the_end = the_start + bunch_count
83
+ the_end = the_size -1 if the_end >= the_size
84
+ it = the_start .. the_end
85
+ yield it.map{|x| en.next rescue nil}.compact
86
+ break if the_end == the_size -1
87
+ i+=1
88
+ sleep sleeping_time
89
+ end
90
+ i -1 # return counts of bunches
91
+ end
92
+
93
+ def read_collection
94
+ if yml_file.exist?
95
+ contracts.merge! YAML.load_file yml_file rescue contracts
96
+ else
97
+ yml_file.open( "w"){}
98
+ end
99
+ end
100
+
101
+ def store_collection
102
+ yml_file.open( 'w' ){|f| f.write @contracts.to_yaml}
103
+ end
104
+
105
+ def add_contract symbol, contract
106
+ if symbol.is_a? String
107
+ symbol.to_sym
108
+ elsif symbol.is_a? Symbol
109
+ symbol
110
+ else
111
+ symbol.to_i
112
+ end
113
+ # ensure that evey Sybmol::xxx.yyy entry has a description
114
+ contract.description = contract.to_human[1..-2] if contract.description.nil?
115
+ # overwrite contract if existing
116
+ contracts[ symbol ] = contract.essential
117
+ store_collection
118
+ end
119
+
120
+ def remove_contract symbol
121
+ @contracts.delete symbol
122
+ store_collection
123
+ end
124
+
125
+
126
+ def to_human
127
+ self.to_s.split("::").last
128
+ end
129
+
130
+
131
+
132
+ module Unspecified
133
+ extend Symbols
134
+ end
135
+
136
+ end # module Symbols
137
+ end # module IB
@@ -0,0 +1,28 @@
1
+ # Sample bond contract definitions
2
+ module IB
3
+ module Symbols
4
+ module Bonds
5
+ extend Symbols
6
+
7
+ def self.contracts
8
+ @contracts ||= {
9
+ :abbey => IB::Contract.new(:symbol => "ABBEY",
10
+ :currency => "USD",
11
+ :sec_type => :bond,
12
+ :description => "Any ABBEY bond"),
13
+
14
+ :ms => IB::Contract.new(:symbol => "MS",
15
+ :currency => "USD",
16
+ :sec_type => :bond,
17
+ :description => "Any Morgan Stanley bond"),
18
+
19
+ :wag => IB::Contract.new(:symbol => "WAG",
20
+ :currency => "USD",
21
+ :sec_type => :bond,
22
+ :description => "Any Wallgreens bond"),
23
+ }
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ # Frequently used stock contracts definitions
2
+ # TODO: auto-request :ContractDetails from IB if unknown symbol is requested?
3
+ module IB
4
+ module Symbols
5
+ module CFD
6
+ extend Symbols
7
+
8
+ def self.contracts
9
+ @contracts.presence || super.merge(
10
+ :dax => IB::Contract.new(:symbol => "IBDE30", sec_type: :cfd,
11
+ :currency => "EUR",
12
+ :description => "DAX CFD."),
13
+
14
+ )
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,52 @@
1
+ # Frequently used stock contracts definitions
2
+ # TODO: auto-request :ContractDetails from IB if unknown symbol is requested?
3
+ module IB
4
+ module Symbols
5
+ module Combo
6
+ extend Symbols
7
+
8
+ def self.contracts
9
+
10
+ @contracts ||= { #super.merge(
11
+ stoxx_straddle: IB::Straddle.build( from: IB::Symbols::Index.stoxx, strike: 3000,
12
+ expiry: IB::Symbols::Futures.next_expiry, trading_class: 'OESX') ,
13
+ stoxx_calendar: IB::Calendar.build( from: IB::Symbols::Index.stoxx, strike: 3000, back: '2m' ,
14
+ front: IB::Symbols::Futures.next_expiry, trading_class: 'OESX'),
15
+ stoxx_butterfly: IB::Butterfly.fabricate( Symbols::Options.stoxx.merge( strike: 3300), front: 3250, back: 3350 ),
16
+ stoxx_vertical: IB::Vertical.build( from: IB::Symbols::Index.stoxx, sell: 3000, buy: 3500, right: :put,
17
+ expiry: IB::Symbols::Futures.next_expiry, trading_class: 'OESX'),
18
+ zn_calendar: IB::Calendar.fabricate( IB::Symbols::Futures.zn, '3m') ,
19
+
20
+ dbk_straddle: Bag.new( symbol: 'DBK', currency: 'EUR', exchange: 'DTB', combo_legs:
21
+ [ ComboLeg.new( con_id: 270581032 , action: :buy, exchange: 'DTB', ratio: 1), #DBK Dez20 2018 C
22
+ ComboLeg.new( con_id: 270580382, action: :buy, exchange: 'DTB', ratio: 1 ) ], #DBK Dez 20 2018 P
23
+ description: 'Option Straddle: Deutsche Bank(20)[Dez 2018]'
24
+ ),
25
+ ib_mcd: Bag.new( symbol: 'IBKR,MCD', currency: 'USD', combo_legs:
26
+ [ ComboLeg.new( con_id: 43645865, action: :buy, ratio: 1), # IKBR STK
27
+ ComboLeg.new( con_id: 9408, action: :sell,ratio: 1 ) ], # MCD STK
28
+ description: 'Stock Spread: Buy Interactive Brokers, sell Mc Donalds'
29
+ ),
30
+
31
+ vix_calendar: Bag.new( symbol: 'VIX', currency: 'USD', exchange: 'CFE', combo_legs:
32
+ [ ComboLeg.new( con_id: 256038899, action: :buy, exchange: 'CFE', ratio: 1), # VIX FUT 201708
33
+ ComboLeg.new( con_id: 260564703, action: :sell, exchange: 'CFE', ratio: 1 ) ], # VIX FUT 201709
34
+ description: 'VixFuture Calendar-Spread August - September 2017'
35
+ ),
36
+ wti_coil: Bag.new( symbol: 'WTI', currency: 'USD', exchange: 'SMART', combo_legs:
37
+ [ ComboLeg.new( con_id: 55928698, action: :buy, exchange: 'IPE', ratio: 1), # WTI future June 2017
38
+ ComboLeg.new( con_id: 55850663, action: :sell, exchange: 'IPE', ratio: 1 ) ], # COIL future June 2017
39
+ description: 'Smart Future Spread WTI - COIL (June 2017) '
40
+ ),
41
+ wti_brent: Bag.new( symbol: 'CL.BZ', currency: 'USD', exchange: 'NYMEX', combo_legs:
42
+ [ ComboLeg.new( con_id: 47207310, action: :buy, exchange: 'NYMEX', ratio: 1), # CL Dec'16 @NYMEX
43
+ ComboLeg.new( con_id: 47195961, action: :sell, exchange: 'NYMEX', ratio: 1 ) ], #BZ Dec'16 @NYMEX
44
+ description: ' WTI - Brent Spread (Dez. 2016)'
45
+ )
46
+ }
47
+ # )
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,17 @@
1
+ # Frequently used stock contracts definitions
2
+ # TODO: auto-request :ContractDetails from IB if unknown symbol is requested?
3
+ module IB
4
+ module Symbols
5
+ module Commodity
6
+ extend Symbols
7
+
8
+ def self.contracts
9
+ @contracts.presence || super.merge(
10
+ :xau => IB::Contract.new( symbol: 'XAUUSD', sec_type: :commodity, currency: 'USD',
11
+ :description => "London Gold ")
12
+ )
13
+ end
14
+
15
+ end
16
+ end
17
+ end