ib-ruby 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
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
+