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
data/LLM_GUIDE.md
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# LLM Guide for ib-api
|
|
2
|
+
|
|
3
|
+
**Purpose**: This guide is optimized for LLMs (Large Language Models) to understand and work with the ib-api codebase efficiently.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## QUICK MENTAL MODEL
|
|
8
|
+
|
|
9
|
+
**What is this?**: A Ruby gem that provides a programmatic interface to Interactive Brokers' trading platform (TWS/Gateway).
|
|
10
|
+
|
|
11
|
+
**Core pattern**: You create a `Connection` object → it opens a TCP socket to IB → you send/recv messages → events trigger callbacks → data flows through plugins.
|
|
12
|
+
|
|
13
|
+
**Key insight**: Everything is message-driven. Connection manages a state machine, plugins extend functionality, and models represent trading objects.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## FILE MAP (WHERE THINGS LIVE)
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
lib/ib/
|
|
21
|
+
├── connection.rb # CORE: Main Connection class, workflow state machine
|
|
22
|
+
├── plugins.rb # Plugin activation system
|
|
23
|
+
├── messages/
|
|
24
|
+
│ ├── outgoing/ # Messages sent TO IB (requests)
|
|
25
|
+
│ └── incoming/ # Messages received FROM IB (responses)
|
|
26
|
+
└── constants.rb # IB API enums/constants
|
|
27
|
+
|
|
28
|
+
models/ib/ # Zeiteerk-loaded models
|
|
29
|
+
├── contract.rb # Base class for all instruments
|
|
30
|
+
├── stock.rb, option.rb, future.rb, etc. # Specific contract types
|
|
31
|
+
├── order.rb # Order objects
|
|
32
|
+
└── bar.rb # OHLCV market data
|
|
33
|
+
|
|
34
|
+
plugins/ib/ # Plugin implementations (extend Connection)
|
|
35
|
+
├── verify.rb # Contract verification
|
|
36
|
+
├── market-price.rb # Current price fetching
|
|
37
|
+
├── managed-accounts.rb # Account/portfolio management
|
|
38
|
+
└── ...
|
|
39
|
+
|
|
40
|
+
spec/
|
|
41
|
+
├── spec_helper.rb # Test config, loads spec.yml
|
|
42
|
+
├── spec.yml # IB connection settings (REQUIRED for tests)
|
|
43
|
+
└── howto.md # Guide for implementing new messages
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## THE CONNECTION OBJECT (CENTRAL HUB)
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
require 'ib-api'
|
|
52
|
+
|
|
53
|
+
# Create connection (does NOT connect yet)
|
|
54
|
+
ib = IB::Connection.new(host: '127.0.0.1', port: 7497)
|
|
55
|
+
|
|
56
|
+
# Connect (triggers workflow state transition)
|
|
57
|
+
ib.try_connection! # or use the event: ib.try_connection
|
|
58
|
+
|
|
59
|
+
# The connection is globally accessible
|
|
60
|
+
IB::Connection.current == ib # => true
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Connection attributes**:
|
|
64
|
+
- `socket`: TCP connection to IB
|
|
65
|
+
- `next_local_id`: Next available order ID
|
|
66
|
+
- `received`: Hash of received messages (by type)
|
|
67
|
+
- `plugins`: Array of activated plugin names
|
|
68
|
+
- `workflow_state`: Current state (virgin, ready, gateway_mode, etc.)
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## WORKFLOW STATE MACHINE
|
|
73
|
+
|
|
74
|
+
**States (linear progression typical)**:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
virgin (initial)
|
|
78
|
+
│
|
|
79
|
+
├─→ try_connection! → ready
|
|
80
|
+
│
|
|
81
|
+
├─→ activate_managed_accounts! → gateway_mode
|
|
82
|
+
│
|
|
83
|
+
└─→ collect_data! → lean_mode
|
|
84
|
+
|
|
85
|
+
ready
|
|
86
|
+
│
|
|
87
|
+
├─→ initialize_managed_accounts! → account_based_operations
|
|
88
|
+
│
|
|
89
|
+
└─→ disconnect! → disconnected
|
|
90
|
+
|
|
91
|
+
account_based_operations
|
|
92
|
+
│
|
|
93
|
+
└─→ initialize_order_handling! → account_based_orderflow
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**State meanings**:
|
|
97
|
+
- `virgin`: No connection
|
|
98
|
+
- `ready`: Connected, basic functionality
|
|
99
|
+
- `gateway_mode`: Multi-account gateway access
|
|
100
|
+
- `lean_mode`: Minimal data collection
|
|
101
|
+
- `account_based_operations`: Account/portfolio data loaded
|
|
102
|
+
- `account_based_orderflow`: Order processing active
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## MESSAGE SYSTEM (THE PROTOCOL)
|
|
107
|
+
|
|
108
|
+
**Sending messages**:
|
|
109
|
+
```ruby
|
|
110
|
+
# Method 1: Send symbol
|
|
111
|
+
ib.send_message :PlaceOrder, order: my_order, contract: my_contract
|
|
112
|
+
|
|
113
|
+
# Method 2: Send class
|
|
114
|
+
ib.send_message IB::Messages::Outgoing::PlaceOrder, order: my_order, contract: my_contract
|
|
115
|
+
|
|
116
|
+
# Method 3: Use instance
|
|
117
|
+
msg = IB::Messages::Outgoing::PlaceOrder.new(order: my_order, contract: my_contract)
|
|
118
|
+
ib.send_message msg
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Receiving messages** (subscribe to events):
|
|
122
|
+
```ruby
|
|
123
|
+
# Subscribe to a message type
|
|
124
|
+
subscription_id = ib.subscribe(:OrderStatus) do |msg|
|
|
125
|
+
puts "Order #{msg.order_id}: #{msg.status}"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Wait for a specific message type
|
|
129
|
+
ib.wait_for :OrderStatus, timeout: 5
|
|
130
|
+
|
|
131
|
+
# Access received messages
|
|
132
|
+
ib.received[:OrderStatus].each { |msg| ... }
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Message structure**:
|
|
136
|
+
- Outgoing messages: defined in `lib/ib/messages/outgoing/`
|
|
137
|
+
- Incoming messages: defined in `lib/ib/messages/incoming/`
|
|
138
|
+
- Messages use `def_message` macro to generate classes
|
|
139
|
+
- Each message has an ID and version for protocol compatibility
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## PLUGIN SYSTEM (EXTENSIBILITY)
|
|
144
|
+
|
|
145
|
+
**What plugins do**: Extend `IB::Connection` with additional methods by reopening the module.
|
|
146
|
+
|
|
147
|
+
**How to use**:
|
|
148
|
+
```ruby
|
|
149
|
+
# Activate plugin(s)
|
|
150
|
+
ib.activate_plugin :verify, :market_price, :connection_tools
|
|
151
|
+
|
|
152
|
+
# Now methods from those plugins are available
|
|
153
|
+
contract = IB::Stock.new(symbol: 'GE')
|
|
154
|
+
verified = contract.verify # provided by :verify plugin
|
|
155
|
+
price = contract.market_price # provided by :market_price plugin
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**How plugins are written**:
|
|
159
|
+
```ruby
|
|
160
|
+
# plugins/ib/my_plugin.rb
|
|
161
|
+
module IB
|
|
162
|
+
module Connection
|
|
163
|
+
def my_custom_method
|
|
164
|
+
# Can access @socket, send_message, etc.
|
|
165
|
+
send_message :SomeRequest
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Common plugins**:
|
|
172
|
+
- `connection-tools`: Ensures active connection
|
|
173
|
+
- `verify`: Fetch contract details from TWS
|
|
174
|
+
- `managed-accounts`: Fetch account/portfolio data
|
|
175
|
+
- `market-price`: Get current market price
|
|
176
|
+
- `advanced-account`: Account-based trading operations
|
|
177
|
+
- `greeks`: Option risk calculations
|
|
178
|
+
- `option-chain`: Build option chains
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## MODELS (DATA STRUCTURES)
|
|
183
|
+
|
|
184
|
+
**Contracts** (base: `IB::Contract`):
|
|
185
|
+
```ruby
|
|
186
|
+
stock = IB::Stock.new(symbol: 'GE', exchange: 'SMART', currency: 'USD')
|
|
187
|
+
option = IB::Option.new(symbol: 'GE', strike: 50, right: 'CALL', expiry: '20240120')
|
|
188
|
+
future = IB::Future.new(symbol: 'ES', expiry: '202403')
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Orders**:
|
|
192
|
+
```ruby
|
|
193
|
+
order = IB::Order.new(
|
|
194
|
+
total_quantity: 100,
|
|
195
|
+
action: :buy,
|
|
196
|
+
order_type: 'LMT',
|
|
197
|
+
limit_price: 35.0
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Place order
|
|
201
|
+
local_id = ib.place_order(order, stock)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Order methods on Connection**:
|
|
205
|
+
- `place_order(order, contract)`: Place new order
|
|
206
|
+
- `modify_order(order, contract)`: Modify existing order
|
|
207
|
+
- `cancel_order(*local_ids)`: Cancel order(s)
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## TESTING PATTERNS
|
|
212
|
+
|
|
213
|
+
**Test setup**:
|
|
214
|
+
```ruby
|
|
215
|
+
# spec/spec_helper.rb loads:
|
|
216
|
+
require 'spec_helper'
|
|
217
|
+
|
|
218
|
+
# Constants available:
|
|
219
|
+
OPTS[:connection] # Hash from spec.yml
|
|
220
|
+
ACCOUNT # Account ID from spec.yml
|
|
221
|
+
SAMPLE # IB::Stock from spec.yml
|
|
222
|
+
|
|
223
|
+
# Example test:
|
|
224
|
+
describe IB::Stock do
|
|
225
|
+
subject { IB::Stock.new(symbol: 'GE') }
|
|
226
|
+
|
|
227
|
+
it "verifies contract" do
|
|
228
|
+
verified = subject.verify
|
|
229
|
+
expect(verified).to be_truthy
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Running tests**:
|
|
235
|
+
```bash
|
|
236
|
+
# All tests
|
|
237
|
+
bundle exec rspec
|
|
238
|
+
|
|
239
|
+
# Single file
|
|
240
|
+
bundle exec rspec spec/ib/contract_spec.rb
|
|
241
|
+
|
|
242
|
+
# Focused (only tests with :focus tag or fit/fdescribe)
|
|
243
|
+
bundle exec rspec --tag focus
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**IMPORTANT**: Tests require valid IB credentials in `spec/spec.yml`:
|
|
247
|
+
```yaml
|
|
248
|
+
:connection:
|
|
249
|
+
:port: 4002
|
|
250
|
+
:host: 127.0.0.1
|
|
251
|
+
:account: DU123456 # Your paper account ID
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## CONSOLE USAGE
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Start console (connects to Gateway by default)
|
|
260
|
+
./console g # or ./console t for TWS
|
|
261
|
+
|
|
262
|
+
# In console:
|
|
263
|
+
C # => IB::Connection.current instance
|
|
264
|
+
C.received # => Hash of received messages
|
|
265
|
+
C.plugins # => Array of active plugins
|
|
266
|
+
|
|
267
|
+
# Example session:
|
|
268
|
+
> contract = IB::Stock.new(symbol: 'GE')
|
|
269
|
+
> contract.verify
|
|
270
|
+
> contract.market_price
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## CODE PATTERNS TO RECOGNIZE
|
|
276
|
+
|
|
277
|
+
**1. Event subscription pattern**:
|
|
278
|
+
```ruby
|
|
279
|
+
ib.subscribe(:MessageName) { |msg| ... }
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**2. Wait for response pattern**:
|
|
283
|
+
```ruby
|
|
284
|
+
ib.send_message :Request
|
|
285
|
+
ib.wait_for :Response
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**3. Plugin activation pattern**:
|
|
289
|
+
```ruby
|
|
290
|
+
ib.activate_plugin :plugin_name
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**4. Connection state transitions**:
|
|
294
|
+
```ruby
|
|
295
|
+
ib.try_connection! # Connect
|
|
296
|
+
ib.initialize_managed_accounts! # Load account data
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**5. Order placement**:
|
|
300
|
+
```ruby
|
|
301
|
+
local_id = ib.place_order(order, contract)
|
|
302
|
+
ib.wait_for :OpenOrder
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## COMMON OPERATIONS
|
|
308
|
+
|
|
309
|
+
**Get contract details**:
|
|
310
|
+
```ruby
|
|
311
|
+
ib.activate_plugin :verify
|
|
312
|
+
contract = IB::Stock.new(symbol: 'GE')
|
|
313
|
+
details = contract.verify # Returns array of Contract objects
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Get current price**:
|
|
317
|
+
```ruby
|
|
318
|
+
ib.activate_plugin :market_price
|
|
319
|
+
contract = IB::Stock.new(symbol: 'GE')
|
|
320
|
+
price = contract.market_price
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Place order**:
|
|
324
|
+
```ruby
|
|
325
|
+
contract = IB::Stock.new(symbol: 'GE')
|
|
326
|
+
order = IB::Order.new(limit_price: 35.0, order_type: 'LMT', total_quantity: 100, action: :buy)
|
|
327
|
+
ib.place_order(order, contract)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Get account/portfolio data**:
|
|
331
|
+
```ruby
|
|
332
|
+
ib.activate_plugin :managed_accounts
|
|
333
|
+
ib.get_account_data
|
|
334
|
+
ib.portfolio_values # Hash of portfolio positions
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## DEBUGGING NEW MESSAGES
|
|
340
|
+
|
|
341
|
+
When implementing a new message type:
|
|
342
|
+
|
|
343
|
+
1. Uncomment line 37 in `lib/ib/messages/incoming/abstract_message.rb` to see raw TWS output
|
|
344
|
+
2. Use the console (`./console`) to test
|
|
345
|
+
3. Send the request and inspect `C.received[:MessageName]`
|
|
346
|
+
4. Check the buffer attribute for unparsed data
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## KEY DEPENDENCIES
|
|
351
|
+
|
|
352
|
+
- **Zeitwerk**: Modern Ruby autoloading (models in `models/ib/` are autoloaded)
|
|
353
|
+
- **ActiveModel**: Base for data models
|
|
354
|
+
- **Workflow**: State machine for Connection
|
|
355
|
+
- **RSpec**: Testing framework
|
|
356
|
+
- **Ox**: XML parsing for some messages
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## API VERSIONS
|
|
361
|
+
|
|
362
|
+
- Client version: 66 (API 9.71+)
|
|
363
|
+
- Server version: 165+ (TWS 10.19+)
|
|
364
|
+
- Protocol supports multiple IB API versions via message versioning
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## MENTAL CHECKLIST FOR TASKS
|
|
369
|
+
|
|
370
|
+
**Before modifying**:
|
|
371
|
+
1. Read the relevant model or message definition first
|
|
372
|
+
2. Check if a plugin already provides the functionality
|
|
373
|
+
3. Understand the current workflow state
|
|
374
|
+
|
|
375
|
+
**When adding new messages**:
|
|
376
|
+
1. Define in `lib/ib/messages/outgoing/` (request) or `incoming/` (response)
|
|
377
|
+
2. Use `def_message` macro with proper ID and version
|
|
378
|
+
3. Test in console first, then write spec
|
|
379
|
+
|
|
380
|
+
**When adding plugins**:
|
|
381
|
+
1. Create file in `plugins/ib/`
|
|
382
|
+
2. Reopen `IB::Connection` module
|
|
383
|
+
3. Activate via `ib.activate_plugin :plugin_name`
|
|
384
|
+
|
|
385
|
+
**When writing tests**:
|
|
386
|
+
1. Ensure `spec/spec.yml` has valid credentials
|
|
387
|
+
2. Use `SAMPLE` constant for test data
|
|
388
|
+
3. Use `ib.wait_for` to wait for async responses
|
data/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# ib-api
|
|
2
|
+
Ruby interface to Interactive Brokers' TWS API
|
|
3
|
+
|
|
4
|
+
Reimplementation of ib-ruby
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
__STATUS: Gem-Release is still pending
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
* Zeitwerk integration.
|
|
12
|
+
* Plugin's to ease automations
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
__Documentation: [https://ib-ruby.github.io/ib-doc/](https://ib-ruby.github.io/ib-doc/)__ (_work in progress_)
|
|
16
|
+
|
|
17
|
+
----
|
|
18
|
+
`ib-api` offers a modular access to the TWS-API-Interface of Interactive Brokers.
|
|
19
|
+
|
|
20
|
+
----
|
|
21
|
+
|
|
22
|
+
Install in the usual way
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
$ gem install ib-api
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
In its plain vanilla usage, it just exchanges messages with the TWS. Any response is stored in the `received-array`.
|
|
29
|
+
|
|
30
|
+
It needs just a few lines of code to place an order
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
require 'ib-api'
|
|
34
|
+
# connect with default parameters
|
|
35
|
+
ib = IB::Connection.new
|
|
36
|
+
|
|
37
|
+
# define a contract to deal with
|
|
38
|
+
the_stock = IB::Stock.new symbol: 'TAP'
|
|
39
|
+
|
|
40
|
+
# order 100 shares for 35 $
|
|
41
|
+
limit_order = IB::Order.new limit_price: 35, order_type: 'LMT', total_quantity: 100, action: :buy
|
|
42
|
+
ib.send_message :PlaceOrder,
|
|
43
|
+
:order => limit_order,
|
|
44
|
+
:contract => the_stock,
|
|
45
|
+
:local_id => ib.next_local_id
|
|
46
|
+
|
|
47
|
+
# wait until the orderstate message returned
|
|
48
|
+
ib.wait_for :OrderStatus
|
|
49
|
+
|
|
50
|
+
# print the Orderstatus
|
|
51
|
+
puts ib.recieved[:OrderStatus].to_human
|
|
52
|
+
|
|
53
|
+
# => ["<OrderState: Submitted #17/1528367295 from 2000 filled 0.0/100.0 at 0.0/0.0 why_held >"]
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Plugins
|
|
58
|
+
|
|
59
|
+
**IB-API** ships with simple plugins to facilitate automations
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
require 'ib-api'
|
|
63
|
+
# connect with default parameters
|
|
64
|
+
ib = IB::Connection.new do | c |
|
|
65
|
+
c.activate_plugin "verify"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
g = IB::Stock.new symbol: 'GE'
|
|
69
|
+
puts g.verify.first.attributes
|
|
70
|
+
{:symbol=>"GE", :sec_type=>"STK", :last_trading_day=>"", :strike=>0.0, :right=>"", :exchange=>"SMART", :currency=>"USD", :local_symbol=>"GE", :trading_class=>"GE", :con_id=>498843743, :multiplier=>0, :primary_exchange=>"NYSE", }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Currently implemented plugins
|
|
74
|
+
|
|
75
|
+
* connection-tools: ensure that a connection is established and active
|
|
76
|
+
* verify: get contract details from the tws
|
|
77
|
+
* symbols: use predefined symbols
|
|
78
|
+
* managed-accounts: fetch and organize account- and portfoliovalues
|
|
79
|
+
* advanced-account: perform account-based previewing, opening, modifying and closing of Positions
|
|
80
|
+
* process-orders: account-based bookkeeping of orders
|
|
81
|
+
* auto-adjust: properly adjust the orderprice to the next valid min-tick of the contract
|
|
82
|
+
* market-price: fetch the current market-price of a contract
|
|
83
|
+
* eod: retrieve EOD-Data for the given contract
|
|
84
|
+
* greeks: read current option greeks
|
|
85
|
+
* roll: easy rolling of futures and options
|
|
86
|
+
* option-chain: build option-chains for given strikes and expiries
|
|
87
|
+
* spread-prototypes: create limit, stop, market, etc. orders through prototypes
|
|
88
|
+
* probability-of-expiring: calculate the probability of expiring for the option-contract
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## Minimal TWS-Version
|
|
92
|
+
|
|
93
|
+
`ib-api` is tested via the _stable IB-Gateway_ (Version 10.33) and should work with any current tws-installation.
|
|
94
|
+
|
|
95
|
+
## Tests
|
|
96
|
+
|
|
97
|
+
are invoked by
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
bundle exec guard
|
|
101
|
+
# or
|
|
102
|
+
bundle exec rake spec
|
|
103
|
+
```
|
|
104
|
+
Integration tests on order-placements are not included. To run the test suite its thus safe to use a _real Account_.
|
|
105
|
+
You have to edit `spec/spec.yml` and replace the `:account`-Setting with your own `AccountID`, even if you connect to a single account.
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Contributing
|
|
109
|
+
|
|
110
|
+
Bug reports and pull requests are welcome. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
111
|
+
|
|
112
|
+
## Code of Conduct
|
|
113
|
+
|
|
114
|
+
Everyone interacting in the Core project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/ib-api/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
10.33.1
|
data/api.gemspec
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require "ib/version"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "ib-api"
|
|
8
|
+
spec.version = IB::VERSION
|
|
9
|
+
spec.authors = ["Hartmut Bischoff"]
|
|
10
|
+
spec.email = ["topofocus@gmail.com"]
|
|
11
|
+
spec.license = "MIT"
|
|
12
|
+
|
|
13
|
+
spec.summary = %q{Ruby Implementation of the Interactive Brokers TWS API}
|
|
14
|
+
spec.description = %q{Ruby Implementation of the Interactive Brokers TWS API}
|
|
15
|
+
spec.homepage = "https://github.com/ib-ruby"
|
|
16
|
+
spec.required_ruby_version = ">= 3.0"
|
|
17
|
+
|
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
|
20
|
+
if spec.respond_to?(:metadata)
|
|
21
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
|
22
|
+
|
|
23
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
24
|
+
spec.metadata["source_code_uri"] = "https://github.com/ib-ruby/ib-api"
|
|
25
|
+
# spec.metadata["changelog_uri"] = "https://github.com/ib-ruby/ib-api/CHANGELOG.md"
|
|
26
|
+
else
|
|
27
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
|
28
|
+
"public gem pushes."
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Specify which files should be added to the gem when it is released.
|
|
32
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
33
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
34
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
35
|
+
end
|
|
36
|
+
spec.bindir = "exe"
|
|
37
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
38
|
+
spec.require_paths = ["lib"]
|
|
39
|
+
|
|
40
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
|
41
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
42
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
43
|
+
spec.add_dependency 'activesupport', '~> 6.0'
|
|
44
|
+
spec.add_dependency 'activemodel', '~> 7.0'
|
|
45
|
+
spec.add_dependency 'ox', '~> 2.14'
|
|
46
|
+
spec.add_dependency 'terminal-table', '~> 3.0'
|
|
47
|
+
spec.add_dependency 'zeitwerk', '~> 2.6'
|
|
48
|
+
spec.add_dependency 'workflow', '~> 3.1'
|
|
49
|
+
|
|
50
|
+
end
|
data/bin/console
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
### loads the active-orient environment
|
|
3
|
+
### and starts an interactive shell
|
|
4
|
+
###
|
|
5
|
+
### Parameter: t)ws | g)ateway (or number of port ) Default: Gateway ,
|
|
6
|
+
### client_id , Default 2000
|
|
7
|
+
###
|
|
8
|
+
### Define Parameter in file console.yml
|
|
9
|
+
###
|
|
10
|
+
require 'bundler/setup'
|
|
11
|
+
require 'yaml'
|
|
12
|
+
|
|
13
|
+
require 'ib-api'
|
|
14
|
+
|
|
15
|
+
class Array
|
|
16
|
+
# enables calling members of an array. which are hashes by it name
|
|
17
|
+
# i.e
|
|
18
|
+
#
|
|
19
|
+
# 2.5.0 :006 > C.received[:OpenOrder].local_id
|
|
20
|
+
# => [16, 17, 21, 20, 19, 8, 7]
|
|
21
|
+
# 2.5.0 :007 > C.received[:OpenOrder].contract.to_human
|
|
22
|
+
# => ["<Bag: IECombo SMART USD legs: >", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: WFC USD>", "<Stock: WFC USD>"]
|
|
23
|
+
#
|
|
24
|
+
# its included only in the console, for inspection purposes
|
|
25
|
+
|
|
26
|
+
def method_missing(method, *key)
|
|
27
|
+
unless method == :to_hash || method == :to_str #|| method == :to_int
|
|
28
|
+
return self.map{|x| x.public_send(method, *key)}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end # Array
|
|
33
|
+
|
|
34
|
+
class Object
|
|
35
|
+
def inspect
|
|
36
|
+
respond_to?(:to_human) ? to_human : super
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# read items from console.yml
|
|
41
|
+
read_yml = -> (key) do
|
|
42
|
+
YAML::load_file( File.expand_path('../console.yml',__FILE__))[key]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
puts
|
|
46
|
+
puts ">> IB-API Interactive Console <<"
|
|
47
|
+
puts '-'* 45
|
|
48
|
+
puts
|
|
49
|
+
puts "Namespace is IB ! "
|
|
50
|
+
puts
|
|
51
|
+
puts '-'* 45
|
|
52
|
+
include IB
|
|
53
|
+
require 'irb'
|
|
54
|
+
client_id = ARGV[1] || read_yml[:client_id]
|
|
55
|
+
specified_host = ARGV[0] || 'Gateway'
|
|
56
|
+
host = case specified_host
|
|
57
|
+
when /^[gG]/
|
|
58
|
+
read_yml[:gateway]
|
|
59
|
+
when /^[Tt]/
|
|
60
|
+
read_yml[:tws]
|
|
61
|
+
else
|
|
62
|
+
raise "Specify target from console.yml: `g|t` instead of #{specified_host}"
|
|
63
|
+
end
|
|
64
|
+
ARGV.clear
|
|
65
|
+
|
|
66
|
+
C = Connection.new client_id: client_id, host: host
|
|
67
|
+
C.logger.level = Logger::WARN
|
|
68
|
+
|
|
69
|
+
C.subscribe(:Alert){ |m| puts "A: "+ m.message }
|
|
70
|
+
C.subscribe(:AccountUpdateTime){ }
|
|
71
|
+
|
|
72
|
+
C.received = true
|
|
73
|
+
C.activate_plugin :connection_tools, :symbols, :market_price,
|
|
74
|
+
"order-prototypes", "spread-prototypes",
|
|
75
|
+
"advanced_account", 'process_orders'
|
|
76
|
+
C.logger.level = Logger::INFO
|
|
77
|
+
puts C.workflow_state
|
|
78
|
+
C.get_account_data
|
|
79
|
+
C.request_open_orders
|
|
80
|
+
C.logger.level = Logger::ERROR
|
|
81
|
+
puts "Connection established on #{host}"
|
|
82
|
+
|
|
83
|
+
unless C.received[:OpenOrder].blank?
|
|
84
|
+
puts "---------------------------------------- OpenOrders -------------------------------------------"
|
|
85
|
+
puts C.clients.map{ |c| c.orders.map &:to_human }.flatten.join("\n")
|
|
86
|
+
end
|
|
87
|
+
puts ""
|
|
88
|
+
puts Terminal::Table.new title: 'Active Plugins',
|
|
89
|
+
rows: C.plugins.delete_if{ |x| x =~ /\// }.sort.each_slice(4),
|
|
90
|
+
style: { border: :unicode }
|
|
91
|
+
puts
|
|
92
|
+
puts "----> C points to the connection-instance"
|
|
93
|
+
puts
|
|
94
|
+
puts '-'* 45
|
|
95
|
+
|
|
96
|
+
IRB.start(__FILE__)
|
data/bin/console.yml
ADDED