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,43 @@
|
|
|
1
|
+
# Frequently used stock contracts definitions
|
|
2
|
+
module IB
|
|
3
|
+
module Symbols
|
|
4
|
+
module Index
|
|
5
|
+
extend Symbols
|
|
6
|
+
|
|
7
|
+
def self.contracts
|
|
8
|
+
@contracts.presence || super.merge(
|
|
9
|
+
:dax => IB::Index.new( :symbol => "DAX", :currency => "EUR", exchange: 'EUREX',
|
|
10
|
+
:description => "DAX Performance Index."),
|
|
11
|
+
:asx => IB::Index.new( :symbol => 'AP', :currency => 'AUD', exchange: 'ASX',
|
|
12
|
+
:description => "ASX 200 Index (Base for IndexOptions)" ),
|
|
13
|
+
:hsi => IB::Index.new( :symbol => 'HSI', :currency => 'HKD', exchange: 'HKFE',
|
|
14
|
+
:description => "Hang Seng Index" ),
|
|
15
|
+
:minihsi => IB::Index.new( :symbol => 'MHI', :currency => 'HKD', exchange: 'HKFE',
|
|
16
|
+
:description => "Mini Hang Seng Index" ),
|
|
17
|
+
:stoxx => IB::Index.new( :symbol => "ESTX50", :currency => "EUR", exchange: 'EUREX',
|
|
18
|
+
:description => "Dow Jones Euro STOXX50"),
|
|
19
|
+
:spx => IB::Index.new( :symbol => "SPX", :currency => "USD", exchange: 'CBOE',
|
|
20
|
+
:description => "S&P 500 Stock Index"),
|
|
21
|
+
:vhsi => IB::Index.new( symbol: 'VHSI', exchange: 'HKFE',
|
|
22
|
+
:description => "Hang Seng Volatility Index"),
|
|
23
|
+
:vasx => IB::Index.new( symbol: 'XVI', exchange: 'ASX',
|
|
24
|
+
:description => "ASX 200 Volatility Index") ,
|
|
25
|
+
:vstoxx => IB::Index.new( :symbol => "V2TX", :currency => "EUR", exchange: 'EUREX',
|
|
26
|
+
:description => "VSTOXX Volatility Index"),
|
|
27
|
+
:vdax => IB::Index.new( :symbol => "VDAX", exchange: 'EUREX',
|
|
28
|
+
:description => "German VDAX Volatility Index"),
|
|
29
|
+
:vix => IB::Index.new( :symbol => "VIX", exchange: 'CBOE',
|
|
30
|
+
:description => "CBOE Volatility Index"),
|
|
31
|
+
:volume => IB::Index.new( symbol: 'VOL-NYSE', exchange: 'NYSE',
|
|
32
|
+
description: "NYSE Volume Index" ),
|
|
33
|
+
:trin => IB::Index.new( symbol: 'TRIN-NYSE', exchange: 'NYSE',
|
|
34
|
+
description: "NYSE TRIN (or arms) Index"),
|
|
35
|
+
:tick => IB::Index.new( symbol: 'TICK-NYSE', exchange: 'NYSE',
|
|
36
|
+
description: "NYSE TICK Index"),
|
|
37
|
+
:a_d => IB::Index.new( symbol: 'AD-NYSE', exchange: 'NYSE',
|
|
38
|
+
description: "NYSE Advance Decline Index") )
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Option contracts definitions.
|
|
2
|
+
# TODO: add next_expiry and other convenience from Futures module.
|
|
3
|
+
# Notice: OSI-Notation is broken
|
|
4
|
+
module IB
|
|
5
|
+
module Symbols
|
|
6
|
+
module Options
|
|
7
|
+
extend Symbols
|
|
8
|
+
|
|
9
|
+
## usage: IB::Symbols::Options.stoxx.merge( strike: 5000, expiry: 202404 )
|
|
10
|
+
## IB::Symbols::Options.stoxx.merge( strike: 5000 ).next_expiry => fetch the next regulary
|
|
11
|
+
## monthly option (3.rd friday)
|
|
12
|
+
def self.contracts
|
|
13
|
+
@contracts ||= {
|
|
14
|
+
stoxx: IB::Option.new(symbol: :ESTX50,
|
|
15
|
+
expiry: IB::Option.next_expiry ,
|
|
16
|
+
right: :put,
|
|
17
|
+
trading_class: 'OESX',
|
|
18
|
+
currency: 'EUR',
|
|
19
|
+
exchange: 'EUREX',
|
|
20
|
+
description: "Monthly settled ESTX50 Options"),
|
|
21
|
+
spx: IB::Option.new( symbol: :SPX,
|
|
22
|
+
expiry: IB::Option.next_expiry ,
|
|
23
|
+
right: :put,
|
|
24
|
+
trading_class: 'SPX',
|
|
25
|
+
currency: 'USD',
|
|
26
|
+
exchange: 'SMART',
|
|
27
|
+
description: "Monthly settled SPX options"),
|
|
28
|
+
spxw: IB::Option.new( symbol: :SPX,
|
|
29
|
+
expiry: IB::Option.next_expiry ,
|
|
30
|
+
right: :put,
|
|
31
|
+
trading_class: 'SPXW',
|
|
32
|
+
currency: 'USD', exchange: 'SMART',
|
|
33
|
+
description: "Daily settled SPX options"),
|
|
34
|
+
xsp: IB::Option.new( symbol: 'XSP',
|
|
35
|
+
expiry: IB::Option.next_expiry ,
|
|
36
|
+
right: :put,
|
|
37
|
+
trading_class: 'XSP',
|
|
38
|
+
currency: 'USD',
|
|
39
|
+
exchange: 'SMART',
|
|
40
|
+
description: "Daily settled Mini-SPX options"),
|
|
41
|
+
:spy => IB::Option.new( :symbol => :SPY,
|
|
42
|
+
:expiry => IB::Option.next_expiry,
|
|
43
|
+
:right => :put,
|
|
44
|
+
:currency => "USD",
|
|
45
|
+
:exchange => 'SMART',
|
|
46
|
+
:description => "SPY Put next expiration"),
|
|
47
|
+
:rut => IB::Option.new( :symbol => :RUT,
|
|
48
|
+
:expiry => IB::Option.next_expiry,
|
|
49
|
+
:right => :put,
|
|
50
|
+
:currency => "USD",
|
|
51
|
+
:exchange => 'SMART',
|
|
52
|
+
:trading_class => 'RUT',
|
|
53
|
+
description: "Monthly settled RUT options"),
|
|
54
|
+
:rutw => IB::Option.new( :symbol => :RUT,
|
|
55
|
+
:expiry => IB::Option.next_expiry,
|
|
56
|
+
:right => :put,
|
|
57
|
+
:currency => "USD",
|
|
58
|
+
:exchange => 'SMART',
|
|
59
|
+
description: "Weekly settled RUT options"),
|
|
60
|
+
:russell => IB::Option.new( :symbol => :RUT, # :russell == :rut !
|
|
61
|
+
:expiry => IB::Option.next_expiry,
|
|
62
|
+
:right => :put,
|
|
63
|
+
:currency => "USD",
|
|
64
|
+
:exchange => 'SMART',
|
|
65
|
+
description: "Monthly settled RUT options"),
|
|
66
|
+
:mini_russell => IB::Option.new( :symbol => :MRUT,
|
|
67
|
+
:expiry => IB::Option.next_expiry,
|
|
68
|
+
:right => :put,
|
|
69
|
+
:currency => "USD",
|
|
70
|
+
:exchange => 'SMART',
|
|
71
|
+
:description => "Weekly settled Mini-Russell2000 options"),
|
|
72
|
+
:aapl => IB::Option.new( :symbol => "AAPL",
|
|
73
|
+
:expiry => IB::Option.next_expiry,
|
|
74
|
+
:right => "C",
|
|
75
|
+
:strike => 150,
|
|
76
|
+
:exchange => 'SMART',
|
|
77
|
+
:currency => 'USD',
|
|
78
|
+
:description => "Apple Call 130"),
|
|
79
|
+
|
|
80
|
+
:ibm => IB::Option.new( symbol: 'IBM',
|
|
81
|
+
exchange: 'SMART',
|
|
82
|
+
right: :put,
|
|
83
|
+
expiry: IB::Option.next_expiry ,
|
|
84
|
+
description: 'IBM-Option'),
|
|
85
|
+
:ibm_lazy_expiry => IB::Option.new( symbol: 'IBM',
|
|
86
|
+
right: :put,
|
|
87
|
+
strike: 180,
|
|
88
|
+
exchange: 'SMART',
|
|
89
|
+
description: 'IBM-Option Chain with strike 180'),
|
|
90
|
+
:ibm_lazy_strike => IB::Option.new( symbol: 'IBM',
|
|
91
|
+
right: :put,
|
|
92
|
+
exchange: 'SMART',
|
|
93
|
+
expiry: IB::Option.next_expiry,
|
|
94
|
+
description: 'IBM-Option Chain ( monthly expiry)')
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Frequently used stock contracts definitions
|
|
2
|
+
# TODO: auto-request :ContractDetails from IB if unknown symbol is requested?
|
|
3
|
+
module IB
|
|
4
|
+
module Symbols
|
|
5
|
+
module Stocks
|
|
6
|
+
extend Symbols
|
|
7
|
+
|
|
8
|
+
def self.contracts
|
|
9
|
+
@contracts.presence || super.merge(
|
|
10
|
+
:ib_smart => IB::Stock.new( :symbol => 'IBKR',
|
|
11
|
+
:description => 'Interactive Brokers Stock with smart exchange setting'),
|
|
12
|
+
:ib => IB::Stock.new( :symbol=> 'IBKR', exchange: 'ISLAND',
|
|
13
|
+
:description => 'Interactive Brokers Stock'),
|
|
14
|
+
:aapl => IB::Stock.new( :symbol => "AAPL",
|
|
15
|
+
:currency => "USD",
|
|
16
|
+
:description => "Apple Inc."),
|
|
17
|
+
|
|
18
|
+
:msft_conid => IB::Stock.new( con_id: 272093,
|
|
19
|
+
currency: :usd ,
|
|
20
|
+
description: 'Microsoft selected by its con-id'),
|
|
21
|
+
:msft => IB::Stock.new( symbol: 'MSFT',
|
|
22
|
+
description: 'Microsoft selected by its symbol'),
|
|
23
|
+
:msft_island =>IB::Stock.new( symbol: 'MSFT', primary_exchange: 'ISLAND',
|
|
24
|
+
description: 'Microsoft, primary trading @ ISLAND'),
|
|
25
|
+
:vxx => IB::Stock.new( :symbol => "VXX",
|
|
26
|
+
:exchange => "ARCA",
|
|
27
|
+
:description => "iPath S&P500 VIX short term Futures ETN"),
|
|
28
|
+
:wfc => IB::Stock.new( :symbol => "WFC",
|
|
29
|
+
:exchange => "NYSE",
|
|
30
|
+
:currency => "USD",
|
|
31
|
+
:description => "Wells Fargo"),
|
|
32
|
+
:sie => IB::Stock.new( symbol: 'SIE',
|
|
33
|
+
currency: 'EUR',
|
|
34
|
+
description: 'Siemens AG'),
|
|
35
|
+
:wrong => IB::Stock.new( :symbol => "QEEUUE",
|
|
36
|
+
:exchange => "NYSE",
|
|
37
|
+
:currency => "USD",
|
|
38
|
+
:description => "Non-existent stock")
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
|
|
3
|
+
Plugin that provides helper methods for predefined Contracts
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Public API
|
|
7
|
+
==========
|
|
8
|
+
|
|
9
|
+
Extends IB::Contract
|
|
10
|
+
|
|
11
|
+
=end
|
|
12
|
+
|
|
13
|
+
# These modules are used to facilitate referencing of most popular IB Contracts.
|
|
14
|
+
# Like pages in the TWS-GUI, they can be utilised to organise trading and research.
|
|
15
|
+
#
|
|
16
|
+
# Symbol Allocations are organized as modules. They represent the contents of yaml files in
|
|
17
|
+
#
|
|
18
|
+
# /lib/symbols/
|
|
19
|
+
#
|
|
20
|
+
# Any collection is represented as simple Hash, with __key__ as qualifier and an __IB::Contract__ as value.
|
|
21
|
+
# The Value is either a fully prequalified Contract (Stock, Option, Future, Forex, CFD, BAG) or
|
|
22
|
+
# a lazy qualified Contract acting as base für further calucaltions and requests.
|
|
23
|
+
#
|
|
24
|
+
# IB::Symbols.allocate_collection :Name
|
|
25
|
+
#
|
|
26
|
+
# creates the Module and file. If a previously created file is found, its contents are read and
|
|
27
|
+
# the vcollection ist reestablished.
|
|
28
|
+
#
|
|
29
|
+
# IB::Symbols::Name.add_contract :wfc, IB::Stock.new( symbol: 'WFC' )
|
|
30
|
+
#
|
|
31
|
+
# adds the contract and stores it in the yaml file
|
|
32
|
+
#
|
|
33
|
+
# IB::Symbols::Name.wfc # or IB::Symbols::Name[:wfc]
|
|
34
|
+
#
|
|
35
|
+
# retrieves the contract
|
|
36
|
+
#
|
|
37
|
+
# IB::Symbols::Name.all
|
|
38
|
+
#
|
|
39
|
+
# returns an Array of stored contracts
|
|
40
|
+
#
|
|
41
|
+
# IB::Symbols::Name.remove_contract :wfc
|
|
42
|
+
#
|
|
43
|
+
# deletes the contract from the list (and the file)
|
|
44
|
+
#
|
|
45
|
+
# To finish the cycle
|
|
46
|
+
#
|
|
47
|
+
# IB::Symbols::Name.purge_collection
|
|
48
|
+
#
|
|
49
|
+
# deletes the file and erases the collection in memory.
|
|
50
|
+
#
|
|
51
|
+
# Additional methods can be introduced
|
|
52
|
+
# * for individual contracts on the module-level or
|
|
53
|
+
# * to organize the list as methods of Array in Module IB::SymbolExtention
|
|
54
|
+
#
|
|
55
|
+
#
|
|
56
|
+
# Contracts can be hardcoded in the required standard-collections as well.
|
|
57
|
+
# Note that the :description field is local to ib-ruby, and is NOT part of the standard TWS API.
|
|
58
|
+
# It is never transmitted to IB. It's purely used clientside, and you can store any arbitrary
|
|
59
|
+
# string that you may find useful there.
|
|
60
|
+
|
|
61
|
+
module IB
|
|
62
|
+
module Symbols
|
|
63
|
+
class Error < StandardError; end
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def hardcoded?
|
|
68
|
+
!self.methods.include? :yml_file
|
|
69
|
+
end
|
|
70
|
+
def method_missing(method, *key)
|
|
71
|
+
if key.empty?
|
|
72
|
+
if contracts.has_key?(method)
|
|
73
|
+
contracts[method]
|
|
74
|
+
elsif methods.include?(:each) && each.methods.include?(method)
|
|
75
|
+
self.each.send method
|
|
76
|
+
else
|
|
77
|
+
error "contract #{method} not defined. Try »all« for a list of defined Contracts.", :symbol
|
|
78
|
+
end
|
|
79
|
+
else
|
|
80
|
+
error "method missing"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def all
|
|
85
|
+
contracts.keys.sort rescue contracts.keys
|
|
86
|
+
end
|
|
87
|
+
def print_all
|
|
88
|
+
puts contracts.sort.map{|x,y| [x,y.description].join(" -> ")}.join "\n"
|
|
89
|
+
end
|
|
90
|
+
def contracts
|
|
91
|
+
if @contracts.present?
|
|
92
|
+
@contracts
|
|
93
|
+
else
|
|
94
|
+
@contracts = Hash.new
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
def [] symbol
|
|
98
|
+
if c=contracts[symbol]
|
|
99
|
+
return c
|
|
100
|
+
else
|
|
101
|
+
# symbol probably has not been predefined, tell user about it
|
|
102
|
+
file = self.to_s.split(/::/).last.downcase
|
|
103
|
+
msg = "Unknown symbol :#{symbol}, please pre-define it in lib/ib/symbols/#{file}.rb"
|
|
104
|
+
error msg, :symbol
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
Connection.current.activate_plugin "verify"
|
|
111
|
+
Connection.current.activate_plugin "roll"
|
|
112
|
+
Connection.current.activate_plugin "spread-prototypes"
|
|
113
|
+
[ :forex, :futures, :stocks, :index, :cfd, :commodity, :options, :combo, :bonds, :abstract ].each do |pt|
|
|
114
|
+
Connection.current.activate_plugin "symbols/#{pt.to_s}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
=begin rdoc
|
|
3
|
+
|
|
4
|
+
Plugin that provides Verifying a contract
|
|
5
|
+
|
|
6
|
+
Public API
|
|
7
|
+
==========
|
|
8
|
+
|
|
9
|
+
Extends IB::Contract
|
|
10
|
+
|
|
11
|
+
* verify
|
|
12
|
+
|
|
13
|
+
returns an array of suitable IB::Contracts
|
|
14
|
+
```ruby
|
|
15
|
+
a = Stock.new symbol: 'AA'
|
|
16
|
+
aa = a.verify.first
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
an optional block may be used to modify and filter the tws-response
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
f = IB::Future.new symbol: 'M2K'
|
|
23
|
+
con_ids = f.verify{ |c| c.con_id }
|
|
24
|
+
=> [412889018, 428519982, 446091466, 461318872, 477836981]
|
|
25
|
+
```
|
|
26
|
+
=end
|
|
27
|
+
|
|
28
|
+
module Verify
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# IB::Contract#Verify
|
|
32
|
+
|
|
33
|
+
# verifies the contract
|
|
34
|
+
#
|
|
35
|
+
# returns the number of contracts returned by the TWS.
|
|
36
|
+
#
|
|
37
|
+
#
|
|
38
|
+
# The method accepts a block. The queried contract-Object is accessible there.
|
|
39
|
+
# If multiple contracts are returned by the tws, the block is executed with each of these contracts.
|
|
40
|
+
#
|
|
41
|
+
#
|
|
42
|
+
# Verify returns an _Array_ of contracts. The operation leaves the contract untouched.
|
|
43
|
+
#
|
|
44
|
+
#
|
|
45
|
+
# Returns nil if the contract could not be verified.
|
|
46
|
+
#
|
|
47
|
+
# > s = Stock.new symbol: 'AA'
|
|
48
|
+
# => #<IB::Stock:0x0000000002626cc0
|
|
49
|
+
# @attributes={:symbol=>"AA", :con_id=>0, :right=>"", :include_expired=>false,
|
|
50
|
+
# :sec_type=>"STK", :currency=>"USD", :exchange=>"SMART"}
|
|
51
|
+
# > sp = s.verify.first.essential
|
|
52
|
+
# => #<IB::Stock:0x00000000025a3cf8
|
|
53
|
+
# @attributes={:symbol=>"AA", :con_id=>251962528, :exchange=>"SMART", :currency=>"USD",
|
|
54
|
+
# :strike=>0.0, :local_symbol=>"AA", :multiplier=>0, :primary_exchange=>"NYSE",
|
|
55
|
+
# :trading_class=>"AA", :sec_type=>"STK", :right=>"", :include_expired=>false}
|
|
56
|
+
#
|
|
57
|
+
# > s = Stock.new symbol: 'invalid'
|
|
58
|
+
# => @attributes={:symbol=>"invalid", :sec_type=>"STK", :currency=>"USD", :exchange=>"SMART"}
|
|
59
|
+
# > sp = s.verify
|
|
60
|
+
# => []
|
|
61
|
+
#
|
|
62
|
+
# Takes a Block to modify the queried contracts
|
|
63
|
+
#
|
|
64
|
+
# f = Future.new symbol: 'M2K'
|
|
65
|
+
# con_ids = f.verify{ |c| c.con_id }
|
|
66
|
+
# [412889018, 428519982, 446091466, 461318872, 477836981]
|
|
67
|
+
#
|
|
68
|
+
#
|
|
69
|
+
# Parameter: thread: (true/false)
|
|
70
|
+
#
|
|
71
|
+
# If multiple contracts are to be verified, they can be queried simultaneously.
|
|
72
|
+
# IB::Symbols::W500.map{|c| c.verify(thread: true){ |vc| do_something }}.join
|
|
73
|
+
|
|
74
|
+
def verify thread: nil, &b
|
|
75
|
+
if thread
|
|
76
|
+
Thread.new { _verify &b }
|
|
77
|
+
else
|
|
78
|
+
i = 0
|
|
79
|
+
begin
|
|
80
|
+
_verify &b
|
|
81
|
+
rescue IB::VerifyError
|
|
82
|
+
i += 1
|
|
83
|
+
if i < 3
|
|
84
|
+
sleep 1
|
|
85
|
+
retry
|
|
86
|
+
else
|
|
87
|
+
raise
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end # def
|
|
92
|
+
|
|
93
|
+
# returns a hash
|
|
94
|
+
def necessary_attributes
|
|
95
|
+
|
|
96
|
+
v= { stock: { currency: 'USD', exchange: 'SMART', symbol: nil},
|
|
97
|
+
option: { currency: 'USD', exchange: 'SMART', right: 'P', expiry: nil, strike: nil, symbol: nil},
|
|
98
|
+
future: { currency: 'USD', exchange: nil, expiry: nil, symbol: nil },
|
|
99
|
+
forex: { currency: 'USD', exchange: 'IDEALPRO', symbol: nil }
|
|
100
|
+
}
|
|
101
|
+
sec_type.present? ? v[sec_type] : { con_id: nil, exchange: 'SMART' } # enables to use only con_id for verifying
|
|
102
|
+
# if the contract allows SMART routing
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
# Base method to verify a contract
|
|
109
|
+
#
|
|
110
|
+
# if :thread is given, the method subscribes to messages, fires the request and returns the thread, that
|
|
111
|
+
# receives the exit-condition-message
|
|
112
|
+
#
|
|
113
|
+
# otherwise the method waits until the response form tws is processed
|
|
114
|
+
#
|
|
115
|
+
#
|
|
116
|
+
# if :update is true, the attributes of the Contract itself are adapted
|
|
117
|
+
#
|
|
118
|
+
# otherwise the Contract is untouched
|
|
119
|
+
def _verify &b # :nodoc:
|
|
120
|
+
ib = Connection.current
|
|
121
|
+
error "No Connection" unless ib.is_a? Connection
|
|
122
|
+
# we generate a Request-Message-ID on the fly
|
|
123
|
+
error "Either con_id or sec_type have to be set", :verify if con_id.to_i.zero? && sec_type.blank?
|
|
124
|
+
# define local vars which are updated within the query-block
|
|
125
|
+
received_contracts = []
|
|
126
|
+
queue = Queue.new
|
|
127
|
+
message_id = nil
|
|
128
|
+
|
|
129
|
+
# a tws-request is suppressed for bags and if the contract_detail-record is present
|
|
130
|
+
tws_request_not_necessary = bag? || contract_detail.is_a?( ContractDetail )
|
|
131
|
+
|
|
132
|
+
if tws_request_not_necessary
|
|
133
|
+
yield self if block_given?
|
|
134
|
+
return [self] # return an array!
|
|
135
|
+
else # subscribe to ib-messages and describe what to do
|
|
136
|
+
a = ib.subscribe(:Alert, :ContractData, :ContractDataEnd) do |msg|
|
|
137
|
+
case msg
|
|
138
|
+
when Messages::Incoming::Alert
|
|
139
|
+
## do not throw an error here, asynchronous operation!
|
|
140
|
+
## just notice failure in log and return nil instead of contract-object
|
|
141
|
+
if msg.code == 200 && msg.error_id == message_id
|
|
142
|
+
ib.logger.error { "Not a valid Contract :: #{self.to_human} " }
|
|
143
|
+
queue.push "InvalidContract"
|
|
144
|
+
end
|
|
145
|
+
when Messages::Incoming::ContractData
|
|
146
|
+
if msg.request_id.to_i == message_id
|
|
147
|
+
c = if block_given?
|
|
148
|
+
yield msg.contract
|
|
149
|
+
else
|
|
150
|
+
msg.contract
|
|
151
|
+
end
|
|
152
|
+
queue.push c unless c.nil?
|
|
153
|
+
end
|
|
154
|
+
when Messages::Incoming::ContractDataEnd
|
|
155
|
+
queue.close if msg.request_id.to_i == message_id
|
|
156
|
+
end # case
|
|
157
|
+
end # subscribe
|
|
158
|
+
|
|
159
|
+
### send the request !
|
|
160
|
+
# contract_to_be_queried = con_id.present? ? self : query_contract
|
|
161
|
+
# if no con_id is present, the given attributes are checked by query_contract
|
|
162
|
+
# if contract_to_be_queried.present? # is nil if query_contract fails
|
|
163
|
+
message_id = ib.send_message :RequestContractData, :contract => query_contract
|
|
164
|
+
|
|
165
|
+
Thread.new do
|
|
166
|
+
(0 .. 10).each{ sleep 0.1 }
|
|
167
|
+
queue.push "TimeOut" unless queue.closed?
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
while r = queue.pop
|
|
171
|
+
if r.is_a? IB::Contract
|
|
172
|
+
received_contracts << r
|
|
173
|
+
else
|
|
174
|
+
error "No data received from IB-Servers", :verify if r == "TimeOut"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
ib.unsubscribe a
|
|
178
|
+
end
|
|
179
|
+
received_contracts # return contracts
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Generates an IB::Contract with the required attributes to retrieve a unique contract from the TWS
|
|
183
|
+
#
|
|
184
|
+
# Background: If the tws is queried with a »complete« IB::Contract, it fails occasionally.
|
|
185
|
+
# So – even to update its contents, a defined subset of query-parameters has to be used.
|
|
186
|
+
#
|
|
187
|
+
# The required data-fields are stored in a yaml-file and fetched by #YmlFile.
|
|
188
|
+
#
|
|
189
|
+
# If `con_id` is present, only `con_id` and `exchange` are transmitted to the tws.
|
|
190
|
+
# Otherwise a IB::Stock, IB::Option, IB::Future or IB::Forex-Object with necessary attributes
|
|
191
|
+
# to query the tws is build (and returned)
|
|
192
|
+
#
|
|
193
|
+
# If Attributes are missing, an IB::VerifyError is fired,
|
|
194
|
+
# This can be trapped with
|
|
195
|
+
# rescue IB::VerifyError do ...
|
|
196
|
+
|
|
197
|
+
def query_contract( invalid_record: true ) # :nodoc:
|
|
198
|
+
# don't raise a verify error at this time. Contract.new con_id= xxxx, currency = 'xyz' is also valid
|
|
199
|
+
## raise VerifyError, "Querying Contract failed: Invalid Security Type" unless SECURITY_TYPES.values.include? sec_type
|
|
200
|
+
|
|
201
|
+
## the yml contains symbol-entries
|
|
202
|
+
## these are converted to capitalized strings
|
|
203
|
+
items_as_string = ->(i){i.map{|x,y| x.to_s.capitalize}.join(', ')}
|
|
204
|
+
## here we read the corresponding attributes of the specified contract
|
|
205
|
+
item_values = ->(i){ i.map{|x,y| self.send(x).presence || y }}
|
|
206
|
+
## and finally we create a attribute-hash to instantiate a new Contract
|
|
207
|
+
## to_h is present only after ruby 2.1.0
|
|
208
|
+
item_attributehash = ->(i){ i.keys.zip(item_values[i]).to_h }
|
|
209
|
+
## now lets proceed, but only if no con_id is present
|
|
210
|
+
if con_id.blank? || con_id.zero?
|
|
211
|
+
# if item_values[necessary_attributes].any?( &:nil? )
|
|
212
|
+
# raise VerifyError, "#{items_as_string[necessary_attributes]} are needed to retrieve Contract,
|
|
213
|
+
# got: #{item_values[necessary_attributes].join(',')}"
|
|
214
|
+
# end
|
|
215
|
+
# Contract.build item_attributehash[necessary_items].merge(:sec_type=> sec_type) # return this
|
|
216
|
+
Contract.build self.invariant_attributes # return this
|
|
217
|
+
else # its always possible, to retrieve a Contract if con_id and exchange or are present
|
|
218
|
+
Contract.new con_id: con_id , :exchange => exchange.presence || item_attributehash[necessary_attributes][:exchange].presence || 'SMART' # return this
|
|
219
|
+
end # if
|
|
220
|
+
end # def
|
|
221
|
+
end # module verify
|
|
222
|
+
|
|
223
|
+
class Contract
|
|
224
|
+
include Verify
|
|
225
|
+
end
|
|
226
|
+
end #module ib
|