ib-symbols 1.0

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.
@@ -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