ib-ruby 0.8.4 → 0.8.5

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.
Files changed (118) hide show
  1. data/.gitignore +3 -0
  2. data/HISTORY +3 -0
  3. data/README.md +29 -9
  4. data/VERSION +1 -1
  5. data/app/assets/javascripts/ib/bars.js +2 -0
  6. data/app/assets/javascripts/ib/executions.js +2 -0
  7. data/app/assets/javascripts/ib/order_states.js +2 -0
  8. data/app/assets/stylesheets/ib/bars.css +4 -0
  9. data/app/assets/stylesheets/ib/executions.css +4 -0
  10. data/app/assets/stylesheets/ib/order_states.css +4 -0
  11. data/app/controllers/ib/bars_controller.rb +87 -0
  12. data/app/controllers/ib/combo_legs_controller.rb +87 -0
  13. data/app/controllers/ib/contract_details_controller.rb +87 -0
  14. data/app/controllers/ib/contracts_controller.rb +87 -0
  15. data/app/controllers/ib/executions_controller.rb +87 -0
  16. data/app/controllers/ib/order_states_controller.rb +87 -0
  17. data/app/controllers/ib/orders_controller.rb +87 -0
  18. data/app/helpers/ib/bars_helper.rb +4 -0
  19. data/app/helpers/ib/combo_legs_helper.rb +4 -0
  20. data/app/helpers/ib/contract_details_helper.rb +4 -0
  21. data/app/helpers/ib/contracts_helper.rb +4 -0
  22. data/app/helpers/ib/executions_helper.rb +4 -0
  23. data/app/helpers/ib/order_states_helper.rb +4 -0
  24. data/app/helpers/ib/orders_helper.rb +4 -0
  25. data/app/views/ib/bars/_form.html.erb +57 -0
  26. data/app/views/ib/bars/edit.html.erb +6 -0
  27. data/app/views/ib/bars/index.html.erb +41 -0
  28. data/app/views/ib/bars/new.html.erb +5 -0
  29. data/app/views/ib/bars/show.html.erb +55 -0
  30. data/app/views/ib/combo_legs/_form.html.erb +53 -0
  31. data/app/views/ib/combo_legs/edit.html.erb +6 -0
  32. data/app/views/ib/combo_legs/index.html.erb +39 -0
  33. data/app/views/ib/combo_legs/new.html.erb +5 -0
  34. data/app/views/ib/combo_legs/show.html.erb +55 -0
  35. data/app/views/ib/contract_details/_form.html.erb +141 -0
  36. data/app/views/ib/contract_details/edit.html.erb +6 -0
  37. data/app/views/ib/contract_details/index.html.erb +83 -0
  38. data/app/views/ib/contract_details/new.html.erb +5 -0
  39. data/app/views/ib/contract_details/show.html.erb +160 -0
  40. data/app/views/ib/contracts/_form.html.erb +77 -0
  41. data/app/views/ib/contracts/edit.html.erb +6 -0
  42. data/app/views/ib/contracts/index.html.erb +53 -0
  43. data/app/views/ib/contracts/new.html.erb +5 -0
  44. data/app/views/ib/contracts/show.html.erb +85 -0
  45. data/app/views/ib/executions/_form.html.erb +77 -0
  46. data/app/views/ib/executions/edit.html.erb +6 -0
  47. data/app/views/ib/executions/index.html.erb +51 -0
  48. data/app/views/ib/executions/new.html.erb +5 -0
  49. data/app/views/ib/executions/show.html.erb +80 -0
  50. data/app/views/ib/order_states/_form.html.erb +93 -0
  51. data/app/views/ib/order_states/edit.html.erb +6 -0
  52. data/app/views/ib/order_states/index.html.erb +59 -0
  53. data/app/views/ib/order_states/new.html.erb +5 -0
  54. data/app/views/ib/order_states/show.html.erb +100 -0
  55. data/app/views/ib/orders/_form.html.erb +353 -0
  56. data/app/views/ib/orders/edit.html.erb +6 -0
  57. data/app/views/ib/orders/index.html.erb +193 -0
  58. data/app/views/ib/orders/new.html.erb +5 -0
  59. data/app/views/ib/orders/show.html.erb +435 -0
  60. data/bin/scaffold.rb +29 -0
  61. data/config/routes.rb +8 -1
  62. data/db/config.yml +5 -0
  63. data/db/migrate/101_add_ib_executions.rb +3 -0
  64. data/db/migrate/111_add_ib_bars.rb +6 -0
  65. data/db/migrate/121_add_ib_order_states.rb +8 -0
  66. data/db/migrate/131_add_ib_orders.rb +24 -0
  67. data/db/migrate/141_add_ib_combo_legs.rb +6 -0
  68. data/db/migrate/151_add_ib_underlyings.rb +3 -0
  69. data/db/migrate/161_add_ib_contract_details.rb +11 -0
  70. data/db/migrate/171_add_ib_contracts.rb +8 -1
  71. data/db/schema.rb +6 -5
  72. data/lib/ib/base.rb +3 -1
  73. data/lib/ib/base_properties.rb +26 -15
  74. data/lib/ib/connection.rb +3 -2
  75. data/lib/ib/errors.rb +16 -9
  76. data/lib/ib/extensions.rb +6 -4
  77. data/lib/ib/symbols.rb +10 -3
  78. data/lib/ib/symbols/forex.rb +49 -64
  79. data/lib/ib/symbols/futures.rb +2 -3
  80. data/lib/ib/symbols/options.rb +2 -1
  81. data/lib/ib/symbols/stocks.rb +2 -1
  82. data/lib/models/ib/bar.rb +6 -2
  83. data/lib/models/ib/combo_leg.rb +4 -3
  84. data/lib/models/ib/contract.rb +9 -5
  85. data/lib/models/ib/contract_detail.rb +1 -1
  86. data/lib/models/ib/execution.rb +3 -1
  87. data/lib/models/ib/order.rb +22 -20
  88. data/lib/models/ib/order_state.rb +4 -2
  89. data/lib/models/ib/underlying.rb +3 -4
  90. data/spec/README.md +12 -10
  91. data/spec/ib/symbols/symbols_spec.rb +10 -0
  92. data/spec/integration_helper.rb +1 -1
  93. data/spec/model_helper.rb +9 -8
  94. data/spec/models/ib/combo_leg_spec.rb +29 -28
  95. data/spec/models/ib/contract_detail_spec.rb +4 -1
  96. data/spec/models/ib/contract_spec.rb +66 -58
  97. data/spec/models/ib/execution_spec.rb +50 -44
  98. data/spec/models/ib/order_spec.rb +2 -2
  99. data/spec/order_helper.rb +5 -4
  100. data/spec/spec_helper.rb +3 -3
  101. metadata +59 -35
  102. data/app/models/ib/underlying.rb +0 -5
  103. data/bin/account_info +0 -29
  104. data/bin/cancel_orders +0 -27
  105. data/bin/contract_details +0 -35
  106. data/bin/depth_of_market +0 -43
  107. data/bin/fa_accounts +0 -22
  108. data/bin/fundamental_data +0 -39
  109. data/bin/historic_data +0 -51
  110. data/bin/historic_data_cli +0 -182
  111. data/bin/list_orders +0 -28
  112. data/bin/market_data +0 -41
  113. data/bin/option_data +0 -44
  114. data/bin/place_combo_order +0 -58
  115. data/bin/place_order +0 -27
  116. data/bin/template +0 -18
  117. data/bin/tick_data +0 -26
  118. data/bin/time_and_sales +0 -53
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This script converts given migration file into rails scaffold command
4
+
5
+ output = STDOUT
6
+ ARGV.each do |file_name|
7
+ if File.exist? file_name
8
+ File.open(file_name) do |file|
9
+ puts "\nProcessing: #{file.inspect}"
10
+
11
+ model_name = nil
12
+ file.each do |line|
13
+ if line =~ /create_table.*:ib_(.*)s.* do \|t\|/
14
+ model_name = Regexp.last_match(1)
15
+ output.print "\nrails generate scaffold #{model_name} "
16
+ end
17
+
18
+ if line =~ /t\.(\w*) :(\w*)/
19
+ field, type = Regexp.last_match(2), Regexp.last_match(1)
20
+ if type == 'references'
21
+ field, type = field + '_id', 'integer'
22
+ end
23
+ output.print "#{field}:#{type} "
24
+ end
25
+ end
26
+ end
27
+ output.puts
28
+ end
29
+ end
@@ -1,6 +1,13 @@
1
1
  IB::Engine.routes.draw do
