ib-api 10.33.1
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.
- checksums.yaml +7 -0
- data/.gitignore +52 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CLAUDE.md +131 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +120 -0
- data/Guardfile +24 -0
- data/LICENSE +674 -0
- data/LLM_GUIDE.md +388 -0
- data/README.md +114 -0
- data/Rakefile +11 -0
- data/VERSION +1 -0
- data/api.gemspec +50 -0
- data/bin/console +96 -0
- data/bin/console.yml +3 -0
- data/bin/setup +8 -0
- data/bin/simple +91 -0
- data/changelog.md +32 -0
- data/conditions/ib/execution_condition.rb +31 -0
- data/conditions/ib/margin_condition.rb +28 -0
- data/conditions/ib/order_condition.rb +29 -0
- data/conditions/ib/percent_change_condition.rb +34 -0
- data/conditions/ib/price_condition.rb +44 -0
- data/conditions/ib/time_condition.rb +42 -0
- data/conditions/ib/volume_condition.rb +36 -0
- data/lib/class_extensions.rb +167 -0
- data/lib/ib/base.rb +109 -0
- data/lib/ib/base_properties.rb +178 -0
- data/lib/ib/connection.rb +573 -0
- data/lib/ib/constants.rb +402 -0
- data/lib/ib/contract.rb +30 -0
- data/lib/ib/errors.rb +52 -0
- data/lib/ib/messages/abstract_message.rb +68 -0
- data/lib/ib/messages/incoming/abstract_message.rb +116 -0
- data/lib/ib/messages/incoming/abstract_tick.rb +25 -0
- data/lib/ib/messages/incoming/account_message.rb +26 -0
- data/lib/ib/messages/incoming/alert.rb +34 -0
- data/lib/ib/messages/incoming/contract_data.rb +105 -0
- data/lib/ib/messages/incoming/contract_message.rb +13 -0
- data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
- data/lib/ib/messages/incoming/execution_data.rb +50 -0
- data/lib/ib/messages/incoming/histogram_data.rb +30 -0
- data/lib/ib/messages/incoming/historical_data.rb +65 -0
- data/lib/ib/messages/incoming/historical_data_update.rb +50 -0
- data/lib/ib/messages/incoming/managed_accounts.rb +21 -0
- data/lib/ib/messages/incoming/market_depth.rb +34 -0
- data/lib/ib/messages/incoming/market_depth_l2.rb +15 -0
- data/lib/ib/messages/incoming/next_valid_id.rb +19 -0
- data/lib/ib/messages/incoming/open_order.rb +290 -0
- data/lib/ib/messages/incoming/order_status.rb +85 -0
- data/lib/ib/messages/incoming/portfolio_value.rb +47 -0
- data/lib/ib/messages/incoming/position_data.rb +21 -0
- data/lib/ib/messages/incoming/positions_multi.rb +15 -0
- data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
- data/lib/ib/messages/incoming/receive_fa.rb +30 -0
- data/lib/ib/messages/incoming/scanner_data.rb +54 -0
- data/lib/ib/messages/incoming/tick_by_tick.rb +77 -0
- data/lib/ib/messages/incoming/tick_efp.rb +18 -0
- data/lib/ib/messages/incoming/tick_generic.rb +12 -0
- data/lib/ib/messages/incoming/tick_option.rb +60 -0
- data/lib/ib/messages/incoming/tick_price.rb +60 -0
- data/lib/ib/messages/incoming/tick_size.rb +55 -0
- data/lib/ib/messages/incoming/tick_string.rb +13 -0
- data/lib/ib/messages/incoming.rb +292 -0
- data/lib/ib/messages/outgoing/abstract_message.rb +84 -0
- data/lib/ib/messages/outgoing/bar_request_message.rb +247 -0
- data/lib/ib/messages/outgoing/new-place-order.rb +193 -0
- data/lib/ib/messages/outgoing/old-place-order.rb +147 -0
- data/lib/ib/messages/outgoing/place_order.rb +149 -0
- data/lib/ib/messages/outgoing/request_account_summary.rb +79 -0
- data/lib/ib/messages/outgoing/request_historical_data.rb +182 -0
- data/lib/ib/messages/outgoing/request_market_data.rb +102 -0
- data/lib/ib/messages/outgoing/request_market_depth.rb +57 -0
- data/lib/ib/messages/outgoing/request_real_time_bars.rb +48 -0
- data/lib/ib/messages/outgoing/request_scanner_subscription.rb +73 -0
- data/lib/ib/messages/outgoing/request_tick_by_tick_data.rb +21 -0
- data/lib/ib/messages/outgoing.rb +410 -0
- data/lib/ib/messages.rb +139 -0
- data/lib/ib/order_condition.rb +26 -0
- data/lib/ib/plugins.rb +27 -0
- data/lib/ib/prepare_data.rb +61 -0
- data/lib/ib/raw_message_parser.rb +99 -0
- data/lib/ib/socket.rb +83 -0
- data/lib/ib/support.rb +236 -0
- data/lib/ib/version.rb +6 -0
- data/lib/ib-api.rb +44 -0
- data/lib/server_versions.rb +145 -0
- data/lib/support/array_function.rb +28 -0
- data/lib/support/logging.rb +45 -0
- data/models/ib/account.rb +72 -0
- data/models/ib/account_value.rb +33 -0
- data/models/ib/bag.rb +55 -0
- data/models/ib/bar.rb +31 -0
- data/models/ib/combo_leg.rb +127 -0
- data/models/ib/contract.rb +411 -0
- data/models/ib/contract_detail.rb +118 -0
- data/models/ib/execution.rb +67 -0
- data/models/ib/forex.rb +12 -0
- data/models/ib/future.rb +64 -0
- data/models/ib/index.rb +14 -0
- data/models/ib/option.rb +149 -0
- data/models/ib/option_detail.rb +84 -0
- data/models/ib/order.rb +720 -0
- data/models/ib/order_state.rb +155 -0
- data/models/ib/portfolio_value.rb +86 -0
- data/models/ib/spread.rb +176 -0
- data/models/ib/stock.rb +25 -0
- data/models/ib/underlying.rb +32 -0
- data/plugins/ib/advanced-account.rb +442 -0
- data/plugins/ib/alerts/base-alert.rb +125 -0
- data/plugins/ib/alerts/gateway-alerts.rb +15 -0
- data/plugins/ib/alerts/order-alerts.rb +73 -0
- data/plugins/ib/auto-adjust.rb +0 -0
- data/plugins/ib/connection-tools.rb +122 -0
- data/plugins/ib/eod.rb +326 -0
- data/plugins/ib/greeks.rb +102 -0
- data/plugins/ib/managed-accounts.rb +274 -0
- data/plugins/ib/market-price.rb +150 -0
- data/plugins/ib/option-chain.rb +167 -0
- data/plugins/ib/order-flow.rb +157 -0
- data/plugins/ib/order-prototypes/abstract.rb +67 -0
- data/plugins/ib/order-prototypes/adaptive.rb +40 -0
- data/plugins/ib/order-prototypes/all-in-one.rb +46 -0
- data/plugins/ib/order-prototypes/combo.rb +46 -0
- data/plugins/ib/order-prototypes/forex.rb +40 -0
- data/plugins/ib/order-prototypes/limit.rb +193 -0
- data/plugins/ib/order-prototypes/market.rb +116 -0
- data/plugins/ib/order-prototypes/pegged.rb +169 -0
- data/plugins/ib/order-prototypes/premarket.rb +31 -0
- data/plugins/ib/order-prototypes/stop.rb +202 -0
- data/plugins/ib/order-prototypes/volatility.rb +39 -0
- data/plugins/ib/order-prototypes.rb +118 -0
- data/plugins/ib/probability-of-expiring.rb +109 -0
- data/plugins/ib/process-orders.rb +155 -0
- data/plugins/ib/roll.rb +86 -0
- data/plugins/ib/spread-prototypes/butterfly.rb +77 -0
- data/plugins/ib/spread-prototypes/calendar.rb +97 -0
- data/plugins/ib/spread-prototypes/stock-spread.rb +56 -0
- data/plugins/ib/spread-prototypes/straddle.rb +70 -0
- data/plugins/ib/spread-prototypes/strangle.rb +93 -0
- data/plugins/ib/spread-prototypes/vertical.rb +83 -0
- data/plugins/ib/spread-prototypes.rb +70 -0
- data/plugins/ib/symbols/abstract.rb +136 -0
- data/plugins/ib/symbols/bonds.rb +28 -0
- data/plugins/ib/symbols/cfd.rb +19 -0
- data/plugins/ib/symbols/combo.rb +46 -0
- data/plugins/ib/symbols/commodity.rb +17 -0
- data/plugins/ib/symbols/forex.rb +41 -0
- data/plugins/ib/symbols/futures.rb +127 -0
- data/plugins/ib/symbols/index.rb +43 -0
- data/plugins/ib/symbols/options.rb +99 -0
- data/plugins/ib/symbols/stocks.rb +44 -0
- data/plugins/ib/symbols/version.rb +5 -0
- data/plugins/ib/symbols.rb +118 -0
- data/plugins/ib/verify.rb +226 -0
- data/symbols/w20.yml +210 -0
- data/t.txt +20 -0
- data/update.md +71 -0
- metadata +327 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
|
|
3
|
+
=begin
|
|
4
|
+
|
|
5
|
+
Plugin to support a simple Order-Flow
|
|
6
|
+
|
|
7
|
+
Public API
|
|
8
|
+
==========
|
|
9
|
+
|
|
10
|
+
Extends IB::Order
|
|
11
|
+
|
|
12
|
+
* check_margin
|
|
13
|
+
* depends on a previously submitted `what-if' order
|
|
14
|
+
* on success it returns the order-object for further processing, otherwise nil.
|
|
15
|
+
* place
|
|
16
|
+
* submit the order
|
|
17
|
+
* return a order-object for further processing
|
|
18
|
+
* modify
|
|
19
|
+
* modify price or quantity of the submitted order
|
|
20
|
+
* cancel
|
|
21
|
+
* submit a cancel request
|
|
22
|
+
|
|
23
|
+
=end
|
|
24
|
+
module OrderFlow
|
|
25
|
+
# Placement
|
|
26
|
+
#
|
|
27
|
+
# The Order is only placed, if local_id is not set
|
|
28
|
+
#
|
|
29
|
+
# Modifies the Order-Object and returns the assigned local_id
|
|
30
|
+
def place
|
|
31
|
+
connection = IB::Connection.current
|
|
32
|
+
error "Unable to place order, next_local_id not known" unless connection.next_local_id
|
|
33
|
+
error "local_id present. Order is already placed. Do you want to modify?" unless local_id.nil?
|
|
34
|
+
# self.client_id = connection.client_id
|
|
35
|
+
self.local_id = connection.next_local_id
|
|
36
|
+
connection.next_local_id += 1
|
|
37
|
+
self.placed_at = Time.now
|
|
38
|
+
#connection.place_order self.dup.then{|y| y.contract = nil; y}, contract
|
|
39
|
+
modify
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Modify Order (convenience wrapper for send_message :PlaceOrder), returns order record received trom tws
|
|
43
|
+
def modify
|
|
44
|
+
error "Unable to modify order; local_id not specified" if local_id.nil?
|
|
45
|
+
error "Unable to place order, contract has to be specified" unless contract.is_a?( IB::Contract )
|
|
46
|
+
|
|
47
|
+
ib = IB::Connection.current
|
|
48
|
+
q = Queue.new
|
|
49
|
+
is = ib.subscribe( :OpenOrder ) do | msg |
|
|
50
|
+
puts msg.to_human
|
|
51
|
+
if msg.order.local_id == local_id
|
|
52
|
+
q << msg.order
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
ia = ib.subscribe( :Alert ) do | msg|
|
|
56
|
+
ib.logger.error msg.to_human
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
self.modified_at = Time.now
|
|
60
|
+
ib.send_message :PlaceOrder,
|
|
61
|
+
:local_id => local_id,
|
|
62
|
+
:order => self.dup.then{|y| y.contract = nil; y},
|
|
63
|
+
:contract => if contract.con_id.to_i > 0
|
|
64
|
+
Contract.new con_id: the_contract.con_id,
|
|
65
|
+
exchange: the_contract.exchange
|
|
66
|
+
else
|
|
67
|
+
contract
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
th = Thread.new{ sleep 1 ; q.close }
|
|
71
|
+
received_order = q.pop # synchronize
|
|
72
|
+
ib.unsubscribe ia, is
|
|
73
|
+
if q.closed?
|
|
74
|
+
error "order #{to_human} is not accepted", :reader
|
|
75
|
+
self # return original error after error handling
|
|
76
|
+
else
|
|
77
|
+
Thread.kill th
|
|
78
|
+
q.close
|
|
79
|
+
received_order
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# returns the order if the margin-requirements are met
|
|
84
|
+
#
|
|
85
|
+
# Details of the test are published in the log (level: LOGGER::INOT)
|
|
86
|
+
#
|
|
87
|
+
# typical setup
|
|
88
|
+
# ```ruby
|
|
89
|
+
# ib = IB::Connection.new
|
|
90
|
+
# ib.activate_plugin ...
|
|
91
|
+
# u = ib.clients.last
|
|
92
|
+
# submitted_order = u.preview( order: some_order, contract: some_contract )
|
|
93
|
+
# .check_margin( 0.25 ) &.place
|
|
94
|
+
# place order only if after its placement Equity-with-loan ist minimal 25 percent higher then the margin requirements
|
|
95
|
+
# i.e. the margin utilization is max. 75 %.
|
|
96
|
+
#
|
|
97
|
+
# ```
|
|
98
|
+
def check_margin treshold = 0.1
|
|
99
|
+
error "Unable to check margin, forcast is not initialized" if order_state.nil? or order_state.init_margin_after.nil?
|
|
100
|
+
utilization = order_state.init_margin_after / order_state.equity_with_loan_after
|
|
101
|
+
if 1 - utilization > treshold
|
|
102
|
+
Connection.current.logger.info "Margin OK: #{action} #{total_quantity} of #{contract.to_human}: requirements: #{order_state.init_margin_change.round} #{contract.currency} equals to #{utilization.round(1) *100} % margin utilization"
|
|
103
|
+
self
|
|
104
|
+
else
|
|
105
|
+
Connection.current.logger.info "Margin requirements NOT met, utilization: #{utilization.round(2) *100} % ( margin requirement: #{order_state.init_margin_change.round} #{contract.currency})"
|
|
106
|
+
nil
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
#
|
|
110
|
+
# Auto Adjust implements a simple algorithm to ensure that an order is accepted
|
|
111
|
+
|
|
112
|
+
# It reads `contract_detail.min_tick`.
|
|
113
|
+
#
|
|
114
|
+
# For min-tick smaller then 0.01, the value is rounded to the next higer digit.
|
|
115
|
+
#
|
|
116
|
+
# The method mutates the Order-Object.
|
|
117
|
+
#
|
|
118
|
+
# | min-tick | round |
|
|
119
|
+
# |--------------|------------|
|
|
120
|
+
# | 10 | 110 |
|
|
121
|
+
# | 1 | 111 |
|
|
122
|
+
# | 0.1 | 111.1 |
|
|
123
|
+
# | 0.01 | 111.11 |
|
|
124
|
+
# | 0.001 | 111.111 |
|
|
125
|
+
# | 0.0001 | 111.111 |
|
|
126
|
+
# |--------------|------------|
|
|
127
|
+
#
|
|
128
|
+
def auto_adjust
|
|
129
|
+
# lambda to perform the calculation
|
|
130
|
+
adjust_price = ->(a,b) do
|
|
131
|
+
count = -Math.log10(b).round.to_i
|
|
132
|
+
count = count -1 if count > 2
|
|
133
|
+
a.round count
|
|
134
|
+
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
error "No Contract provided to Auto adjust" unless contract.is_a? IB::Contract
|
|
139
|
+
|
|
140
|
+
unless contract.is_a? IB::Bag
|
|
141
|
+
|
|
142
|
+
min_tick = contract.then{ |y| y.contract_detail.is_a?( IB::ContractDetail ) ? y.contract_detail.min_tick : y.verify.first.contract_detail.min_tick }
|
|
143
|
+
# there are two attributes to consider: limit_price and aux_price
|
|
144
|
+
# limit_price + aux_price may be nil or an empty string. Then ".to_f.zero?" becomes true
|
|
145
|
+
self.limit_price = adjust_price.call(limit_price.to_d, min_tick) unless limit_price.to_f.zero?
|
|
146
|
+
self.aux_price = adjust_price.call(aux_price.to_d, min_tick) unless aux_price.to_f.zero?
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
end # module OrderFlow
|
|
151
|
+
|
|
152
|
+
class Order
|
|
153
|
+
include OrderFlow
|
|
154
|
+
end # class
|
|
155
|
+
# Connection.current.activate_plugin 'process-orders'
|
|
156
|
+
end # module IB
|
|
157
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# These modules are used to facilitate referencing of most common Ordertypes
|
|
2
|
+
|
|
3
|
+
module IB
|
|
4
|
+
module OrderPrototype
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def order **fields
|
|
10
|
+
|
|
11
|
+
# special treatment of size: positive numbers --> buy order, negative: sell
|
|
12
|
+
if fields[:size].present? && fields[:action].blank?
|
|
13
|
+
error "Size = 0 is not possible" if fields[:size].zero?
|
|
14
|
+
fields[:action] = fields[:size] >0 ? :buy : :sell
|
|
15
|
+
fields[:size] = fields[:size].abs
|
|
16
|
+
end
|
|
17
|
+
# change aliases to the original. We are modifying the fields-hash.
|
|
18
|
+
fields.keys.each{|x| fields[aliases.key(x)] = fields.delete(x) if aliases.has_value?(x)}
|
|
19
|
+
# inlcude defaults (arguments override defaults)
|
|
20
|
+
the_arguments = defaults.merge fields
|
|
21
|
+
# check if requirements are fullfilled
|
|
22
|
+
necessary = requirements.keys.detect{|y| the_arguments[y].nil?}
|
|
23
|
+
if necessary.present?
|
|
24
|
+
msg =self.name + ".order -> A necessary field is missing: #{necessary}: --> #{requirements[necessary]}"
|
|
25
|
+
error msg, :args, nil
|
|
26
|
+
end
|
|
27
|
+
if alternative_parameters.present?
|
|
28
|
+
unless ( alternative_parameters.keys & the_arguments.keys ).size == 1
|
|
29
|
+
msg =self.name + ".order -> One of the alternative fields needs to be specified: \n\t:" +
|
|
30
|
+
"#{alternative_parameters.map{|x| x.join ' => '}.join(" or \n\t:")}"
|
|
31
|
+
error msg, :args, nil
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# initialise order with given attributes
|
|
36
|
+
IB::Order.new the_arguments
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def alternative_parameters
|
|
40
|
+
{}
|
|
41
|
+
end
|
|
42
|
+
def requirements
|
|
43
|
+
{ action: IB::VALUES[:side], total_quantity: 'also aliased as :size' }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def defaults
|
|
47
|
+
{ tif: :good_till_cancelled }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def optional
|
|
51
|
+
{ account: 'Account(number) to trade on' }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def aliases
|
|
55
|
+
{ total_quantity: :size }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def parameters
|
|
59
|
+
the_output = ->(var){ var.map{|x| x.join(" --> ") }.join("\n\t: ")}
|
|
60
|
+
|
|
61
|
+
"Required : " + the_output[requirements] + "\n --------------- \n" +
|
|
62
|
+
"Optional : " + the_output[optional] + "\n --------------- \n"
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
|
|
2
|
+
module IB
|
|
3
|
+
# module OrderPrototype
|
|
4
|
+
module Adaptive
|
|
5
|
+
extend OrderPrototype
|
|
6
|
+
class << self
|
|
7
|
+
|
|
8
|
+
def defaults
|
|
9
|
+
Limit.defaults.merge algo_strategy: "Adaptive",
|
|
10
|
+
algo_params: { "adaptivePriority" => "Normal" }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def aliases
|
|
14
|
+
Limit.aliases
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def requirements
|
|
18
|
+
Limit.requirements
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def summary
|
|
23
|
+
<<-HERE
|
|
24
|
+
The Adaptive Algo combines IB’s Smart routing capabilities with user-defined
|
|
25
|
+
priority settings in an effort to achieve further cost efficiency at the
|
|
26
|
+
point of execution. Using the Adaptive algo leads to better execution prices
|
|
27
|
+
on average than for regular limit or market orders.
|
|
28
|
+
|
|
29
|
+
Algo Strategy Value: Adaptive
|
|
30
|
+
|
|
31
|
+
adaptivePriority: String. The ‘Priority’ selector determines the time taken
|
|
32
|
+
to scan for better execution prices. The ‘Urgent’ setting scans only briefly,
|
|
33
|
+
while the ‘Patient’ scan works more slowly and has a higher chance of
|
|
34
|
+
achieving a better overall fill for your order. Valid Value/Format:
|
|
35
|
+
Urgent > Normal > Patient
|
|
36
|
+
HERE
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
|
|
3
|
+
#Combo-Orders are used for NonGuaranteed Orders only.
|
|
4
|
+
#»Normal« Option-Spreads are transmited by ordinary Limit-Orders
|
|
5
|
+
module Combo
|
|
6
|
+
### Basic Order Prototype: Combo with two limits
|
|
7
|
+
extend OrderPrototype
|
|
8
|
+
class << self
|
|
9
|
+
def defaults
|
|
10
|
+
## todo implement serialisation of key/tag Hash to camelCased-keyValue-List
|
|
11
|
+
# super.merge order_type: :limit , combo_params: { non_guaranteed: true}
|
|
12
|
+
# for the time being, we use the array representation
|
|
13
|
+
super.merge order_type: :limit , combo_params: [ ['NonGuaranteed', true] ]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def requirements
|
|
18
|
+
Limit.requirements
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def aliases
|
|
22
|
+
Limit.aliases
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def summary
|
|
27
|
+
<<-HERE
|
|
28
|
+
Create combination orders. It is constructed through options, stock and futures legs
|
|
29
|
+
(stock legs can be included if the order is routed through SmartRouting).
|
|
30
|
+
|
|
31
|
+
Although a combination/spread order is constructed of separate legs, it is executed
|
|
32
|
+
as a single transaction if it is routed directly to an exchange. For combination orders
|
|
33
|
+
that are SmartRouted, each leg may be executed separately to ensure best execution.
|
|
34
|
+
|
|
35
|
+
The »NonGuaranteed«-Flag is set to "false". A Pair of two securites should always be
|
|
36
|
+
routed »Guaranteed«, otherwise separate orders are prefered.
|
|
37
|
+
|
|
38
|
+
If a Bag-Order with »NonGuarateed :true« should be submitted, the Order-Type would be
|
|
39
|
+
REL+MKT, LMT+MKT, or REL+LMT
|
|
40
|
+
--------
|
|
41
|
+
Products: Options, Stocks, Futures
|
|
42
|
+
HERE
|
|
43
|
+
end # def
|
|
44
|
+
end # class
|
|
45
|
+
end # module combo
|
|
46
|
+
end # module ib
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
|
|
3
|
+
#Combo-Orders are used for NonGuaranteed Orders only.
|
|
4
|
+
#»Normal« Option-Spreads are transmited by ordinary Limit-Orders
|
|
5
|
+
module Combo
|
|
6
|
+
### Basic Order Prototype: Combo with two limits
|
|
7
|
+
extend OrderPrototype
|
|
8
|
+
class << self
|
|
9
|
+
def defaults
|
|
10
|
+
## todo implement serialisation of key/tag Hash to camelCased-keyValue-List
|
|
11
|
+
# super.merge order_type: :limit , combo_params: { non_guaranteed: true}
|
|
12
|
+
# for the time being, we use the array representation
|
|
13
|
+
super.merge order_type: :limit , combo_params: [ ['NonGuaranteed', true] ]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def requirements
|
|
18
|
+
Limit.requirements
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def aliases
|
|
22
|
+
Limit.aliases
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def summary
|
|
27
|
+
<<-HERE
|
|
28
|
+
Create combination orders. It is constructed through options, stock and futures legs
|
|
29
|
+
(stock legs can be included if the order is routed through SmartRouting).
|
|
30
|
+
|
|
31
|
+
Although a combination/spread order is constructed of separate legs, it is executed
|
|
32
|
+
as a single transaction if it is routed directly to an exchange. For combination orders
|
|
33
|
+
that are SmartRouted, each leg may be executed separately to ensure best execution.
|
|
34
|
+
|
|
35
|
+
The »NonGuaranteed«-Flag is set to "false". A Pair of two securites should always be
|
|
36
|
+
routed »Guaranteed«, otherwise separate orders are prefered.
|
|
37
|
+
|
|
38
|
+
If a Bag-Order with »NonGuarateed :true« should be submitted, the Order-Type would be
|
|
39
|
+
REL+MKT, LMT+MKT, or REL+LMT
|
|
40
|
+
--------
|
|
41
|
+
Products: Options, Stocks, Futures
|
|
42
|
+
HERE
|
|
43
|
+
end # def
|
|
44
|
+
end # class
|
|
45
|
+
end # module combo
|
|
46
|
+
end # module ib
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
# module UseOrder
|
|
3
|
+
module ForexLimit
|
|
4
|
+
extend OrderPrototype
|
|
5
|
+
class << self
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def defaults
|
|
9
|
+
super.merge order_type: :limit , tif: :day
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def requirements
|
|
14
|
+
super.merge cash_qty: '(true/false) to indicate to let IB calculate the cash-quantity of the alternate currency'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def summary
|
|
19
|
+
<<-HERE
|
|
20
|
+
Forex orders can be placed in denomination of second currency in pair using cashQty field.
|
|
21
|
+
Don't specify a limit-price to force immidiate execution.
|
|
22
|
+
HERE
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
=begin
|
|
26
|
+
2.5.0 :001 > f = Symbols::Forex[:eurusd]
|
|
27
|
+
=> #<IB::Contract:0x0000000003299458 @attributes={"symbol"=>"EUR", "exchange"=>"IDEALPRO", "currency"=>"USD", "sec_type"=>"CASH", "created_at"=>2018-01-20 05:21:01 +0100, "updated_at"=>2018-01-20 05:21:01 +0100, "con_id"=>0, "right"=>"", "include_expired"=>false}, @description="EURUSD">
|
|
28
|
+
|
|
29
|
+
2.5.0 :002 > uf = ForexLimit.order action: :buy, size: 15000, cash_qty: true
|
|
30
|
+
{:action=>:buy, :cash_qty=>true, :total_quantity=>15000}
|
|
31
|
+
=> #<IB::Order:0x0000000002f45a40 @attributes={"tif"=>"DAY", "order_type"=>"LMT", "side"=>"B", "cash_qty"=>true, "total_quantity"=>15000, "created_at"=>2018-01-20 05:21:06 +0100, "updated_at"=>2018-01-20 05:21:06 +0100, "active_start_time"=>"", "active_stop_time"=>"", "algo_strategy"=>"", "algo_id"=>"", "auction_strategy"=>0, "conditions"=>[], "continuous_update"=>0, "delta_neutral_designated_location"=>"", "delta_neutral_con_id"=>0, "delta_neutral_settling_firm"=>"", "delta_neutral_clearing_account"=>"", "delta_neutral_clearing_intent"=>"", "designated_location"=>"", "display_size"=>0, "discretionary_amount"=>0, "etrade_only"=>true, "exempt_code"=>-1, "ext_operator"=>"", "firm_quote_only"=>true, "not_held"=>false, "oca_type"=>0, "open_close"=>1, "opt_out_smart_routing"=>false, "origin"=>0, "outside_rth"=>false, "parent_id"=>0, "random_size"=>false, "random_price"=>false, "scale_auto_reset"=>false, "scale_random_percent"=>false, "scale_table"=>"", "short_sale_slot"=>0, "solicided"=>false, "transmit"=>true, "trigger_method"=>0, "what_if"=>false, "leg_prices"=>[], "algo_params"=>{}, "combo_params"=>[], "soft_dollar_tier_params"=>{"name"=>"", "val"=>"", "display_name"=>""}}, @order_states=[#<IB::OrderState:0x0000000002f44258 @attributes={"status"=>"New", "filled"=>0, "remaining"=>0, "price"=>0, "average_price"=>0, "created_at"=>2018-01-20 05:21:06 +0100, "updated_at"=>2018-01-20 05:21:06 +0100}>]>
|
|
32
|
+
2.5.0 :004 > C.place_order uf, f
|
|
33
|
+
=> 4
|
|
34
|
+
2.5.0 :005 > 05:21:23.606 Got message 4 (IB::Messages::Incoming::Alert)
|
|
35
|
+
I, [2018-01-20T05:21:23.606819 #31020] INFO -- : TWS Warning 10164: Traders are responsible for understanding cash quantity details, which are provided on a best efforts basis only.
|
|
36
|
+
Restriction is specified in Precautionary Settings of Global Configuration/Presets.
|
|
37
|
+
|
|
38
|
+
=end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
|
|
2
|
+
module IB
|
|
3
|
+
module Limit
|
|
4
|
+
extend OrderPrototype
|
|
5
|
+
class << self
|
|
6
|
+
|
|
7
|
+
def defaults
|
|
8
|
+
super.merge order_type: :limit
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def aliases
|
|
12
|
+
super.merge limit_price: :price
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def requirements
|
|
16
|
+
super.merge limit_price: "also aliased as :price"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def summary
|
|
21
|
+
<<-HERE
|
|
22
|
+
A Limit order is an order to buy or sell at a specified price or better.
|
|
23
|
+
The Limit order ensures that if the order fills, it will not fill at a price less favorable than
|
|
24
|
+
your limit price, but it does not guarantee a fill.
|
|
25
|
+
It appears in the orderbook.
|
|
26
|
+
HERE
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
module Discretionary
|
|
31
|
+
extend OrderPrototype
|
|
32
|
+
class << self
|
|
33
|
+
|
|
34
|
+
def defaults
|
|
35
|
+
Limit.defaults
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def aliases
|
|
39
|
+
Limit.aliases.merge discretionary_amount: :dc
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def requirements
|
|
43
|
+
Limit.requirements
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def optional
|
|
47
|
+
super.merge discretionary_amount: :decimal
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def summary
|
|
51
|
+
<<-HERE
|
|
52
|
+
A Discretionary order is a Limitorder submitted with a hidden,
|
|
53
|
+
specified 'discretionary' amount off the limit price which may be used
|
|
54
|
+
to increase the price range over which the limit order is eligible to execute.
|
|
55
|
+
The market sees only the limit price.
|
|
56
|
+
The discretionary amount adds to the given limit price. The main effort is
|
|
57
|
+
to hide your real intentions from the public. Discretionary orders can be placed
|
|
58
|
+
for stocks and option on us exchanges, using 'SMART' routing.
|
|
59
|
+
HERE
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def example
|
|
63
|
+
<<-HERE
|
|
64
|
+
You want to by a stock for 65 $ or less. Its trading is volatile, the spread is large.
|
|
65
|
+
There is a technical resistence at 64.5 $ and you think, that there will be a price
|
|
66
|
+
floor somewhere between 64.5 and 65 $. You place a limit order
|
|
67
|
+
at 64.5 $, which appears in the order book. Secretly, you instruct your broker to
|
|
68
|
+
fill the order, if the price is lower then 65 $. Chances for a filling are inceased.
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
dc_order = IB::Discretionary.order size: 1000, price: 65, dc: 0.5
|
|
72
|
+
account.place order: dc_order, contract: IB::Stock.new( symbol: 'BN' )
|
|
73
|
+
```
|
|
74
|
+
HERE
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
# module OrderPrototype
|
|
79
|
+
module Sweep2Fill
|
|
80
|
+
extend OrderPrototype
|
|
81
|
+
class << self
|
|
82
|
+
|
|
83
|
+
def defaults
|
|
84
|
+
super.merge order_type: ':limit' , tif: :day, sweep_to_fill: true
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def aliases
|
|
88
|
+
Limit.aliases
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def requirements
|
|
92
|
+
Limit.requirements
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def summary
|
|
97
|
+
<<-HERE
|
|
98
|
+
Sweep-to-fill orders are useful when a trader values speed of execution over price. A sweep-to-fill
|
|
99
|
+
order identifies the best price and the exact quantity offered/available at that price, and
|
|
100
|
+
transmits the corresponding portion of your order for immediate execution. Simultaneously it
|
|
101
|
+
identifies the next best price and quantity offered/available, and submits the matching quantity
|
|
102
|
+
of your order for immediate execution.
|
|
103
|
+
|
|
104
|
+
------------------------
|
|
105
|
+
Products: CFD, STK, WAR (SMART only)
|
|
106
|
+
|
|
107
|
+
HERE
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
module LimitIfTouched
|
|
112
|
+
extend OrderPrototype
|
|
113
|
+
class << self
|
|
114
|
+
|
|
115
|
+
def defaults
|
|
116
|
+
Limit.defaults.merge order_type: :limit_if_touched
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def aliases
|
|
120
|
+
Limit.aliases.merge aux_price: :trigger_price
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def requirements
|
|
124
|
+
Limit.requirements.merge aux_price: 'also aliased as :trigger_price '
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def summary
|
|
129
|
+
<<-HERE
|
|
130
|
+
A Limit if Touched is an order to buy (or sell) a contract at a specified price or better,
|
|
131
|
+
below (or above) the market. This order is held in the system until the trigger price is touched.
|
|
132
|
+
An LIT order is similar to a stop limit order, except that an LIT sell order is placed above
|
|
133
|
+
the current market price, and a stop limit sell order is placed below.
|
|
134
|
+
HERE
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
module LimitOnClose
|
|
141
|
+
extend OrderPrototype
|
|
142
|
+
class << self
|
|
143
|
+
|
|
144
|
+
def defaults
|
|
145
|
+
Limit.defaults.merge order_type: :limit_on_close
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def aliases
|
|
149
|
+
Limit.aliases
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def requirements
|
|
153
|
+
Limit.requirements
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def summary
|
|
158
|
+
<<-HERE
|
|
159
|
+
A Limit-on-close (LOC) order will be submitted at the close and will execute if the
|
|
160
|
+
closing price is at or better than the submitted limit price.
|
|
161
|
+
HERE
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
module LimitOnOpen
|
|
167
|
+
extend OrderPrototype
|
|
168
|
+
class << self
|
|
169
|
+
|
|
170
|
+
def defaults
|
|
171
|
+
super.merge order_type: :limit_on_open , tif: :opening_price
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def aliases
|
|
175
|
+
Limit.aliases
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def requirements
|
|
179
|
+
Limit.requirements
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def summary
|
|
184
|
+
<<-HERE
|
|
185
|
+
A Limit-on-Open (LOO) order combines a limit order with the OPG time in force to create an
|
|
186
|
+
order that is submitted at the market's open, and that will only execute at the specified
|
|
187
|
+
limit price or better. Orders are filled in accordance with specific exchange rules.
|
|
188
|
+
HERE
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
# end
|
|
193
|
+
end
|