ib-api 10.33.4 → 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.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/Gemfile +2 -3
- data/Gemfile.lock +52 -67
- data/README.md +8 -60
- data/VERSION +1 -1
- data/api.gemspec +3 -10
- data/bin/console +38 -39
- data/bin/console.yml +2 -2
- data/changelog.md +0 -25
- data/example/README.md +76 -0
- data/example/account_info +54 -0
- data/example/account_positions +30 -0
- data/example/account_summary +88 -0
- data/example/cancel_orders +74 -0
- data/example/fa_accounts +25 -0
- data/example/fundamental_data +40 -0
- data/example/historic_data_cli +186 -0
- data/example/list_orders +45 -0
- data/example/portfolio_csv +81 -0
- data/example/scanner_data +62 -0
- data/example/template +19 -0
- data/example/tick_data +28 -0
- data/lib/extensions/class-extensions.rb +87 -0
- data/lib/ib/base.rb +1 -7
- data/lib/ib/base_properties.rb +12 -30
- data/lib/ib/connection.rb +269 -418
- data/lib/ib/constants.rb +22 -31
- data/lib/ib/errors.rb +1 -9
- data/lib/ib/logger.rb +26 -0
- data/lib/ib/messages/abstract_message.rb +43 -10
- data/lib/ib/messages/incoming/abstract_message.rb +98 -98
- data/lib/ib/messages/incoming/account_value.rb +78 -0
- data/lib/ib/messages/incoming/alert.rb +4 -4
- data/lib/ib/messages/incoming/contract_data.rb +29 -32
- data/lib/ib/messages/incoming/execution_data.rb +3 -3
- data/lib/ib/messages/incoming/historical_data.rb +33 -14
- data/lib/ib/messages/incoming/{market_depth.rb → market_depths.rb} +10 -0
- data/lib/ib/messages/incoming/next_valid_id.rb +0 -1
- data/lib/ib/messages/incoming/open_order.rb +201 -214
- data/lib/ib/messages/incoming/order_status.rb +1 -1
- data/lib/ib/messages/incoming/portfolio_value.rb +58 -27
- data/lib/ib/messages/incoming/scanner_data.rb +1 -1
- data/lib/ib/messages/incoming/ticks.rb +268 -0
- data/lib/ib/messages/incoming.rb +95 -136
- data/lib/ib/messages/outgoing/abstract_message.rb +22 -18
- data/lib/ib/messages/outgoing/{request_account_summary.rb → account_requests.rb} +40 -7
- data/lib/ib/messages/outgoing/{bar_request_message.rb → bar_requests.rb} +16 -13
- data/lib/ib/messages/outgoing/place_order.rb +198 -138
- data/lib/ib/messages/outgoing/{request_market_data.rb → request_marketdata.rb} +29 -32
- data/lib/ib/messages/outgoing/request_tick_data.rb +21 -0
- data/lib/ib/messages/outgoing.rb +160 -133
- data/lib/ib/messages.rb +7 -47
- data/lib/ib/model.rb +4 -0
- data/lib/ib/models.rb +14 -0
- data/lib/{server_versions.rb → ib/server_versions.rb} +9 -40
- data/lib/ib/socket.rb +147 -45
- data/lib/ib/support.rb +158 -240
- data/lib/ib/version.rb +1 -1
- data/lib/ib-api.rb +5 -42
- data/lib/models/ib/account.rb +85 -0
- data/{models → lib/models}/ib/account_value.rb +5 -5
- data/{models → lib/models}/ib/bag.rb +7 -7
- data/{models → lib/models}/ib/bar.rb +2 -2
- data/{models → lib/models}/ib/combo_leg.rb +4 -26
- data/lib/models/ib/condition.rb +245 -0
- data/{models → lib/models}/ib/contract.rb +170 -166
- data/{models → lib/models}/ib/contract_detail.rb +15 -25
- data/{models → lib/models}/ib/execution.rb +1 -1
- data/{models → lib/models}/ib/forex.rb +2 -1
- data/lib/models/ib/future.rb +15 -0
- data/{models → lib/models}/ib/index.rb +3 -2
- data/lib/models/ib/option.rb +78 -0
- data/lib/models/ib/option_detail.rb +55 -0
- data/{models → lib/models}/ib/order.rb +165 -366
- data/{models → lib/models}/ib/order_state.rb +22 -25
- data/lib/models/ib/portfolio_value.rb +64 -0
- data/lib/models/ib/stock.rb +16 -0
- data/{models → lib/models}/ib/underlying.rb +5 -3
- data/lib/models/ib/vertical.rb +96 -0
- data/lib/requires.rb +12 -0
- metadata +64 -188
- data/CLAUDE.md +0 -131
- data/LLM_GUIDE.md +0 -388
- data/bin/simple +0 -91
- data/conditions/ib/execution_condition.rb +0 -31
- data/conditions/ib/margin_condition.rb +0 -28
- data/conditions/ib/order_condition.rb +0 -29
- data/conditions/ib/percent_change_condition.rb +0 -34
- data/conditions/ib/price_condition.rb +0 -44
- data/conditions/ib/time_condition.rb +0 -42
- data/conditions/ib/volume_condition.rb +0 -36
- data/lib/class_extensions.rb +0 -167
- data/lib/ib/contract.rb +0 -30
- data/lib/ib/messages/incoming/abstract_tick.rb +0 -25
- data/lib/ib/messages/incoming/account_message.rb +0 -26
- data/lib/ib/messages/incoming/contract_message.rb +0 -13
- data/lib/ib/messages/incoming/histogram_data.rb +0 -30
- data/lib/ib/messages/incoming/historical_data_update.rb +0 -50
- data/lib/ib/messages/incoming/managed_accounts.rb +0 -21
- data/lib/ib/messages/incoming/market_depth_l2.rb +0 -15
- data/lib/ib/messages/incoming/position_data.rb +0 -21
- data/lib/ib/messages/incoming/positions_multi.rb +0 -15
- data/lib/ib/messages/incoming/receive_fa.rb +0 -30
- data/lib/ib/messages/incoming/tick_by_tick.rb +0 -77
- data/lib/ib/messages/incoming/tick_efp.rb +0 -18
- data/lib/ib/messages/incoming/tick_generic.rb +0 -12
- data/lib/ib/messages/incoming/tick_option.rb +0 -60
- data/lib/ib/messages/incoming/tick_price.rb +0 -60
- data/lib/ib/messages/incoming/tick_size.rb +0 -55
- data/lib/ib/messages/incoming/tick_string.rb +0 -13
- data/lib/ib/messages/outgoing/new-place-order.rb +0 -193
- data/lib/ib/messages/outgoing/old-place-order.rb +0 -147
- data/lib/ib/messages/outgoing/request_historical_data.rb +0 -182
- data/lib/ib/messages/outgoing/request_market_depth.rb +0 -57
- data/lib/ib/messages/outgoing/request_real_time_bars.rb +0 -48
- data/lib/ib/messages/outgoing/request_scanner_subscription.rb +0 -73
- data/lib/ib/messages/outgoing/request_tick_by_tick_data.rb +0 -21
- data/lib/ib/order_condition.rb +0 -26
- data/lib/ib/plugins.rb +0 -27
- data/lib/ib/prepare_data.rb +0 -61
- data/lib/ib/raw_message_parser.rb +0 -99
- data/lib/support/array_function.rb +0 -28
- data/lib/support/logging.rb +0 -45
- data/models/ib/account.rb +0 -72
- data/models/ib/future.rb +0 -64
- data/models/ib/option.rb +0 -149
- data/models/ib/option_detail.rb +0 -84
- data/models/ib/portfolio_value.rb +0 -86
- data/models/ib/spread.rb +0 -176
- data/models/ib/stock.rb +0 -25
- data/plugins/ib/advanced-account.rb +0 -442
- data/plugins/ib/alerts/base-alert.rb +0 -125
- data/plugins/ib/alerts/gateway-alerts.rb +0 -15
- data/plugins/ib/alerts/order-alerts.rb +0 -73
- data/plugins/ib/auto-adjust.rb +0 -0
- data/plugins/ib/connection-tools.rb +0 -122
- data/plugins/ib/eod.rb +0 -326
- data/plugins/ib/greeks.rb +0 -102
- data/plugins/ib/managed-accounts.rb +0 -274
- data/plugins/ib/market-price.rb +0 -150
- data/plugins/ib/option-chain.rb +0 -167
- data/plugins/ib/order-flow.rb +0 -157
- data/plugins/ib/order-prototypes/abstract.rb +0 -67
- data/plugins/ib/order-prototypes/adaptive.rb +0 -40
- data/plugins/ib/order-prototypes/all-in-one.rb +0 -46
- data/plugins/ib/order-prototypes/combo.rb +0 -46
- data/plugins/ib/order-prototypes/forex.rb +0 -40
- data/plugins/ib/order-prototypes/limit.rb +0 -193
- data/plugins/ib/order-prototypes/market.rb +0 -116
- data/plugins/ib/order-prototypes/pegged.rb +0 -169
- data/plugins/ib/order-prototypes/premarket.rb +0 -31
- data/plugins/ib/order-prototypes/stop.rb +0 -202
- data/plugins/ib/order-prototypes/volatility.rb +0 -39
- data/plugins/ib/order-prototypes.rb +0 -118
- data/plugins/ib/probability-of-expiring.rb +0 -109
- data/plugins/ib/process-orders.rb +0 -155
- data/plugins/ib/roll.rb +0 -86
- data/plugins/ib/spread-prototypes/butterfly.rb +0 -77
- data/plugins/ib/spread-prototypes/calendar.rb +0 -97
- data/plugins/ib/spread-prototypes/stock-spread.rb +0 -56
- data/plugins/ib/spread-prototypes/straddle.rb +0 -70
- data/plugins/ib/spread-prototypes/strangle.rb +0 -93
- data/plugins/ib/spread-prototypes/vertical.rb +0 -83
- data/plugins/ib/spread-prototypes.rb +0 -70
- data/plugins/ib/symbols/abstract.rb +0 -136
- data/plugins/ib/symbols/bonds.rb +0 -28
- data/plugins/ib/symbols/cfd.rb +0 -19
- data/plugins/ib/symbols/combo.rb +0 -46
- data/plugins/ib/symbols/commodity.rb +0 -17
- data/plugins/ib/symbols/forex.rb +0 -41
- data/plugins/ib/symbols/futures.rb +0 -127
- data/plugins/ib/symbols/index.rb +0 -43
- data/plugins/ib/symbols/options.rb +0 -99
- data/plugins/ib/symbols/stocks.rb +0 -44
- data/plugins/ib/symbols/version.rb +0 -5
- data/plugins/ib/symbols.rb +0 -118
- data/plugins/ib/verify.rb +0 -226
- data/symbols/w20.yml +0 -210
- data/t.txt +0 -20
- data/update.md +0 -71
data/lib/ib-api.rb
CHANGED
|
@@ -1,44 +1,7 @@
|
|
|
1
|
+
module IB
|
|
1
2
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
require 'active_support/core_ext/module/attribute_accessors.rb'
|
|
6
|
-
require 'bigdecimal/util' # provides .to_d for numeric and string classes
|
|
7
|
-
require 'class_extensions'
|
|
8
|
-
require 'logger'
|
|
9
|
-
require 'terminal-table'
|
|
10
|
-
require 'workflow'
|
|
3
|
+
end
|
|
4
|
+
IbRuby = IB
|
|
5
|
+
Ib = IB
|
|
11
6
|
|
|
12
|
-
|
|
13
|
-
#require 'ib/connection'
|
|
14
|
-
|
|
15
|
-
require "server_versions"
|
|
16
|
-
|
|
17
|
-
require 'ib/constants'
|
|
18
|
-
require 'ib/errors'
|
|
19
|
-
#loader = Zeitwerk::Loader.new
|
|
20
|
-
loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
|
|
21
|
-
loader.ignore("#{__dir__}/server_versions.rb")
|
|
22
|
-
loader.ignore("#{__dir__}/ib-api.rb")
|
|
23
|
-
loader.ignore("#{__dir__}/ib/contract.rb")
|
|
24
|
-
loader.ignore("#{__dir__}/ib/constants.rb")
|
|
25
|
-
loader.ignore("#{__dir__}/ib/errors.rb")
|
|
26
|
-
loader.ignore("#{__dir__}/ib/order_condition.rb")
|
|
27
|
-
loader.ignore("#{__dir__}/ib/messages/outgoing/old-place-order.rb")
|
|
28
|
-
loader.ignore("#{__dir__}/ib/messages/outgoing/new-place-order.rb")
|
|
29
|
-
#loader.ignore("#{__dir__}/models")
|
|
30
|
-
loader.inflector.inflect(
|
|
31
|
-
"ib" => "IB",
|
|
32
|
-
"receive_fa" => "ReceiveFA",
|
|
33
|
-
"tick_efp" => "TickEFP",
|
|
34
|
-
)
|
|
35
|
-
#loader.push_dir("#{__dir__}")
|
|
36
|
-
loader.push_dir("#{__dir__}/../models/")
|
|
37
|
-
loader.push_dir("#{__dir__}/../conditions/")
|
|
38
|
-
loader.setup
|
|
39
|
-
loader.eager_load
|
|
40
|
-
#require 'requires'
|
|
41
|
-
require 'ib/contract.rb'
|
|
42
|
-
require 'ib/order_condition.rb'
|
|
43
|
-
#IbRuby = Ib
|
|
44
|
-
#IB = Ib
|
|
7
|
+
require 'requires'
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
class Account < IB::Model
|
|
3
|
+
include BaseProperties
|
|
4
|
+
# include Redis::Objects
|
|
5
|
+
# attr_accessible :alias, :account, :connected
|
|
6
|
+
|
|
7
|
+
prop :account, # String
|
|
8
|
+
:alias, #
|
|
9
|
+
:type,
|
|
10
|
+
:last_updated,
|
|
11
|
+
:connected => :bool
|
|
12
|
+
|
|
13
|
+
# redis_id_field :account
|
|
14
|
+
# value :my_alias
|
|
15
|
+
# value :the_account
|
|
16
|
+
# value :active
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
validates_format_of :account, :with => /\A[D]?[UF]{1}\d{5,8}\z/ , :message => 'should be (X)X00000'
|
|
20
|
+
|
|
21
|
+
# in tableless mode the scope is ignored
|
|
22
|
+
|
|
23
|
+
has_many :account_values
|
|
24
|
+
has_many :portfolio_values
|
|
25
|
+
has_many :contracts
|
|
26
|
+
has_many :orders
|
|
27
|
+
has_many :focuses
|
|
28
|
+
|
|
29
|
+
def default_attributes
|
|
30
|
+
super.merge account: 'X000000'
|
|
31
|
+
super.merge alias: ''
|
|
32
|
+
super.merge type: 'Account'
|
|
33
|
+
super.merge connected: false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def logger #nodoc#
|
|
37
|
+
Connection.logger
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Setze Account connect/disconnect und undate!
|
|
41
|
+
def connect!
|
|
42
|
+
update_attribute :connected , true
|
|
43
|
+
end
|
|
44
|
+
def disconnect!
|
|
45
|
+
update_attribute :connected , false
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def print_type #nodoc#
|
|
49
|
+
(test_environment? ? "demo_" : "") + ( user? ? "user" : "advisor" )
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def advisor?
|
|
53
|
+
!!(type =~ /Advisor/ || account =~ /\A[D]?[F]{1}/)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def user?
|
|
57
|
+
!!(type =~ /User/ || account =~ /\A[D]?[U]{1}/)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_environment?
|
|
61
|
+
!!(account =~ /^[D]{1}/)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def == other
|
|
65
|
+
super(other) ||
|
|
66
|
+
other.is_a?(self.class) && account == other.account
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def to_human
|
|
70
|
+
a = if self.alias.present? && self.alias != account
|
|
71
|
+
" alias: "+ self.alias
|
|
72
|
+
else
|
|
73
|
+
""
|
|
74
|
+
end
|
|
75
|
+
"<#{print_type} #{account}#{a}>"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def name #nodoc#
|
|
79
|
+
self.alias.present? ? self.alias : account
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# alias :id :account
|
|
83
|
+
end # class
|
|
84
|
+
|
|
85
|
+
end # module
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
module IB
|
|
2
2
|
# Instantiate with a Hash of attributes, to be auto-set via initialize in Model.
|
|
3
|
-
class AccountValue < IB::
|
|
3
|
+
class AccountValue < IB::Model
|
|
4
4
|
include BaseProperties
|
|
5
5
|
|
|
6
6
|
belongs_to :account
|
|
7
7
|
|
|
8
8
|
prop :key,
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
:value,
|
|
10
|
+
:currency
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
# comparison
|
|
@@ -20,8 +20,8 @@ module IB
|
|
|
20
20
|
end
|
|
21
21
|
def default_attributes
|
|
22
22
|
super.merge key: 'AccountValue',
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
value: 0,
|
|
24
|
+
currency: 'USD'
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def to_human
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'models/ib/contract'
|
|
2
|
+
|
|
1
3
|
module IB
|
|
2
4
|
|
|
3
5
|
# "BAG" is not really a contract, but a combination (combo) of securities.
|
|
@@ -9,9 +11,6 @@ module IB
|
|
|
9
11
|
# The exception is for a STK legs, which must specify the SMART exchange.
|
|
10
12
|
# 2. :symbol => "USD" For combo Contract, this is an arbitrary value (like "USD")
|
|
11
13
|
|
|
12
|
-
prop :combo_params # bags carry "non_guarantieed: true/false" in combo_params
|
|
13
|
-
|
|
14
|
-
|
|
15
14
|
validates_format_of :sec_type, :with => /\Abag\z/, :message => "should be a bag"
|
|
16
15
|
validates_format_of :right, :with => /\Anone\z/, :message => "should be none"
|
|
17
16
|
validates_format_of :expiry, :with => /\A\z/, :message => "should be blank"
|
|
@@ -28,12 +27,14 @@ module IB
|
|
|
28
27
|
"<Bag: #{[symbol, exchange, currency].join(' ')} legs: #{legs_description} >"
|
|
29
28
|
end
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
def con_id= arg
|
|
31
|
+
# dont' update con_id
|
|
32
|
+
end
|
|
34
33
|
|
|
35
34
|
### Leg-related methods
|
|
36
35
|
|
|
36
|
+
# TODO: Rewrite with legs and legs_description being strictly in sync...
|
|
37
|
+
# TODO: Find a way to serialize legs without references...
|
|
37
38
|
# IB-equivalent leg description.
|
|
38
39
|
def legs_description
|
|
39
40
|
self[:legs_description] || combo_legs.map { |the_leg| "#{the_leg.con_id}|#{the_leg.weight}" }.join(',')
|
|
@@ -45,7 +46,6 @@ module IB
|
|
|
45
46
|
legs_description.split(',').sort == other.legs_description.split(',').sort
|
|
46
47
|
end
|
|
47
48
|
|
|
48
|
-
|
|
49
49
|
# Contract comparison
|
|
50
50
|
def == other
|
|
51
51
|
super && same_legs?(other)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module IB
|
|
2
2
|
# This is a single data point delivered by HistoricData or RealTimeBar messages.
|
|
3
3
|
# Instantiate with a Hash of attributes, to be auto-set via initialize in Model.
|
|
4
|
-
class Bar < IB::
|
|
4
|
+
class Bar < IB::Model
|
|
5
5
|
include BaseProperties
|
|
6
6
|
|
|
7
7
|
has_one :contract # The bar represents timeseries info for this Contract
|
|
@@ -22,7 +22,7 @@ module IB
|
|
|
22
22
|
validates_numericality_of :open, :high, :low, :close, :volume
|
|
23
23
|
|
|
24
24
|
def to_human
|
|
25
|
-
|
|
25
|
+
"<Bar: #{time} wap #{wap} OHLC #{open} #{high} #{low} #{close} " +
|
|
26
26
|
(trades ? "trades #{trades}" : "") + " vol #{volume}>"
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -2,7 +2,7 @@ module IB
|
|
|
2
2
|
|
|
3
3
|
# ComboLeg is essentially a join Model between Combo (BAG) Contract and
|
|
4
4
|
# individual Contracts (securities) that this BAG contains.
|
|
5
|
-
class ComboLeg < IB::
|
|
5
|
+
class ComboLeg < IB::Model
|
|
6
6
|
include BaseProperties
|
|
7
7
|
|
|
8
8
|
# BAG Combo Contract that contains this Leg
|
|
@@ -20,10 +20,10 @@ module IB
|
|
|
20
20
|
# specific combination order, refer to the Interactive
|
|
21
21
|
# Analytics section of the User's Guide.
|
|
22
22
|
:exchange, # String: exchange to which the complete combo order will be routed.
|
|
23
|
-
|
|
23
|
+
#
|
|
24
24
|
# For institutional customers only! For stock legs when doing short sale
|
|
25
|
-
:short_sale_slot, # int:
|
|
26
|
-
|
|
25
|
+
:short_sale_slot, # int: 0 - retail(default),
|
|
26
|
+
# 1 = clearing broker, 2 = third party
|
|
27
27
|
:designated_location, # String: Only for shortSaleSlot == 2.
|
|
28
28
|
# Otherwise leave blank or orders will be rejected.
|
|
29
29
|
:exempt_code, # int: (-1)
|
|
@@ -83,28 +83,6 @@ module IB
|
|
|
83
83
|
].flatten
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
# fields are generated by serialize(:extended)
|
|
88
|
-
# i.e.
|
|
89
|
-
# z= Strangle.build from: Symbols::Index.stoxx, p: 3700, c: 4000, expiry: 202106
|
|
90
|
-
# zc= z.combo_legs.serialize :extended
|
|
91
|
-
# => [[321584786, 1, "BUY", "DTB", 0, 0, "", -1], [321584637, 1, "BUY", "DTB", 0, 0, "", -1]]
|
|
92
|
-
# nz = zc.map{|o| ComboLeg.build *o }
|
|
93
|
-
# zc.map{|o| ComboLeg.build o } => # is equivalent
|
|
94
|
-
# => [#<IB::ComboLeg:0x0000000001c36bc0 @attributes={:con_id=>321584786, :ratio=>1, :side=>"B", :exchange=>"DTB", ...
|
|
95
|
-
# nz.first == z.combo_legs.first => true
|
|
96
|
-
#
|
|
97
|
-
def self.build *fields
|
|
98
|
-
self.new Hash[[:con_id,
|
|
99
|
-
:ratio,
|
|
100
|
-
:side, # reverse to_sup?
|
|
101
|
-
:exchange,
|
|
102
|
-
:open_close,
|
|
103
|
-
:short_sale_slot,
|
|
104
|
-
:designated_location,
|
|
105
|
-
:exempt_code].zip fields]
|
|
106
|
-
end
|
|
107
|
-
|
|
108
86
|
def to_human
|
|
109
87
|
"<ComboLeg: #{side} #{ratio} con_id #{con_id} at #{exchange}>"
|
|
110
88
|
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
require 'ib/support'
|
|
2
|
+
module IB
|
|
3
|
+
class OrderCondition < IB::Model
|
|
4
|
+
include BaseProperties
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
prop :operator, # 1 -> " >= " , 0 -> " <= " see /lib/ib/constants # 338f
|
|
8
|
+
:conjunction_connection, # "o" -> or "a"
|
|
9
|
+
:contract
|
|
10
|
+
def self.verify_contract_if_necessary c
|
|
11
|
+
c.con_id.to_i.zero? ||( c.primary_exchange.blank? && c.exchange.blank?) ? c.verify! : c
|
|
12
|
+
end
|
|
13
|
+
def condition_type
|
|
14
|
+
error "condition_type method is abstract"
|
|
15
|
+
end
|
|
16
|
+
def default_attributes
|
|
17
|
+
super.merge( operator: ">=" , conjunction_connection: :and )
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def serialize_contract_by_con_id
|
|
21
|
+
[ contract.con_id , contract.primary_exchange.presence || contract.exchange ]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def serialize
|
|
25
|
+
[ condition_type, self[:conjunction_connection] ]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PriceCondition < OrderCondition
|
|
32
|
+
using IBSupport # refine Array-method for decoding of IB-Messages
|
|
33
|
+
prop :price,
|
|
34
|
+
:trigger_method # see /models/ib/order.rb# 51 ff and /lib/ib/constants # 210 ff
|
|
35
|
+
|
|
36
|
+
def default_attributes
|
|
37
|
+
super.merge( :trigger_method => :default )
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def condition_type
|
|
41
|
+
1
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.make buffer
|
|
45
|
+
m= self.new conjunction_connection: buffer.read_string,
|
|
46
|
+
operator: buffer.read_int,
|
|
47
|
+
price: buffer.read_decimal
|
|
48
|
+
|
|
49
|
+
the_contract = IB::Contract.new con_id: buffer.read_int, exchange: buffer.read_string
|
|
50
|
+
m.contract = the_contract
|
|
51
|
+
m.trigger_method = buffer.read_int
|
|
52
|
+
m
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def serialize
|
|
57
|
+
super << self[:operator] << price << serialize_contract_by_con_id << self[:trigger_method]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# dsl: PriceCondition.fabricate some_contract, ">=", 500
|
|
61
|
+
def self.fabricate contract, operator, price
|
|
62
|
+
error "Condition Operator has to be \">=\" or \"<=\" " unless ["<=", ">="].include? operator
|
|
63
|
+
self.new operator: operator,
|
|
64
|
+
price: price.to_i,
|
|
65
|
+
contract: verify_contract_if_necessary( contract )
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class TimeCondition < OrderCondition
|
|
71
|
+
using IBSupport # refine Array-method for decoding of IB-Messages
|
|
72
|
+
prop :time
|
|
73
|
+
|
|
74
|
+
def condition_type
|
|
75
|
+
3
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def self.make buffer
|
|
79
|
+
self.new conjunction_connection: buffer.read_string,
|
|
80
|
+
operator: buffer.read_int,
|
|
81
|
+
time: buffer.read_parse_date
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def serialize
|
|
85
|
+
t = self[:time]
|
|
86
|
+
if t.is_a?(String) && t =~ /^\d{8}\z/ # expiry-format yyymmmdd
|
|
87
|
+
self.time = DateTime.new t[0..3],t[4..5],t[-2..-1]
|
|
88
|
+
end
|
|
89
|
+
serialized_time = case self[:time] # explicity formatting of time-object
|
|
90
|
+
when String
|
|
91
|
+
self[:time]
|
|
92
|
+
when DateTime
|
|
93
|
+
self[:time].gmtime.strftime("%Y%m%d %H:%M:%S %Z")
|
|
94
|
+
when Date, Time
|
|
95
|
+
self[:time].strftime("%Y%m%d %H:%M:%S")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
super << self[:operator] << serialized_time
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.fabricate operator, time
|
|
102
|
+
self.new operator: operator,
|
|
103
|
+
time: time
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
class ExecutionCondition < OrderCondition
|
|
108
|
+
using IBSupport # refine Array-method for decoding of IB-Messages
|
|
109
|
+
|
|
110
|
+
def condition_type
|
|
111
|
+
5
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.make buffer
|
|
115
|
+
m =self.new conjunction_connection: buffer.read_string,
|
|
116
|
+
operator: buffer.read_int
|
|
117
|
+
|
|
118
|
+
the_contract = IB::Contract.new sec_type: buffer.read_string,
|
|
119
|
+
exchange: buffer.read_string,
|
|
120
|
+
symbol: buffer.read_string
|
|
121
|
+
m.contract = the_contract
|
|
122
|
+
m
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def serialize
|
|
126
|
+
super << contract[:sec_type] <<(contract.primary_exchange.presence || contract.exchange) << contract.symbol
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def self.fabricate contract
|
|
130
|
+
self.new contract: verify_contract_if_necessary( contract )
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
class MarginCondition < OrderCondition
|
|
136
|
+
using IBSupport # refine Array-method for decoding of IB-Messages
|
|
137
|
+
|
|
138
|
+
prop :percent
|
|
139
|
+
|
|
140
|
+
def condition_type
|
|
141
|
+
4
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def self.make buffer
|
|
145
|
+
self.new conjunction_connection: buffer.read_string,
|
|
146
|
+
operator: buffer.read_int,
|
|
147
|
+
percent: buffer.read_int
|
|
148
|
+
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def serialize
|
|
152
|
+
super << self[:operator] << percent
|
|
153
|
+
end
|
|
154
|
+
def self.fabricate operator, percent
|
|
155
|
+
error "Condition Operator has to be \">=\" or \"<=\" " unless ["<=", ">="].include? operator
|
|
156
|
+
self.new operator: operator,
|
|
157
|
+
percent: percent
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class VolumeCondition < OrderCondition
|
|
163
|
+
using IBSupport # refine Array-method for decoding of IB-Messages
|
|
164
|
+
|
|
165
|
+
prop :volume
|
|
166
|
+
|
|
167
|
+
def condition_type
|
|
168
|
+
6
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def self.make buffer
|
|
172
|
+
m = self.new conjunction_connection: buffer.read_string,
|
|
173
|
+
operator: buffer.read_int,
|
|
174
|
+
volumne: buffer.read_int
|
|
175
|
+
|
|
176
|
+
the_contract = IB::Contract.new con_id: buffer.read_int, exchange: buffer.read_string
|
|
177
|
+
m.contract = the_contract
|
|
178
|
+
m
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def serialize
|
|
182
|
+
|
|
183
|
+
super << self[:operator] << volume << serialize_contract_by.con_id
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# dsl: VolumeCondition.fabricate some_contract, ">=", 50000
|
|
187
|
+
def self.fabricate contract, operator, volume
|
|
188
|
+
error "Condition Operator has to be \">=\" or \"<=\" " unless ["<=", ">="].include? operator
|
|
189
|
+
self.new operator: operator,
|
|
190
|
+
volume: volume,
|
|
191
|
+
contract: verify_contract_if_necessary( contract )
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
class PercentChangeCondition < OrderCondition
|
|
196
|
+
using IBSupport # refine Array-method for decoding of IB-Messages
|
|
197
|
+
prop :percent_change
|
|
198
|
+
|
|
199
|
+
def condition_type
|
|
200
|
+
7
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def self.make buffer
|
|
204
|
+
m = self.new conjunction_connection: buffer.read_string,
|
|
205
|
+
operator: buffer.read_int,
|
|
206
|
+
percent_change: buffer.read_decimal
|
|
207
|
+
|
|
208
|
+
the_contract = IB::Contract.new con_id: buffer.read_int, exchange: buffer.read_string
|
|
209
|
+
m.contract = the_contract
|
|
210
|
+
m
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def serialize
|
|
214
|
+
super << self[:operator] << percent_change << serialize_contract_by_con_id
|
|
215
|
+
|
|
216
|
+
end
|
|
217
|
+
# dsl: PercentChangeCondition.fabricate some_contract, ">=", "5%"
|
|
218
|
+
def self.fabricate contract, operator, change
|
|
219
|
+
error "Condition Operator has to be \">=\" or \"<=\" " unless ["<=", ">="].include? operator
|
|
220
|
+
self.new operator: operator,
|
|
221
|
+
percent_change: change.to_i,
|
|
222
|
+
contract: verify_contract_if_necessary( contract )
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
class OrderCondition
|
|
226
|
+
using IBSupport # refine Array-method for decoding of IB-Messages
|
|
227
|
+
# subclasses representing specialized condition types.
|
|
228
|
+
|
|
229
|
+
Subclasses = Hash.new(OrderCondition)
|
|
230
|
+
Subclasses[1] = IB::PriceCondition
|
|
231
|
+
Subclasses[3] = IB::TimeCondition
|
|
232
|
+
Subclasses[5] = IB::ExecutionCondition
|
|
233
|
+
Subclasses[4] = IB::MarginCondition
|
|
234
|
+
Subclasses[6] = IB::VolumeCondition
|
|
235
|
+
Subclasses[7] = IB::PercentChangeCondition
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# This builds an appropriate subclass based on its type
|
|
239
|
+
#
|
|
240
|
+
def self.make_from buffer
|
|
241
|
+
condition_type = buffer.read_int
|
|
242
|
+
OrderCondition::Subclasses[condition_type].make( buffer )
|
|
243
|
+
end
|
|
244
|
+
end # class
|
|
245
|
+
end # module
|