2
+ # resources :bars, :module => "ib"
3
+ resources :bars
4
+ resources :combo_legs
5
+ resources :contracts
6
+ resources :contract_details
7
+ resources :executions
8
+ resources :orders
9
+ resources :order_states
2
10
  resources :underlyings
3
- # resources :underlyings, :module => "ib"
4
11
 
5
12
  root :to => "underlyings#index"
6
13
  end
@@ -12,6 +12,11 @@ test-mri:
12
12
  <<: *test
13
13
  :adapter: sqlite3
14
14
 
15
+ # Dev configurations (JRuby)
16
+ development:
17
+ <<: *test
18
+ :database: db/development.sqlite3
19
+
15
20
  # Battle configurations (JRuby)
16
21
  prod:
17
22
  <<: *test
@@ -22,3 +22,6 @@ class AddIbExecutions < ActiveRecord::Migration
22
22
  end
23
23
  end
24
24
  end
25
+
26
+ __END__
27
+ rails generate scaffold execution order_id:integer local_id:integer client_id:integer perm_id:integer order_ref:string exec_id:string side:string quantity:integer cumulative_quantity:integer price:float average_price:float exchange:string account_name:string liquidation:boolean time:string
@@ -3,6 +3,7 @@ class AddIbBars < ActiveRecord::Migration
3
3
  def change
