ib-api 972.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +50 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +16 -0
  7. data/Gemfile.lock +105 -0
  8. data/Guardfile +24 -0
  9. data/LICENSE +674 -0
  10. data/README.md +65 -0
  11. data/Rakefile +11 -0
  12. data/VERSION +1 -0
  13. data/api.gemspec +43 -0
  14. data/bin/console +95 -0
  15. data/bin/console.yml +3 -0
  16. data/bin/setup +8 -0
  17. data/changelog.md +7 -0
  18. data/example/README.md +76 -0
  19. data/example/account_info +54 -0
  20. data/example/account_positions +30 -0
  21. data/example/account_summary +88 -0
  22. data/example/cancel_orders +74 -0
  23. data/example/fa_accounts +25 -0
  24. data/example/fundamental_data +40 -0
  25. data/example/historic_data_cli +186 -0
  26. data/example/list_orders +45 -0
  27. data/example/portfolio_csv +81 -0
  28. data/example/scanner_data +62 -0
  29. data/example/template +19 -0
  30. data/example/tick_data +28 -0
  31. data/lib/extensions/class-extensions.rb +87 -0
  32. data/lib/ib-api.rb +7 -0
  33. data/lib/ib/base.rb +103 -0
  34. data/lib/ib/base_properties.rb +160 -0
  35. data/lib/ib/connection.rb +450 -0
  36. data/lib/ib/constants.rb +393 -0
  37. data/lib/ib/errors.rb +44 -0
  38. data/lib/ib/logger.rb +26 -0
  39. data/lib/ib/messages.rb +99 -0
  40. data/lib/ib/messages/abstract_message.rb +101 -0
  41. data/lib/ib/messages/incoming.rb +251 -0
  42. data/lib/ib/messages/incoming/abstract_message.rb +116 -0
  43. data/lib/ib/messages/incoming/account_value.rb +78 -0
  44. data/lib/ib/messages/incoming/alert.rb +34 -0
  45. data/lib/ib/messages/incoming/contract_data.rb +102 -0
  46. data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
  47. data/lib/ib/messages/incoming/execution_data.rb +50 -0
  48. data/lib/ib/messages/incoming/historical_data.rb +84 -0
  49. data/lib/ib/messages/incoming/market_depths.rb +44 -0
  50. data/lib/ib/messages/incoming/next_valid_id.rb +18 -0
  51. data/lib/ib/messages/incoming/open_order.rb +277 -0
  52. data/lib/ib/messages/incoming/order_status.rb +85 -0
  53. data/lib/ib/messages/incoming/portfolio_value.rb +78 -0
  54. data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
  55. data/lib/ib/messages/incoming/scanner_data.rb +54 -0
  56. data/lib/ib/messages/incoming/ticks.rb +268 -0
  57. data/lib/ib/messages/outgoing.rb +437 -0
  58. data/lib/ib/messages/outgoing/abstract_message.rb +88 -0
  59. data/lib/ib/messages/outgoing/account_requests.rb +112 -0
  60. data/lib/ib/messages/outgoing/bar_requests.rb +250 -0
  61. data/lib/ib/messages/outgoing/place_order.rb +209 -0
  62. data/lib/ib/messages/outgoing/request_marketdata.rb +99 -0
  63. data/lib/ib/messages/outgoing/request_tick_data.rb +21 -0
  64. data/lib/ib/model.rb +4 -0
  65. data/lib/ib/models.rb +14 -0
  66. data/lib/ib/server_versions.rb +114 -0
  67. data/lib/ib/socket.rb +185 -0
  68. data/lib/ib/support.rb +160 -0
  69. data/lib/ib/version.rb +6 -0
  70. data/lib/models/ib/account.rb +85 -0
  71. data/lib/models/ib/account_value.rb +33 -0
  72. data/lib/models/ib/bag.rb +55 -0
  73. data/lib/models/ib/bar.rb +31 -0
  74. data/lib/models/ib/combo_leg.rb +105 -0
  75. data/lib/models/ib/condition.rb +245 -0
  76. data/lib/models/ib/contract.rb +415 -0
  77. data/lib/models/ib/contract_detail.rb +108 -0
  78. data/lib/models/ib/execution.rb +67 -0
  79. data/lib/models/ib/forex.rb +13 -0
  80. data/lib/models/ib/future.rb +15 -0
  81. data/lib/models/ib/index.rb +15 -0
  82. data/lib/models/ib/option.rb +78 -0
  83. data/lib/models/ib/option_detail.rb +55 -0
  84. data/lib/models/ib/order.rb +519 -0
  85. data/lib/models/ib/order_state.rb +152 -0
  86. data/lib/models/ib/portfolio_value.rb +64 -0
  87. data/lib/models/ib/stock.rb +16 -0
  88. data/lib/models/ib/underlying.rb +34 -0
  89. data/lib/models/ib/vertical.rb +96 -0
  90. data/lib/requires.rb +12 -0
  91. metadata +203 -0
