ib-api 972.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.
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