4
4
  # This is a single data point delivered by HistoricData or RealTimeBar messages.
5
5
  create_table(:ib_bars) do |t|
6
+ t.references :contract
6
7
  t.float :open # double:
7
8
  t.float :high # double:
8
9
  t.float :low # double:
@@ -16,3 +17,8 @@ class AddIbBars < ActiveRecord::Migration
16
17
  end
17
18
  end
18
19
  end
20
+
21
+ __END__
22
+ rails generate scaffold bar contract_id:integer open:float high:float low:float close:float
23
+ wap:float volume:integer trades:integer has_gaps:boolean time:string
24
+
@@ -26,3 +26,11 @@ class AddIbOrderStates < ActiveRecord::Migration
26
26
  end
27
27
  end
28
28
  end
29
+
30
+ __END__
31
+ rails generate scaffold order_state order_id:integer local_id:integer client_id:integer
32
+ perm_id:integer parent_id:integer status:string filled:integer remaining:integer
33
+ price:float average_price:float why_held:string warning_text:string
34
+ commission_currency:string commission:float min_commission:float max_commission:float
35
+ init_margin:string maint_margin:float equity_with_loan:float
36
+
@@ -104,3 +104,27 @@ class AddIbOrders < ActiveRecord::Migration
104
104
  end
105
105
  end
106
106
  end
107
+
108
+ __END__
109
+ rails generate scaffold order contract_id:integer local_id:integer client_id:integer
110
+ perm_id:integer parent_id:integer order_ref:string order_type:string tif:string side:string
111
+ quantity:integer limit_price:float aux_price:float open_close:integer oca_type:integer
112
+ oca_group:string transmit:boolean what_if:boolean outside_rth:boolean not_held:boolean
113
+ hidden:boolean block_order:boolean sweep_to_fill:boolean all_or_none:boolean etrade_only:boolean
114
+ firm_quote_only:boolean opt_out_smart_routing:boolean override_percentage_constraints:boolean
115
+ min_quantity:integer display_size:integer trigger_method:integer origin:integer
116
+ good_after_time:string good_till_date:string rule_80a:string percent_offset:float
117
+ trail_stop_price:float trailing_percent:float fa_group:string fa_profile:string fa_method:string
118
+ fa_percentage:string short_sale_slot:integer designated_location:string exempt_code:integer
119
+ account:string settling_firm:string clearing_account:string clearing_intent:string
120
+ discretionary_amount:float nbbo_price_cap:float auction_strategy:integer starting_price:float
121
+ stock_ref_price:float delta:float stock_range_lower:float stock_range_upper:float
122
+ volatility:float volatility_type:integer reference_price_type:integer continuous_update:integer
123
+ delta_neutral_order_type:string delta_neutral_aux_price:string delta_neutral_con_id:integer
124
+ delta_neutral_settling_firm:string delta_neutral_clearing_account:string
125
+ delta_neutral_clearing_intent:string hedge_type:string hedge_param:string basis_points:float
126
+ basis_points_type:float algo_strategy:string leg_prices:text algo_params:text
127
+ combo_params:text scale_init_level_size:integer scale_subs_level_size:integer
128
+ scale_price_increment:float scale_price_adjust_value:float scale_price_adjust_interval:integer
129
+ scale_profit_offset:float scale_init_position:integer scale_init_fill_qty:integer
130
+ scale_auto_reset:boolean scale_random_percent:boolean placed_at:timestamp modified_at:timestamp
@@ -17,3 +17,9 @@ class AddIbComboLegs < ActiveRecord::Migration
17
17
  end