@@ -0,0 +1,108 @@
1
+ module IB
2
+
3
+ # Additional Contract properties (volatile, therefore extracted)
4
+ class ContractDetail < IB::Model
5
+ include BaseProperties
6
+
7
+ # All fields Strings, unless specified otherwise:
8
+ prop :market_name, # The market name for this contract.
9
+ :trading_class, # The trading class name for this contract.
10
+ :min_tick, # double: The minimum price tick.
11
+ :price_magnifier, # int: Allows execution and strike prices to be reported
12
+ # consistently with market data, historical data and the
13
+ # order price: Z on LIFFE is reported in index points, not GBP.
14
+
15
+ :order_types, # The list of valid order types for this contract.
16
+ :valid_exchanges, # The list of exchanges this contract is traded on.
17
+ :under_con_id, # int: The underlying contract ID.
18
+ :long_name, # Descriptive name of the asset.
19
+ :contract_month, # The contract month of the underlying futures contract.
20
+
21
+ :agg_group,
22
+ :under_symbol,
23
+ :under_sec_type,
24
+ :market_rule_ids,
25
+ :real_expiration_date,
26
+
27
+
28
+ # For Bonds only
29
+ :valid_next_option_date,
30
+ :valid_next_option_type,
31
+ :valid_next_option_partial,
32
+
33
+ # The industry classification of the underlying/product:
34
+ :industry, # Wide industry. For example, Financial.
35
+ :category, # Industry category. For example, InvestmentSvc.
36
+ :subcategory, # Subcategory. For example, Brokerage.
37
+ [:time_zone, :time_zone_id], # Time zone for the trading hours (e.g. EST)
38
+ :trading_hours, # The trading hours of the product. For example:
39
+ # 20090507:0700-1830,1830-2330;20090508:CLOSED.
40
+ :liquid_hours, # The liquid trading hours of the product. For example,
41
+ # 20090507:0930-1600;20090508:CLOSED.
42
+
43
+ # To support products in Australia which trade in non-currency units, the following
44
+ # attributes have been added to Execution and Contract Details objects:
45
+ :ev_rule, # evRule - String contains the Economic Value Rule name and optional argument,
46
+ # separated by a colon. Examle: aussieBond:YearsToExpiration=3.
47
+ # When the optional argument not present, the value will be followed by a colon.
48
+ [:ev_multiplier, :ev_multipler], # evMultiplier - double, tells you approximately
49
+ # how much the market value of a contract would change if the price were
50
+ # to change by 1. It cannot be used to get market value by multiplying
51
+ # the price by the approximate multiplier.
52
+
53
+ :sec_id_list, # Array with multiple Security ids
54
+ # MD Size Multiplier. Returns the size multiplier for values returned to tickSize from a market data request. Generally 100 for US stocks and 1 for other instruments.
55
+ :md_size_multiplier,
56
+ #
57
+ # BOND values:
58
+ :cusip, # The nine-character bond CUSIP or the 12-character SEDOL.
59
+ :ratings, # Credit rating of the issuer. Higher rating is less risky investment.
60
+ # Bond ratings are from Moody's and S&P respectively.
61
+ :desc_append, # Additional descriptive information about the bond.
62
+ :bond_type, # The type of bond, such as "CORP."
63
+ :coupon_type, # The type of bond coupon.
64
+ :coupon, # double: The interest rate used to calculate the amount you
65
+ # will receive in interest payments over the year. default 0
66
+ :maturity, # The date on which the issuer must repay bond face value
67
+ :issue_date, # The date the bond was issued.
68
+ :next_option_date, # only if bond has embedded options.
69
+ :next_option_type, # only if bond has embedded options.
70
+ :notes, # Additional notes, if populated for the bond in IB's database
71
+ :callable => :bool, # Can be called by the issuer under certain conditions.
72
+ :puttable => :bool, # Can be sold back to the issuer under certain conditions
73
+ :convertible => :bool, # Can be converted to stock under certain conditions.
74
+ :next_option_partial => :bool # # only if bond has embedded options.
75
+
76
+ # Extra validations
77
+ validates_format_of :time_zone, :with => /\A\w{3}\z/, :message => 'should be XXX'
78
+
79
+ serialize :sec_id_list, Hash
80
+
81
+ belongs_to :contract
82
+ alias summary contract
83
+ alias summary= contract=
84
+
85
+ def default_attributes
86
+ super.merge :coupon => 0.0,
87
+ :under_con_id => 0,
88
+ :min_tick => 0,
89
+ :ev_multipler => 0,
90
+ :sec_id_list => Hash.new,
91
+ :callable => false,
92
+ :puttable => false,
93
+ :convertible => false,
94
+ :next_option_partial => false
95
+ end
96
+
97
+ def to_human
98
+ ret = "<ContractDetails #{long_name}, market-name:#{market_name}, "
99
+ ret << "category:#{category}, industry:#{industry} / #{subcategory}, " if category.present?
100
+ ret << "underlying: con_id:#{under_con_id} , sec_type:#{under_sec_type}, symbol:#{under_symbol} " unless under_con_id.zero?
101
+ ret << "ev_multiplier:#{ev_multiplier}, convertible:#{convertible}, cupon:#{coupon}, "
102
+ ret << "md_size_multiplier:#{md_size_multiplier}, min_tick:#{min_tick}, next_option_partial:#{next_option_partial} "
103
+ ret <<"price_magnifier:#{price_magnifier}, puttable:#{puttable}, sec_id-list:#{sec_id_list}, "
104
+ ret <<"valid exchanges: #{ valid_exchanges}, order types: #{order_types} >"
105
+ end
106
+
107
+ end # class ContractDetail
108
+ end # module IB
@@ -0,0 +1,67 @@
1
+ module IB
2
+
3
+ # This is IB Order execution report.
4
+ class Execution < IB::Model
5
+ include BaseProperties
6
+
7
+ belongs_to :order
8
+
9
+ prop :local_id, # int: order id. TWS orders have a fixed order id of 0.
10
+ :client_id, # int: client id. TWS orders have a fixed client id of 0.
11
+ :perm_id, # int: TWS id used to identify orders over TWS sessions
12
+ :exec_id, # String: Unique order execution id over TWS sessions.
13
+ :time, # # TODO: convert into Time object?
14
+ # String: The order execution time.
15
+ :exchange, # String: Exchange that executed the order.
16
+ :order_ref, # String: Same order_ref as in corresponding Order
17
+ :price, # double: The order execution price.
18
+ :average_price, # double: Used in regular trades, combo trades and legs of the combo.
19
+ :ev_rule, # String: Australian products only
20
+ :ev_multiplier, # double: Australian products onlyA
21
+ :model_code,
22
+ :last_liquidity,
23
+
24
+ [:quantity, :shares], # int: The number of shares filled.
25
+ :cumulative_quantity, # int: Used in regular trades, combo trades and legs of combo
26
+ :liquidation => :bool, # This position is liquidated last should the need arise.
27
+ [:account_name, :account_number] => :s, # The customer account number.
28
+ [:side, :action] => PROPS[:side] # Was the transaction a buy or a sale: BOT|SLD
29
+
30
+ # Extra validations
31
+ validates_numericality_of :quantity, :cumulative_quantity, :price, :average_price
32
+ validates_numericality_of :local_id, :client_id, :perm_id, :only_integer => true
33
+
34
+ def default_attributes
35
+ super.merge :local_id => 0,
36
+ :client_id => 0,
37
+ :quantity => 0,
38
+ :price => 0,
39
+ :perm_id => 0,
40
+ :liquidation => false
41
+ end
42
+
43
+ # Comparison
44
+ def == other
45
+ super(other) ||
46
+ other.is_a?(self.class) &&
47
+ perm_id == other.perm_id &&
48
+ local_id == other.local_id && # ((p __LINE__)||true) &&
49
+ client_id == other.client_id &&
50
+ exec_id == other.exec_id &&
51
+ time == other.time &&
52
+ exchange == other.exchange &&
53
+ order_ref == other.order_ref &&
54
+ side == other.side
55
+ # TODO: || compare all attributes!
56
+ end
57
+
58
+ def to_human
59
+ "<Execution: #{time} #{side} #{quantity} at #{price} on #{exchange}, " +
60
+ "cumulative #{cumulative_quantity} at #{average_price}, " +
61
+ "ids #{local_id}/#{perm_id}/#{exec_id}>"
62
+ end
63
+
64
+ alias to_s to_human
65
+
66
+ end # Execution
67
+ end # module IB
@@ -0,0 +1,13 @@
1
+ #require 'models/ib/contract'
2
+ module IB
3
+ class Forex < IB::Contract
4
+ validates_format_of :sec_type, :with => /\Aforex\z/,
5
+ :message => "should be a Currency-Pair"
6
+ def default_attributes
7
+ # Base-currency: USD
8
+ super.merge :sec_type => :forex, currency:'USD', exchange:'IDEALPRO'
9
+ end
10
+
11
+ end
12
+ end
13
+
@@ -0,0 +1,15 @@
1
+ #require 'models/ib/contract'
2
+ module IB
3
+ class Future < Contract
4
+ validates_format_of :sec_type, :with => /\Afuture\z/,
5
+ :message => "should be a Future"
6
+ def default_attributes
7
+ super.merge :sec_type => :future, currency:'USD'
8
+ end
9
+ def to_human
10
+ "<Future: " + [symbol, expiry, currency].join(" ") + ">"
11
+ end
12
+
13
+ end
14
+ end
15
+
@@ -0,0 +1,15 @@
1
+ #require 'models/ib/contract'
2
+ module IB
3
+ class Index < Contract
4
+ validates_format_of :sec_type, :with => /\Aind\z/,
5
+ :message => "should be a Index"
6
+ def default_attributes
7
+ super.merge :sec_type => :ind
8
+ end
9
+ def to_human
10
+ "<Index: " + [symbol, currency].join(" ") + ">"
11
+ end
12
+
13
+ end
14
+ end
15
+
@@ -0,0 +1,78 @@
1
+ require 'models/ib/contract'
2
+ require 'models/ib/option_detail'
3
+
4
+ module IB
5
+ class Option < Contract
6
+
7
+ validates_numericality_of :strike, :greater_than => 0
8
+ validates_format_of :sec_type, :with => /\Aoption\z/,
9
+ :message => "should be an option"
10
+ validates_format_of :local_symbol, :with => /\A\w+\s*\d{6}[pcPC]\d{8}$|\A\z/,
11
+ :message => "invalid OSI code"
12
+ validates_format_of :right, :with => /\Aput$|^call\z/,
13
+ :message => "should be put or call"
14
+
15
+
16
+ # introduce Option.greek with reference to IB::OptionDetail-dataset
17
+ #
18
+ has_one :greek , as: :option_detail
19
+ # For Options, this is contract's OSI (Option Symbology Initiative) name/code
20
+ alias osi local_symbol
21
+
22
+ def osi= value
23
+ # Normalize to 21 char
24
+ self.local_symbol = value.sub(/ /, ' '*(22-value.size))
25
+ end
26
+
27
+ # Make valid IB Contract definition from OSI (Option Symbology Initiative) code.
28
+ # NB: Simply making a new Contract with *local_symbol* (osi) property set to a
29
+ # valid OSI code works just as well, just do NOT set *expiry*, *right* or
30
+ # *strike* properties in this case.
31
+ # This class method provided as a backup and shows how to analyse OSI codes.
32
+ def self.from_osi osi
33
+
34
+ # Parse contract's OSI (OCC Option Symbology Initiative) code
35
+ args = osi.match(/(\w+)\s?(\d\d)(\d\d)(\d\d)([pcPC])(\d+)/).to_a.drop(1)
36
+ symbol = args.shift
37
+ year = 2000 + args.shift.to_i
38
+ month = args.shift.to_i
39
+ day = args.shift.to_i
40
+ right = args.shift.upcase
41
+ strike = args.shift.to_i/1000.0
42
+
43
+ # Set correct expiry date - IB expiry date differs from OSI if expiry date
44
+ # falls on Saturday (see https://github.com/arvicco/option_mower/issues/4)
45
+ expiry_date = Time.utc(year, month, day)
46
+ expiry_date = Time.utc(year, month, day-1) if expiry_date.wday == 6
47
+
48
+ new :symbol => symbol,
49
+ :exchange => "SMART",
50
+ :expiry => expiry_date.to_ib[2..7], # YYMMDD
51
+ :right => right,
52
+ :strike => strike
53
+ end
54
+
55
+ def default_attributes
56
+ super.merge :sec_type => :option
57
+ #self[:description] ||= osi ? osi : "#{symbol} #{strike} #{right} #{expiry}"
58
+ end
59
+ def == other
60
+ super(other) || ( # finish positive, if contract#== is true
61
+ # otherwise, we most probably compare the response from IB with our selfmade input
62
+ exchange == other.exchange &&
63
+ include_expired == other.include_expired &&
64
+ sec_type == other.sec_type &&
65
+ multiplier == other.multiplier &&
66
+ strike == other.strike &&
67
+ right == other.right &&
68
+ multiplier == other.multiplier &&
69
+ expiry == other.expiry )
70
+
71
+ end
72
+
73
+ def to_human
74
+ "<Option: " + [symbol, expiry, right, strike, exchange, currency].join(" ") + ">"
75
+ end
76
+
77
+ end # class Option
78
+ end # module IB
@@ -0,0 +1,55 @@
1
+ module IB
2
+
3
+ # Additional Option properties and Option-Calculations
4
+ class OptionDetail < IB::Model
5
+ include BaseProperties
6
+
7
+ prop :delta, :gamma, :vega, :theta, # greeks
8
+ :implied_volatility,
9
+ :pv_dividend, # anticipated Dividend
10
+ :under_price, # price of the Underlying
11
+ :option_price,
12
+ :close_price,
13
+ :open_tick,
14
+ :bid_price,
15
+ :ask_price,
16
+ :prev_strike,
17
+ :next_strike,
18
+ :prev_expiry,
19
+ :next_expiry,
20
+ :option_price
21
+ belongs_to :option
22
+
23
+ # returns true if all datafields are filled with reasonal data
24
+ def complete?
25
+ fields= [ :delta, :gamma, :vega, :theta,
26
+ :implied_volatility, :pv_dividend, :open_tick,
27
+ :under_price, :option_price, :close_price, :bid_price, :ask_price]
28
+
29
+ !fields.detect{|y| self.send(y).nil?}
30
+
31
+ end
32
+
33
+ def greeks?
34
+ fields= [ :delta, :gamma, :vega, :theta,
35
+ :implied_volatility, :pv_dividend]
36
+
37
+ !fields.detect{|y| self.send(y).nil?}
38
+
39
+ end
40
+
41
+ def to_human
42
+ outstr= ->( item ) { if item.nil? then "--" else sprintf("%g" , item) end }
43
+ att = " optionPrice: #{ outstr[ option_price ]}, UnderlyingPrice: #{ outstr[ under_price] } impl.Vola: #{ outstr[ implied_volatility ]} ; dividend: #{ outstr[ pv_dividend ]}; "
44
+ greeks = "Greeks:: delta: #{ outstr[ delta ] }; gamma: #{ outstr[ gamma ]}, vega: #{ outstr[ vega ] }; theta: #{ outstr[ theta ]}"
45
+ prices= " close: #{ outstr[ close_price ]}; bid: #{ outstr[ bid_price ]}; ask: #{ outstr[ ask_price ]} "
46
+ if complete?
47
+ "< "+ prices + "\n" + att + "\n" + greeks + " >"
48
+ else
49
+ "< " + greeks + " >"
50
+ end
51
+
52
+ end
53
+
54
+ end # class
55
+ end # module
@@ -0,0 +1,519 @@
1
+ require 'models/ib/order_state'
2
+
3
+ module IB
4
+ class Order < IB::Model
5
+ include BaseProperties
6
+
7
+ # General Notes:
8
+ # 1. Placing Orders by con_id - When you place an order by con_id, you must
9
+ # provide the con_id AND the exchange. If you provide extra fields when placing
10
+ # an order by conid, the order may not work.
11
+
12
+ # 2. Order IDs - Each order you place must have a unique Order ID. Increment
13
+ # your own Order IDs to avoid conflicts between orders placed from your API application.
14
+
15
+ # Main order fields
16
+ prop :local_id, # int: Order id associated with client (volatile).
17
+ :client_id, # int: The id of the client that placed this order.
18
+ :perm_id, # int: TWS permanent id, remains the same over TWS sessions.
19
+ :quantity, :total_quantity, # int: The order quantity.
20
+
21
+ :order_type, # String: Order type.
22
+ # Limit Risk: MTL / MKT PRT / QUOTE / STP / STP LMT / TRAIL / TRAIL LIMIT / TRAIL LIT / TRAIL MIT
23
+ # Speed of Execution: MKT / MIT / MOC / MOO / PEG MKT / REL
24
+ # Price Improvement: BOX TOP / LOC / LOO / LIT / PEG MID / VWAP
25
+ # Advanced Trading: OCA / VOL / SCALE
26
+ # Other (no abbreviation): Bracket, Auction, Discretionary, Sweep-to-Fill,
27
+ # Price Improvement Auction, Block, Hidden, Iceberg/Reserve, All-or-None, Fill-or-Kill
28
+ # See 'ib/constants.rb' ORDER_TYPES for a complete list of valid values.
29
+
30
+ :limit_price, # double: LIMIT price, used for limit, stop-limit and relative
31
+ # orders. In all other cases specify zero. For relative
32
+ # orders with no limit price, also specify zero.
33
+ :aux_price, # => 0.0, default set to "" (as implemented in python code)
34
+ #:aux_price, # double: STOP price for stop-limit orders, and the OFFSET amount
35
+ # for relative orders. In all other cases, specify zero.
36
+
37
+ :oca_group, # String: Identifies a member of a one-cancels-all group.
38
+ :oca_type, # int: Tells how to handle remaining orders in an OCA group
39
+ # when one order or part of an order executes. Valid values:
40
+ # - 1 = Cancel all remaining orders with block
41
+ # - 2 = Remaining orders are reduced in size with block
42
+ # - 3 = Remaining orders are reduced in size with no block
43
+ # If you use a value "with block" your order has
44
+ # overfill protection. This means that only one order in
45
+ # the group will be routed at a time to remove the
46
+ # possibility of an overfill.
47
+ :parent_id, # int: The order ID of the parent (original) order, used
48
+ # for bracket (STP) and auto trailing stop (TRAIL) orders.
49
+ :display_size, # int: publicly disclosed order size for Iceberg orders.
50
+
51
+ :trigger_method, # Specifies how Simulated Stop, Stop-Limit and Trailing
52
+ # Stop orders are triggered. Valid values are:
53
+ # 0 - Default, "double bid/ask" for OTC/US options, "last" otherswise.
54
+ # 1 - "double bid/ask" method, stop orders are triggered based on
55
+ # two consecutive bid or ask prices.
56
+ # 2 - "last" method, stops are triggered based on the last price.
57
+ # 3 - double last method.
58
+ # 4 - bid/ask method. For a buy order, a single occurrence of the
59
+ # bid price must be at or above the trigger price. For a sell
60
+ # order, a single occurrence of the ask price must be at or
61
+ # below the trigger price.
62
+ # 7 - last or bid/ask method. For a buy order, a single bid price
63
+ # or the last price must be at or above the trigger price.
64
+ # For a sell order, a single ask price or the last price
65
+ # must be at or below the trigger price.
66
+ # 8 - mid-point method, where the midpoint must be at or above
67
+ # (for a buy) or at or below (for a sell) the trigger price,
68
+ # and the spread between the bid and ask must be less than
69
+ # 0.1% of the midpoint
70
+
71
+ :good_after_time, # Indicates that the trade should be submitted after the
72
+ # time and date set, format YYYYMMDD HH:MM:SS (seconds are optional).
73
+ :good_till_date, # Indicates that the trade should remain working until the
74
+ # time and date set, format YYYYMMDD HH:MM:SS (seconds are optional).
75
+ # You must set the :tif to GTD when using this string.
76
+ # Use an empty String if not applicable.
77
+
78
+ :rule_80a, # Individual = 'I', Agency = 'A', AgentOtherMember = 'W',
79
+ # IndividualPTIA = 'J', AgencyPTIA = 'U', AgentOtherMemberPTIA = 'M',
80
+ # IndividualPT = 'K', AgencyPT = 'Y', AgentOtherMemberPT = 'N'
81
+ :min_quantity, # int: Identifies a minimum quantity order type.
82
+ :percent_offset, # double: percent offset amount for relative (REL)orders only
83
+ :trail_stop_price, # double: for TRAILLIMIT orders only
84
+ # As of client v.56, we receive trailing_percent in openOrder
85
+ :trailing_percent,
86
+
87
+ # Financial advisors only - use an empty String if not applicable.
88
+ :fa_group, :fa_profile, :fa_method, :fa_percentage,
89
+ :model_code , # string, no further reference in docs.
90
+ # Institutional orders only!
91
+ :origin, # 0=Customer, 1=Firm
92
+ :order_ref, # String: Order reference. Customer defined order ID tag.
93
+ :short_sale_slot, # 1 - you hold the shares,
94
+ # 2 - they will be delivered from elsewhere.
95
+ # Only for Action="SSHORT
96
+ :designated_location, # String: set when slot==2 only
97
+ :exempt_code, # int
98
+
99
+ # Clearing info
100
+ :account, # String: The account number (Uxxx). For institutional customers only.
101
+ :settling_firm, # String: Institutional only
102
+ :clearing_account, # String: For IBExecution customers: Specifies the
103
+ # true beneficiary of the order. This value is required
104
+ # for FUT/FOP orders for reporting to the exchange.
105
+ :clearing_intent, # IBExecution customers: "", IB, Away, PTA (post trade allocation).
106
+
107
+ # SMART routing only
108
+ :discretionary_amount, # double: The amount off the limit price
109
+ # allowed for discretionary orders.
110
+ :nbbo_price_cap, # double: Maximum Smart order distance from the NBBO.
111
+
112
+ # BOX or VOL ORDERS ONLY
113
+ :auction_strategy, # For BOX exchange only. Valid values:
114
+ # 1=AUCTION_MATCH, 2=AUCTION_IMPROVEMENT, 3=AUCTION_TRANSPARENT
115
+ :starting_price, # double: Starting price. Valid on BOX orders only.
116
+ :stock_ref_price, # double: The stock reference price, used for VOL
117
+ # orders to compute the limit price sent to an exchange (whether or not
118
+ # Continuous Update is selected), and for price range monitoring.
119
+ :delta, # double: Stock delta. Valid on BOX orders only.
120
+
121
+ # Pegged to stock or VOL orders. For price improvement option orders
122
+ # on BOX and VOL orders with dynamic management:
123
+ :stock_range_lower, # double: The lower value for the acceptable
124
+ # underlying stock price range.
125
+ :stock_range_upper, # double The upper value for the acceptable
126
+ # underlying stock price range.
127
+
128
+ # VOLATILITY ORDERS ONLY:
129
+ # http://www.interactivebrokers.com/en/general/education/pdfnotes/PDF-VolTrader.php
130
+ :volatility, # double: What the price is, computed via TWSs Options
131
+ # Analytics. For VOL orders, the limit price sent to an
132
+ # exchange is not editable, as it is the output of a
133
+ # function. Volatility is expressed as a percentage.
134
+ :volatility_type, # int: How the volatility is calculated: 1=daily, 2=annual
135
+ :reference_price_type, # int: For dynamic management of volatility orders:
136
+ # - 1 = Average of National Best Bid or Ask,
137
+ # - 2 = National Best Bid when buying a call or selling a put;
138
+ # and National Best Ask when selling a call or buying a put.
139
+ :continuous_update, # int: Used for dynamic management of volatility orders.
140
+ # Determines whether TWS is supposed to update the order price as the underlying
141
+ # moves. If selected, the limit price sent to an exchange is modified by TWS
142
+ # if the computed price of the option changes enough to warrant doing so. This
143
+ # is helpful in keeping the limit price up to date as the underlying price changes.
144
+ :delta_neutral_order_type, # String: Enter an order type to instruct TWS
145
+ # to submit a delta neutral trade on full or partial execution of the
146
+ # VOL order. For no hedge delta order to be sent, specify NONE.
147
+ # Valid values - LMT, MKT, MTL, REL, MOC
148
+ :delta_neutral_aux_price, # double: Use this field to enter a value if
149
+ # the value in the deltaNeutralOrderType field is an order
150
+ # type that requires an Aux price, such as a REL order.
151
+
152
+ # As of client v.52, we also receive delta... params in openOrder
153
+ :delta_neutral_designated_location,
154
+ :delta_neutral_con_id,
155
+ :delta_neutral_settling_firm,
156
+ :delta_neutral_clearing_account,
157
+ :delta_neutral_clearing_intent,
158
+ # Used when the hedge involves a stock and indicates whether or not it is sold short.
159
+ :delta_neutral_short_sale,
160
+ # Has a value of 1 (the clearing broker holds shares) or 2 (delivered from a third party).
161
+ # If you use 2, then you must specify a deltaNeutralDesignatedLocation.
162
+ :delta_neutral_short_sale_slot,
163
+ # Specifies whether the order is an Open or a Close order and is used
164
+ # when the hedge involves a CFD and and the order is clearing away.
165
+ :delta_neutral_open_close,
166
+
167
+ # HEDGE ORDERS ONLY:
168
+ # As of client v.49/50, we can now add hedge orders using the API.
169
+ # Hedge orders are child orders that take additional fields. There are four
170
+ # types of hedging orders supported by the API: Delta, Beta, FX, Pair.
171
+ # All hedge orders must have a parent order submitted first. The hedge order
172
+ # should set its :parent_id. If the hedgeType is Beta, the beta sent in the
173
+ # hedgeParm can be zero, which means it is not used. Delta is only valid
174
+ # if the parent order is an option and the child order is a stock.
175
+
176
+ :hedge_type, # String: D = Delta, B = Beta, F = FX or P = Pair
177
+ :hedge_param, # String; value depends on the hedgeType; sent from the API
178
+ # only if hedge_type is NOT null. It is required for Pair hedge order,
179
+ # optional for Beta hedge orders, and ignored for Delta and FX hedge orders.
180
+
181
+ # COMBO ORDERS ONLY:
182
+ :basis_points, # double: EFP orders only
183
+ :basis_points_type, # double: EFP orders only
184
+
185
+ # ALGO ORDERS ONLY:
186
+ :algo_strategy, # String
187
+ :algo_params, # public Vector<TagValue> m_algoParams; ?!
188
+ :algo_id, # since Vers. 71
189
+ # SCALE ORDERS ONLY:
190
+ :scale_init_level_size, # int: Size of the first (initial) order component.
191
+ :scale_subs_level_size, # int: Order size of the subsequent scale order
192
+ # components. Used in conjunction with scaleInitLevelSize().
193
+ :scale_price_increment, # double: Price increment between scale components.
194
+ # This field is required for Scale orders.
195
+
196
+ # As of client v.54, we can receive additional scale order fields:
197
+ :scale_price_adjust_value,
198
+ :scale_price_adjust_interval,
199
+ :scale_profit_offset,
200
+ :scale_init_position,
201
+ :scale_init_fill_qty,
202
+ :scale_table, # Vers 69
203
+ :active_start_time, # Vers 69
204
+ :active_stop_time, # Vers 69
205
+ # pegged to benchmark
206
+ :reference_contract_id,
207
+ :is_pegged_change_amount_decrease,
208
+ :pegged_change_amount,
209
+ :reference_change_amount,
210
+ :reference_exchange_id ,
211
+
212
+ :conditions, # Conditions determining when the order will be activated or canceled.
213
+ ### http://xavierib.github.io/twsapidocs/order_conditions.html
214
+ :conditions_ignore_rth, # bool: Indicates whether or not conditions will also be valid outside Regular Trading Hours
215
+ :conditions_cancel_order,# bool: Conditions can determine if an order should become active or canceled.
216
+ :adjusted_order_type,
217
+ :trigger_price,
218
+ :limit_price_offset, # used in trailing stop limit + trailing limit orders
219
+ :adjusted_stop_price,
220
+ :adjusted_stop_limit_price,
221
+ :adjusted_trailing_amount,
222
+
223
+ :adjustable_trailing_unit,
224
+ :ext_operator , # 105: MIN_SERVER_VER_EXT_OPERATOR
225
+ # This is a regulartory attribute that applies
226
+ # to all US Commodity (Futures) Exchanges, provided
227
+ # to allow client to comply with CFTC Tag 50 Rules.
228
+ :soft_dollar_tier_name, # 106: MIN_SERVER_VER_SOFT_DOLLAR_TIER
229
+ :soft_dollar_tier_value,
230
+ :soft_dollar_tier_display_name,
231
+ # Define the Soft Dollar Tier used for the order.
232
+ # Only provided for registered professional advisors and hedge and mutual funds.
233
+ # format: "#{name}=#{value},#{display_name}", name and value are used in the
234
+ # order-specification. Its included as ["#{name}","#{value}"] pair
235
+
236
+ :cash_qty, # 111: MIN_SERVER_VER_CASH_QTY
237
+ # decimal : The native cash quantity
238
+ :mifid_2_decision_maker,
239
+ :mifid_2_decision_algo,
240
+ :mifid_2_execution_maker,
241
+ :mifid_2_execution_algo,
242
+ :dont_use_auto_price_for_hedge,
243
+ :discretionary_up_to_limit_price
244
+
245
+ # Properties with complex processing logics
246
+ prop :tif, # String: Time in Force (time to market): DAY/GAT/GTD/GTC/IOC
247
+ :random_size => :bool, # Vers 76
248
+ :random_price => :bool, # Vers 76
249
+ :scale_auto_reset => :bool,
250
+ :scale_random_percent => :bool,
251
+ :solicided => :bool, # Vers 73
252
+ :what_if => :bool, # Only return pre-trade commissions and margin info, do not place
253
+ :not_held => :bool, # Not Held
254
+ :outside_rth => :bool, # Order may trigger or fill outside of regular hours. (WAS: ignore_rth)
255
+ :hidden => :bool, # Order will not be visible in market depth. ISLAND only.
256
+ :transmit => :bool, # If false, order will be created but not transmitted.
257
+ :block_order => :bool, # This is an ISE Block order.
258
+ :sweep_to_fill => :bool, # This is a Sweep-to-Fill order.
259
+ :override_percentage_constraints => :bool,
260
+ # TWS Presets page constraints ensure that your price and size order values
261
+ # are reasonable. Orders sent from the API are also validated against these
262
+ # safety constraints, unless this parameter is set to True.
263
+ :all_or_none => :bool, # AON
264
+ :etrade_only => :bool, # Trade with electronic quotes.
265
+ :firm_quote_only => :bool, # Trade with firm quotes.
266
+ :opt_out_smart_routing => :bool, # Australian exchange only, default false
267
+ :open_close => PROPS[:open_close], # Originally String: O=Open, C=Close ()
268
+ # for ComboLeg compatibility: SAME = 0; OPEN = 1; CLOSE = 2; UNKNOWN = 3;
269
+ [:side, :action] => PROPS[:side], # String: Action/side: BUY/SELL/SSHORT/SSHORTX
270
+ :is_O_ms_container => :bool
271
+
272
+ prop :placed_at,
273
+ :modified_at,
274
+ :leg_prices,
275
+ :algo_params,
276
+ :combo_params # Valid tags are LeginPrio, MaxSegSize, DontLeginNext, ChangeToMktTime1,
277
+ # ChangeToMktTime2, ChangeToMktOffset, DiscretionaryPct, NonGuaranteed,
278
+ # CondPriceMin, CondPriceMax, and PriceCondConid.
279
+ # to set an execuction-range of a security:
280
+ # PriceCondConid, 10375; -- conid of the combo-leg
281
+ # CondPriceMax, 62.0; -- max and min-price
282
+ # CondPriceMin.;60.0
283
+
284
+
285
+ # prop :misc1, :misc2, :misc3, :misc4, :misc5, :misc6, :misc7, :misc8 # just 4 debugging
286
+
287
+ alias order_combo_legs leg_prices
288
+ alias smart_combo_routing_params combo_params
289
+
290
+ # serialize is included for active_record compatibility
291
+ # serialize :leg_prices
292
+ # serialize :conditions
293
+ # serialize :algo_params, Hash
294
+ # serialize :combo_params
295
+ # serialize :soft_dollar_tier_params, HashWithIndifferentAccess
296
+ serialize :mics_options, Hash
297
+
298
+ # Order is always placed for a contract. Here, we explicitly set this link.
299
+ belongs_to :contract
300
+
301
+ # Order has a collection of Executions if it was filled
302
+ has_many :executions
303
+
304
+ # Order has a collection of OrderStates, last one is always current
305
+ has_many :order_states
306
+ # Order can have multible conditions
307
+ has_many :conditions
308
+
309
+ def order_state
310
+ order_states.last
311
+ end
312
+
313
+ def order_state= state
314
+ self.order_states.push case state
315
+ when IB::OrderState
316
+ state
317
+ when Symbol, String
318
+ IB::OrderState.new :status => state
319
+ end
320
+ end
321
+
322
+ # Some properties received from IB are separated into OrderState object,
323
+ # but they are still readable as Order properties through delegation:
324
+ # Properties arriving via OpenOrder message:
325
+ [:commission, # double: Shows the commission amount on the order.
326
+ :commission_currency, # String: Shows the currency of the commission.
327
+ :min_commission, # The possible min range of the actual order commission.
328
+ :max_commission, # The possible max range of the actual order commission.
329
+ :warning_text, # String: Displays a warning message if warranted.
330
+ :init_margin, # Float: The impact the order would have on your initial margin.
331
+ :maint_margin, # Float: The impact the order would have on your maintenance margin.
332
+ :equity_with_loan, # Float: The impact the order would have on your equity
333
+ :status, # String: Displays the order status. See OrderState for values
334
+ # Properties arriving via OrderStatus message:
335
+ :filled, # int
336
+ :remaining, # int
337
+ :price, # double
338
+ :last_fill_price, # double
339
+ :average_price, # double
340
+ :average_fill_price, # double
341
+ :why_held, # String: comma-separated list of reasons for order to be held.
342
+ # Testing Order state:
343
+ :new?,
344
+ :submitted?,
345
+ :pending?,
346
+ :active?,
347
+ :inactive?,
348
+ :complete_fill?
349
+ ].each { |property| define_method(property) { order_state.send(property) } }
350
+
351
+ # Order is not valid without correct :local_id
352
+ validates_numericality_of :local_id, :perm_id, :client_id, :parent_id,
353
+ :total_quantity, :min_quantity, :display_size,
354
+ :only_integer => true, :allow_nil => true
355
+
356
+ validates_numericality_of :limit_price, :aux_price, :allow_nil => true
357
+
358
+
359
+ def default_attributes # default valus are taken from order.java
360
+ # public Order() { }
361
+ super.merge(
362
+ :active_start_time => "", # order.java # 470 # Vers 69
363
+ :active_stop_time => "", #order.java # 471 # Vers 69
364
+ :algo_strategy => '',
365
+ :algo_id => '' , # order.java # 495
366
+ :auction_strategy => :none,
367
+ :conditions => [],
368
+ :continuous_update => 0,
369
+ :designated_location => '', # order.java # 487
370
+ :display_size => 0,
371
+ :discretionary_amount => 0,
372
+ :etrade_only => true, # stolen from python client
373
+ :exempt_code => -1,
374
+ :ext_operator => '' , # order.java # 499
375
+ :firm_quote_only => true, # stolen from python client
376
+ :not_held => false, # order.java # 494
377
+ :oca_type => :none,
378
+ :order_type => :limit,
379
+ :open_close => :open, # order.java #
380
+ :opt_out_smart_routing => false,
381
+ :origin => :customer,
382
+ :outside_rth => false, # order.java # 472
383
+ :parent_id => 0,
384
+ :random_size => false, #oder.java 497 # Vers 76
385
+ :random_price => false, # order.java # 498 # Vers 76
386
+ :scale_auto_reset => false, # order.java # 490
387
+ :scale_random_percent => false, # order.java # 491
388
+ :scale_table => "", # order.java # 492
389
+ :short_sale_slot => :default,
390
+ :solicided => false, # order.java # 496
391
+ :tif => :day,
392
+ :transmit => true,
393
+ :trigger_method => :default,
394
+ :what_if => false, # order.java # 493
395
+ :leg_prices => [],
396
+ :algo_params => Hash.new, #{},
397
+ :combo_params =>[], #{},
398
+ # :soft_dollar_tier_params => HashWithIndifferentAccess.new(
399
+ # :name => "",
400
+ # :val => "",
401
+ # :display_name => ''),
402
+ :order_state => IB::OrderState.new(:status => 'New',
403
+ :filled => 0,
404
+ :remaining => 0,
405
+ :price => 0,
406
+ :average_price => 0)
407
+ ) # closing of merge
408
+ end
409
+
410
+
411
+ =begin rdoc
412
+ Format of serialisation
413
+
414
+ count of records
415
+ for each condition: conditiontype, condition-fields
416
+ =end
417
+ def serialize_conditions
418
+ if conditions.empty?
419
+ 0
420
+ else
421
+ [ conditions.count ] + conditions.map( &:serialize )+ [ conditions_ignore_rth, conditions_cancel_order]
422
+ end
423
+ end
424
+
425
+ def serialize_algo
426
+ if algo_strategy.nil? || algo_strategy.empty?
427
+ [algo_strategy, algo_id] # just omit the size and content-field
428
+ else
429
+ [algo_strategy,
430
+ algo_params.size,
431
+ algo_params.to_a,
432
+ algo_id ] # Vers 71
433
+ end
434
+ end
435
+
436
+ # def serialize_soft_dollar_tier
437
+ # [soft_dollar_tier_params[:name],soft_dollar_tier_params[:val]]
438
+ # end
439
+
440
+ # def initialize_soft_dollar_tier *fields
441
+ # self.soft_dollar_tier_params= HashWithIndifferentAccess.new(
442
+ # name: fields.pop, val: fields.pop, display_name: fields.pop )
443
+ # end
444
+
445
+ def serialize_misc_options
446
+ "" # Vers. 70
447
+ end
448
+ # Placement
449
+ #
450
+ # The Order is only placed, if local_id is not set
451
+ #
452
+ # Modifies the Order-Object and returns the assigned local_id
453
+ def place the_contract=nil, connection=nil
454
+ connection ||= IB::Connection.current
455
+ error "Unable to place order, next_local_id not known" unless connection.next_local_id
456
+ error "local_id present. Order is already placed. Do you want to modify?" unless local_id.nil?
457
+ self.client_id = connection.client_id
458
+ self.local_id = connection.next_local_id
459
+ connection.next_local_id += 1
460
+ self.placed_at = Time.now
461
+ modify the_contract, connection, self.placed_at
462
+ end
463
+
464
+ # Modify Order (convenience wrapper for send_message :PlaceOrder). Returns local_id.
465
+ def modify the_contract=nil, connection=nil, time=Time.now
466
+ error "Unable to modify order; local_id not specified" if local_id.nil?
467
+ self.contract = the_contract unless the_contract.nil?
468
+ connection ||= IB::Connection.current
469
+ self.modified_at = time
470
+ connection.send_message :PlaceOrder,
471
+ :order => self,
472
+ :contract => contract,
473
+ :local_id => local_id
474
+ local_id
475
+ end
476
+
477
+ # Order comparison
478
+ def == other
479
+ super(other) ||
480
+ other.is_a?(self.class) &&
481
+ (perm_id && other.perm_id && perm_id == other.perm_id ||
482
+ local_id == other.local_id && # ((p __LINE__)||true) &&
483
+ (client_id == other.client_id || client_id == 0 || other.client_id == 0) &&
484
+ parent_id == other.parent_id &&
485
+ tif == other.tif &&
486
+ action == other.action &&
487
+ order_type == other.order_type &&
488
+ total_quantity == other.total_quantity &&
489
+ limit_price == other.limit_price &&
490
+ aux_price == other.aux_price &&
491
+ origin == other.origin &&
492
+ designated_location == other.designated_location &&
493
+ exempt_code == other.exempt_code &&
494
+ what_if == other.what_if &&
495
+ algo_strategy == other.algo_strategy &&
496
+ algo_params == other.algo_params)
497
+
498
+ # TODO: compare more attributes!
499
+ end
500
+
501
+ def to_s #human
502
+ "<Order:" + instance_variables.map do |key|
503
+ value = instance_variable_get(key)
504
+ " #{key}=#{value}" unless value.nil? || value == '' || value == 0
505
+ end.compact.join(',') + " >"
506
+ end
507
+
508
+ def to_human
509
+ "<Order: " + (order_ref.present? ? order_ref.to_s : '') +
510
+ "#{self[:order_type]} #{self[:tif]} #{action} #{total_quantity} " + " @ " +
511
+ (limit_price ? "#{limit_price} " : '') + "#{status} " +
512
+ ((aux_price && aux_price != 0) ? "/#{aux_price}" : '') +
513
+ "##{local_id}/#{perm_id} from #{client_id}" +
514
+ (account ? "/#{account}" : '') +
515
+ (commission ? " fee #{commission}" : '') + ">"
516
+ end
517
+
518
+ end # class Order
519
+ end # module IB