18
18
  end
19
19
  end
20
+
21
+ __END__
22
+ rails generate scaffold combo_leg combo_id:integer leg_contract_id:integer con_id:integer
23
+ side:string ratio:integer exchange:string exempt_code:integer short_sale_slot:integer
24
+ open_close:integer designated_location:string
25
+
@@ -11,3 +11,6 @@ class AddIbUnderlyings < ActiveRecord::Migration
11
11
  end
12
12
  end
13
13
  end
14
+
15
+ __END__
16
+ rails generate scaffold underlying contract_id:integer con_id:integer delta:float price:float
@@ -38,3 +38,14 @@ class AddIbContractDetails < ActiveRecord::Migration
38
38
  end
39
39
  end
40
40
  end
41
+
42
+ __END__
43
+ rails generate scaffold contract_detail contract_id:integer market_name:string
44
+ trading_class:string min_tick:float price_magnifier:integer order_types:string
45
+ valid_exchanges:string under_con_id:integer long_name:string contract_month:string
46
+ industry:string category:string subcategory:string time_zone:string trading_hours:string
47
+ liquid_hours:string cusip:string ratings:string desc_append:string bond_type:string
48
+ coupon_type:string coupon:float maturity:string issue_date:string next_option_date:string
49
+ next_option_type:string notes:string callable:boolean puttable:boolean convertible:boolean
50
+ next_option_partial:boolean
51
+
@@ -8,7 +8,7 @@ class AddIbContracts < ActiveRecord::Migration
8
8
  t.float :strike # double: The strike price.
9
9
  t.string :currency, :limit => 4 # Only needed if there is an ambiguity e.g. when SMART exchange
10
10
  t.string :sec_id_type, :limit => 5 # Security identifier when querying contract details or
11
- t.integer :sec_id # Unique identifier of the given secIdType.
11
+ t.string :sec_id # Unique identifier of the given secIdType.
12
12
  t.string :legs_description # received in OpenOrder for all combos
13
13
  t.string :symbol # This is the symbol of the underlying asset.
14
14
  t.string :local_symbol # Local exchange symbol of the underlying asset
@@ -24,3 +24,10 @@ class AddIbContracts < ActiveRecord::Migration
24
24
  end
25
25
  end
26
26
  end
27
+
28
+ __END__
29
+ rails generate scaffold contract con_id:integer sec_type:string strike:float currency:string
30
+ sec_id:string sec_id_type:string legs_description:string symbol:string local_symbol:string
31
+ multiplier:integer expiry:string exchange:string primary_exchange:string
32
+ include_expired:boolean right:string type:string
33
+
@@ -13,6 +13,7 @@
13
13
  ActiveRecord::Schema.define(:version => 171) do
14
14
 
15
15
  create_table "ib_bars", :force => true do |t|
16
+ t.integer "contract_id"
16
17
  t.float "open"
17
18
  t.float "high"
18
19
  t.float "low"
@@ -20,10 +21,10 @@ ActiveRecord::Schema.define(:version => 171) do
20
21
  t.float "wap"
21
22
  t.integer "volume"
22
23
  t.integer "trades"
23
- t.boolean "has_gaps", :limit => 1
24
- t.string "time", :limit => 18
25
- t.datetime "created_at", :null => false
26
- t.datetime "updated_at", :null => false
24
+ t.boolean "has_gaps", :limit => 1
25
+ t.string "time", :limit => 18
26
+ t.datetime "created_at", :null => false
27
+ t.datetime "updated_at", :null => false
27
28
  end
28
29
 
29
30
  create_table "ib_combo_legs", :force => true do |t|
@@ -83,7 +84,7 @@ ActiveRecord::Schema.define(:version => 171) do
83
84
  t.float "strike"
84
85
  t.string "currency", :limit => 4
85
86
  t.string "sec_id_type", :limit => 5
86
- t.integer "sec_id"
87
+ t.string "sec_id"
87
88
  t.string "legs_description"
88
89
  t.string "symbol"
89
90
  t.string "local_symbol"
@@ -9,13 +9,15 @@ module IB
9
9
  include ActiveModel::Serializers::Xml
10
10
  include ActiveModel::Serializers::JSON
11
11
 
12
+ define_model_callbacks :initialize
13
+
12
14
  # If a opts hash is given, keys are taken as attribute names, values as data.
13
15
  # The model instance fields are then set automatically from the opts Hash.
14
16
  def initialize attributes={}, opts={}
15
17
  run_callbacks :initialize do
16
18
  error "Argument must be a Hash", :args unless attributes.is_a?(Hash)
17
19
 
18
- self.attributes = default_attributes.merge(attributes)
20
+ self.attributes = attributes # set_attribute_defaults is now after_init callback
19
21
  end
20
22
  end
21
23
 
@@ -8,12 +8,6 @@ module IB
8
8
  module BaseProperties
9
9
  extend ActiveSupport::Concern
10
10
 
11
- def default_attributes
12
- {:created_at => Time.now,
13
- :updated_at => Time.now,
14
- }
15
- end
16
-
17
11
  ### Instance methods
18
12
 
19
13
  # Default presentation
@@ -42,12 +36,34 @@ module IB
42
36
 
43
37
  # Default Model comparison
44
38
  def == other
45
- content_attributes.inject(true) { |res, (attr, value)| res && other.send(attr) == value } &&
46
- other.content_attributes.inject(true) { |res, (attr, value)| res && send(attr) == value }
39
+ case other
40
+ when String # Probably a Rails URI, delegate to AR::Base
41
+ super(other)
42
+ else
43
+ content_attributes.keys.inject(true) { |res, key|
44
+ res && (send(key) == other.send(key)) }
45
+ end
46
+ end
47
+
48
+ ### Default attributes support
49
+
50
+ def default_attributes
51
+ {:created_at => Time.now,
52
+ :updated_at => Time.now,
53
+ }
54
+ end
55
+
56
+ def set_attribute_defaults
57
+ default_attributes.each do |key, val|
58
+ self.send("#{key}=", val) if self.send(key).nil?
59
+ # self.send("#{key}=", val) if self[key].nil? # Problems with association defaults
60
+ end
47
61
  end
48
62
 
49
63
  included do
50
64
 
65
+ after_initialize :set_attribute_defaults
66
+
51
67
  ### Class macros
52
68
 
53
69
  def self.prop *properties
@@ -125,13 +141,8 @@ module IB
125
141
  end
126
142
  end
127
143
 
128
- # Extending AR-backed Model class with attribute defaults
129
- if defined?(ActiveRecord::Base) && ancestors.include?(ActiveRecord::Base)
130
- def initialize attributes={}, opts={}
131
- super default_attributes.merge(attributes), opts
132
- end
133
- else
134
- # Timestamps
144
+ # Timestamps in lightweight models
145
+ unless defined?(ActiveRecord::Base) && ancestors.include?(ActiveRecord::Base)
135
146
  prop :created_at, :updated_at
136
147
  end
137
148
 
@@ -1,3 +1,4 @@
1
+ require 'thread'
1
2
  require 'ib/socket'
2
3
  require 'ib/logger'
3
4
 
@@ -11,10 +12,10 @@ module IB
11
12
 
12
13
  DEFAULT_OPTIONS = {:host =>'127.0.0.1',
13
14
  :port => '4001', # IB Gateway connection (default)
14
- #:port => '7496', # TWS connection, with annoying pop-ups
15
+ #:port => '7496', # TWS connection
15
16
  :connect => true, # Connect at initialization
16
17
  :reader => true, # Start a separate reader Thread
17
- :received => true, # Keep all received messages in a Hash
18
+ :received => true, # Keep all received messages in a @received Hash
18
19
  :logger => nil,
19
20
  :client_id => nil, # Will be randomly assigned
20
21
  :client_version => 57, # 48, # 57 = can receive commissionReport message
@@ -7,22 +7,29 @@ module IB
7
7
  class ArgumentError < ArgumentError
8
8
  end
9
9
 
10
+ class SymbolError < ArgumentError
11
+ end
12
+
10
13
  class LoadError < LoadError
11
14
  end
12
15
 
13
16
  end # module IB
14
17
 
15
- ### Patching Object with universally accessible top level error method
18
+ # Patching Object with universally accessible top level error method.
19
+ # The method is used throughout the lib instead of plainly raising exceptions.
20
+ # This allows lib user to easily inject user-specific error handling into the lib
21
+ # by just replacing Object#error method.
16
22
  def error message, type=:standard, backtrace=nil
17
23
  e = case type
18
- when :standard
19
- IB::Error.new message
20
- when :args
21
- IB::ArgumentError.new message
22
- when :load
23
- IB::LoadError.new message
24
- end
24
+ when :standard
25
+ IB::Error.new message
26
+ when :args
27
+ IB::ArgumentError.new message
28
+ when :symbol
29
+ IB::SymbolError.new message
30
+ when :load
31
+ IB::LoadError.new message
32
+ end
25
33
  e.set_backtrace(backtrace) if backtrace
26
34
  raise e
27
35
  end
28
-
@@ -28,9 +28,9 @@ end
28
28
  class String
29
29
  def to_bool
30
30
  case self.chomp.upcase
31
- when 'TRUE', 'T'
31
+ when 'TRUE', 'T', '1'
32
32
  true
33
- when 'FALSE', 'F', ''
33
+ when 'FALSE', 'F', '0', ''
34
34
  false
35
35
  else
36
36
  error "Unable to convert #{self} to bool"
@@ -39,8 +39,9 @@ class String
39
39
  end
40
40
 
41
41
  class NilClass
42
+ # We still need to pass on nil, meaning: no value
42
43
  def to_bool
43
- false
44
+ self
44
45
  end
45
46
  end
46
47
 
@@ -56,8 +57,9 @@ class Symbol
56
57
  end
57
58
 
58
59
  class Object
60
+ # We still need to pass on nil, meaning: no value
59
61
  def to_sup
60
- self.to_s.upcase
62
+ self.to_s.upcase unless self.nil?
61
63
  end
62
64
  end
63
65
 
@@ -1,5 +1,5 @@
1
1
  # These modules are used to facilitate referencing of most popular IB Contracts.
2
- # For example, suppose you're explicitely creating such Contract in all your scripts:
2
+ # For example, suppose you're explicitly creating such Contract in all your scripts:
3
3
  # wfc = IB::Contract.new(:symbol => "WFC",
4
4
  # :exchange => "NYSE",
5
5
  # :currency => "USD",
@@ -10,13 +10,20 @@
10
10
  # it as IB::Symbols::Stock[:wfc] anywhere you need it.
11
11
  #
12
12
  # Note that the :description field is local to ib-ruby, and is NOT part of the standard TWS API.
13
- # It is never transmitted to IB. It's purely used clientside, and you can store any arbitrary
13
+ # It is never transmitted to IB. It's purely used clientside, and you can store any arbitrary
14
14
  # string that you may find useful there.
15
15
 
16
16
  module IB
17
17
  module Symbols
18
18
  def [] symbol
19
- contracts[symbol]
19
+ if contracts[symbol]
20
+ return contracts[symbol]
21
+ else
22
+ # symbol probably has not been predefined, tell user about it
23
+ file = self.to_s.split(/::/).last.downcase
24
+ msg = "Unknown symbol :#{symbol}, please pre-define it in lib/ib/symbols/#{file}.rb"
25
+ error msg, :symbol
26
+ end
20
27
  end
21
28
  end
22
29
  end
@@ -3,72 +3,57 @@ module IB
3
3
  module Forex
4
4
  extend Symbols
5
5
 
6
- # IDEALPRO is for orders over 25,000 and routes to the interbank quote stream.
7
- # IDEAL is for smaller orders, and has wider spreads/slower execution... generally
8
- # used for smaller currency conversions.
9
6
  def self.contracts
10
- @contracts ||= {
11
- :audusd => IB::Contract.new(:symbol => "AUD",
12
- :exchange => "IDEALPRO",
13
- :currency => "USD",
14
- :sec_type => :forex,
15
- :description => "AUDUSD"),
16
-
17
- :gbpusd => IB::Contract.new(:symbol => "GBP",
18
- :exchange => "IDEALPRO",
19
- :currency => "USD",
20
- :sec_type => :forex,
21
- :description => "GBPUSD"),
22
-
23
- :euraud => IB::Contract.new(:symbol => "EUR",
24
- :exchange => "IDEALPRO",
25
- :currency => "AUD",
26
- :sec_type => :forex,
27
- :description => "EURAUD"),
28
-
29
- :eurgbp => IB::Contract.new(:symbol => "EUR",
30
- :exchange => "IDEALPRO",
31
- :currency => "GBP",
32
- :sec_type => :forex,
33
- :description => "EURGBP"),
34
-
35
- :eurjpy => IB::Contract.new(:symbol => "EUR",
36
- :exchange => "IDEALPRO",
37
- :currency => "JPY",
38
- :sec_type => :forex,
39
- :description => "EURJPY"),
40
-
41
- :eurusd => IB::Contract.new(:symbol => "EUR",
42
- :exchange => "IDEALPRO",
43
- :currency => "USD",
44
- :sec_type => :forex,
45
- :description => "EURUSD"),
46
-
47
- :eurcad => IB::Contract.new(:symbol => "EUR",
48
- :exchange => "IDEALPRO",
49
- :currency => "CAD",
50
- :sec_type => :forex,
51
- :description => "EURCAD"),
52
-
53
- :usdchf => IB::Contract.new(:symbol => "USD",
54
- :exchange => "IDEALPRO",
55
- :currency => "CHF",
56
- :sec_type => :forex,
57
- :description => "USDCHF"),
58
-
59
- :usdcad => IB::Contract.new(:symbol => "USD",
60
- :exchange => "IDEALPRO",
61
- :currency => "CAD",
62
- :sec_type => :forex,
63
- :description => "USDCAD"),
64
-
65
- :usdjpy => IB::Contract.new(:symbol => "USD",
66
- :exchange => "IDEALPRO",
67
- :currency => "JPY",
68
- :sec_type => :forex,
69
- :description => "USDJPY")
70
- }
7
+ @contracts ||= define_contracts
8
+ end
9
+
10
+ private
11
+
12
+ # IDEALPRO is for orders over 20,000 and routes to the interbank quote stream.
13
+ # IDEAL is for smaller orders, and has wider spreads/slower execution... generally
14
+ # used for smaller currency conversions. IB::Symbols::Forex contracts are pre-defined
15
+ # on IDEALPRO, if you need something else please define forex contracts manually.
16
+ def self.define_contracts
17
+ @contracts = {}
18
+
19
+ # use combinations of these currencies for pre-defined forex contracts
20
+ recognized_currencies = [
21
+ "aud",
22
+ "cad",
23
+ "chf",
24
+ "eur",
25
+ "gbp",
26
+ "hkd",
27
+ "jpy",
28
+ "nzd",
29
+ "usd"
30
+ ]
31
+
32
+ # create fx symbol list from currency list
33
+ fx_symbol_list = []
34
+ all_pairs = recognized_currencies.product(recognized_currencies)
35
+ all_pairs.each_index do |i|
36
+ fx_symbol_list[i] = (all_pairs[i][0] + all_pairs[i][1]).downcase.to_sym unless all_pairs[i][0] == all_pairs[i][1]
37
+ end
38
+ # delete nil entries in fx_symbol_list array
39
+ fx_symbol_list.compact!
40
+
41
+ # now define each contract
42
+ fx_symbol_list.each do |fx_sym|
43
+ @contracts[fx_sym] = IB::Contract.new(
44
+ :symbol => fx_sym.to_s[0..2].upcase,
45
+ :exchange => "IDEALPRO",
46
+ :currency => fx_sym.to_s[3..5].upcase,
47
+ :sec_type => :forex,
48
+ :description => fx_sym.to_s.upcase
49
+ )
50
+ end
51
+ return @contracts
71
52
  end
72
53
  end
73
54
  end
74
55
  end
56
+
57
+
58
+
59
+