ibflex2 1.0.0__py3-none-any.whl
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.
- ibflex/Types.py +2823 -0
- ibflex/__init__.py +19 -0
- ibflex/__version__.py +26 -0
- ibflex/client.py +259 -0
- ibflex/enums.py +295 -0
- ibflex/parser.py +487 -0
- ibflex/py.typed +0 -0
- ibflex/utils.py +16 -0
- ibflex2-1.0.0.dist-info/METADATA +208 -0
- ibflex2-1.0.0.dist-info/RECORD +14 -0
- ibflex2-1.0.0.dist-info/WHEEL +5 -0
- ibflex2-1.0.0.dist-info/entry_points.txt +2 -0
- ibflex2-1.0.0.dist-info/licenses/LICENSE.txt +19 -0
- ibflex2-1.0.0.dist-info/top_level.txt +1 -0
ibflex/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from . import enums
|
|
2
|
+
from .enums import *
|
|
3
|
+
from . import Types
|
|
4
|
+
from .Types import *
|
|
5
|
+
from . import parser
|
|
6
|
+
from .parser import parse
|
|
7
|
+
from . import utils
|
|
8
|
+
from . import client
|
|
9
|
+
|
|
10
|
+
from .__version__ import (
|
|
11
|
+
__title__,
|
|
12
|
+
__description__,
|
|
13
|
+
__url__,
|
|
14
|
+
__version__,
|
|
15
|
+
__author__,
|
|
16
|
+
__author_email__,
|
|
17
|
+
__license__,
|
|
18
|
+
__copyright__,
|
|
19
|
+
)
|
ibflex/__version__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Get a job, save your money, listen to Jane
|
|
3
|
+
Everybody knows umbrellas cost more in the rain
|
|
4
|
+
All the news is bad
|
|
5
|
+
Is there any other kind?
|
|
6
|
+
Everybody's talking at the same time
|
|
7
|
+
|
|
8
|
+
It's hard times for some
|
|
9
|
+
For others it's sweet
|
|
10
|
+
Someone makes money when there's blood in the street
|
|
11
|
+
Don't take any lip
|
|
12
|
+
Stay in line
|
|
13
|
+
Everybody's talking at the same time
|
|
14
|
+
"""
|
|
15
|
+
__title__ = "ibflex2"
|
|
16
|
+
__description__ = (
|
|
17
|
+
"Parse Interactive Brokers Flex XML reports and convert to Python types (maintained fork)"
|
|
18
|
+
),
|
|
19
|
+
__url__ = "https://github.com/robcohen/ibflex2"
|
|
20
|
+
__upstream_url__ = "https://github.com/csingley/ibflex"
|
|
21
|
+
__version__ = "1.0.0"
|
|
22
|
+
__author__ = "Christopher Singley"
|
|
23
|
+
__author_email__ = "csingley@gmail.com"
|
|
24
|
+
__maintainer__ = "robcohen"
|
|
25
|
+
__license__ = "MIT"
|
|
26
|
+
__copyright__ = "Copyright 2017 Christopher Singley"
|
ibflex/client.py
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
"""
|
|
3
|
+
Download Flex queries without logging into Account Management web page.
|
|
4
|
+
|
|
5
|
+
https://www.interactivebrokers.com/en/software/am/am/reports/flex_web_service_version_3.htm
|
|
6
|
+
"""
|
|
7
|
+
# stdlib imports
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
import xml.etree.ElementTree as ET
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
import time
|
|
12
|
+
from typing import Union, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# 3rd party imports
|
|
16
|
+
import requests
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
###############################################################################
|
|
20
|
+
# SERVICE LOCATIONS
|
|
21
|
+
###############################################################################
|
|
22
|
+
FLEX_URL = 'https://gdcdyn.interactivebrokers.com/Universal/servlet/'
|
|
23
|
+
REQUEST_URL = FLEX_URL + 'FlexStatementService.SendRequest'
|
|
24
|
+
STMT_URL = FLEX_URL + 'FlexStatementService.GetStatement'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
###############################################################################
|
|
28
|
+
# ERRORS
|
|
29
|
+
###############################################################################
|
|
30
|
+
ERRORS = [
|
|
31
|
+
("1003", "Statement is not available."),
|
|
32
|
+
("1004", "Statement is incomplete at this time. Please try again shortly."),
|
|
33
|
+
("1005", "Settlement data is not ready at this time. Please try again shortly."),
|
|
34
|
+
("1006", "FIFO P/L data is not ready at this time. Please try again shortly."),
|
|
35
|
+
("1007", "MTM P/L data is not ready at this time. Please try again shortly."),
|
|
36
|
+
("1008", "MTM and FIFO P/L data is not ready at this time. Please try again shortly."),
|
|
37
|
+
("1009", "The server is under heavy load. Statement could not be generated at this time. Please try again shortly."),
|
|
38
|
+
("1010", "Legacy Flex Queries are no longer supported. Please convert over to Activity Flex."),
|
|
39
|
+
("1011", "Service account is inactive."),
|
|
40
|
+
("1012", "Token has expired."),
|
|
41
|
+
("1013", "IP restriction."),
|
|
42
|
+
("1014", "Query is invalid."),
|
|
43
|
+
("1015", "Token is invalid."),
|
|
44
|
+
("1016", "Account in invalid."),
|
|
45
|
+
("1017", "Reference code is invalid."),
|
|
46
|
+
("1018", "Too many requests have been made from this token. Please try again shortly."),
|
|
47
|
+
("1019", "Statement generation in progress. Please try again shortly."),
|
|
48
|
+
("1020", "Invalid request or unable to validate request."),
|
|
49
|
+
("1021", "Statement could not be retrieved at this time. Please try again shortly."),
|
|
50
|
+
]
|
|
51
|
+
ERROR_CODES, ERROR_MSGS = zip(*ERRORS)
|
|
52
|
+
|
|
53
|
+
SERVER_BUSY = ("1009", "1019", )
|
|
54
|
+
CLIENT_THROTTLED = ("1018", )
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class IbflexClientError(Exception):
|
|
58
|
+
""" Base class for Exceptions defined in this module """
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class BadResponseError(IbflexClientError):
|
|
62
|
+
"""
|
|
63
|
+
Exception raised for malformed Flex response.
|
|
64
|
+
"""
|
|
65
|
+
def __init__(self, response: requests.Response):
|
|
66
|
+
self.response = response
|
|
67
|
+
super(BadResponseError, self).__init__(response.content)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class StatementGenerationTimeout(IbflexClientError):
|
|
71
|
+
""" Exception raised when the Flex server says it is generating the response,
|
|
72
|
+
but does not finish generating the statement in a timely fashion.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ResponseCodeError(IbflexClientError):
|
|
77
|
+
"""
|
|
78
|
+
Exception raised when Flex server returns a response with an error code.
|
|
79
|
+
"""
|
|
80
|
+
def __init__(self, code: str, msg: str):
|
|
81
|
+
self.code = code
|
|
82
|
+
self.msg = msg
|
|
83
|
+
super(ResponseCodeError, self).__init__(f"Code={code}: {msg}")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
###############################################################################
|
|
87
|
+
# FlexStatementResponse TYPES
|
|
88
|
+
###############################################################################
|
|
89
|
+
@dataclass(frozen=True)
|
|
90
|
+
class StatementAccess:
|
|
91
|
+
timestamp: datetime
|
|
92
|
+
ReferenceCode: str
|
|
93
|
+
Url: str
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass(frozen=True)
|
|
97
|
+
class StatementError:
|
|
98
|
+
timestamp: datetime
|
|
99
|
+
ErrorCode: str
|
|
100
|
+
ErrorMessage: str
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
###############################################################################
|
|
104
|
+
# FUNCTIONS
|
|
105
|
+
###############################################################################
|
|
106
|
+
def download(token: str, query_id: str, max_tries: Optional[int] = 5) -> bytes:
|
|
107
|
+
"""2-step FlexQueryReport download process.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
token: Current access token from Reports > Settings > FlexWeb Service.
|
|
111
|
+
query_id: Flex Query ID from
|
|
112
|
+
Reports > Flex Queries > Custom Flex Queries > Configure.
|
|
113
|
+
"""
|
|
114
|
+
stmt_access = request_statement(token, query_id)
|
|
115
|
+
status = 0
|
|
116
|
+
tries = 0
|
|
117
|
+
while status is not True:
|
|
118
|
+
time.sleep(status)
|
|
119
|
+
tries += 1
|
|
120
|
+
response = submit_request(
|
|
121
|
+
url=stmt_access.Url or STMT_URL,
|
|
122
|
+
token=token,
|
|
123
|
+
query=stmt_access.ReferenceCode,
|
|
124
|
+
)
|
|
125
|
+
status = check_statement_response(response)
|
|
126
|
+
if max_tries and tries > max_tries:
|
|
127
|
+
raise StatementGenerationTimeout(
|
|
128
|
+
"Exceeded max number of tries while attempting download"
|
|
129
|
+
)
|
|
130
|
+
return response.content
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def request_statement(
|
|
134
|
+
token: str, query_id: str, url: Optional[str] = None
|
|
135
|
+
) -> StatementAccess:
|
|
136
|
+
"""First part of the 2-step download process.
|
|
137
|
+
"""
|
|
138
|
+
url = url or REQUEST_URL
|
|
139
|
+
### AKE FIX
|
|
140
|
+
url = 'https://ndcdyn.interactivebrokers.com/portal.flexweb/api/v1/flexQuery'
|
|
141
|
+
response = submit_request(url, token, query=query_id)
|
|
142
|
+
stmt_access = parse_stmt_response(response)
|
|
143
|
+
if isinstance(stmt_access, StatementError):
|
|
144
|
+
raise ResponseCodeError(
|
|
145
|
+
stmt_access.ErrorCode,
|
|
146
|
+
stmt_access.ErrorMessage,
|
|
147
|
+
)
|
|
148
|
+
return stmt_access
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def submit_request(url: str, token: str, query: str) -> requests.Response:
|
|
152
|
+
"""Post a query to an API access point, along with an authentication token.
|
|
153
|
+
|
|
154
|
+
Retry with a progressive timeout window.
|
|
155
|
+
"""
|
|
156
|
+
MAX_REQUESTS = 3
|
|
157
|
+
TIMEOUT_INCREMENT = 5
|
|
158
|
+
|
|
159
|
+
response = None
|
|
160
|
+
req_count = 1
|
|
161
|
+
while (not response):
|
|
162
|
+
try:
|
|
163
|
+
response = requests.get(
|
|
164
|
+
url,
|
|
165
|
+
params={"v": "3", "t": token, "q": query},
|
|
166
|
+
headers={"user-agent": "Java"},
|
|
167
|
+
timeout=req_count * TIMEOUT_INCREMENT,
|
|
168
|
+
)
|
|
169
|
+
except requests.exceptions.Timeout:
|
|
170
|
+
if req_count >= MAX_REQUESTS:
|
|
171
|
+
raise
|
|
172
|
+
else:
|
|
173
|
+
print("Request Timeout, re-sending...")
|
|
174
|
+
req_count += 1
|
|
175
|
+
|
|
176
|
+
return response
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def parse_stmt_response(
|
|
180
|
+
response: requests.Response
|
|
181
|
+
) -> Union[StatementAccess, StatementError]:
|
|
182
|
+
"""Read 1st step response; parse into StatementAccess or StatementError.
|
|
183
|
+
"""
|
|
184
|
+
try:
|
|
185
|
+
elem = ET.fromstring(response.content)
|
|
186
|
+
assert elem.tag == 'FlexStatementResponse'
|
|
187
|
+
|
|
188
|
+
timestamp = elem.attrib['timestamp']
|
|
189
|
+
# Convert "EST"/"EDT" to UTC offset so datetime.strptime can understand
|
|
190
|
+
tz = {'EST': '-0500', 'EDT': '-0400'}[timestamp[-3:]]
|
|
191
|
+
timestamp = timestamp[:-3] + tz
|
|
192
|
+
datetime_ = datetime.strptime(timestamp, '%d %B, %Y %I:%M %p %z')
|
|
193
|
+
|
|
194
|
+
data = {child.tag: child.text for child in elem}
|
|
195
|
+
status = data.pop("Status")
|
|
196
|
+
assert status in {"Success", "Fail", "Warn"}
|
|
197
|
+
Type = {
|
|
198
|
+
"Success": StatementAccess,
|
|
199
|
+
"Fail": StatementError,
|
|
200
|
+
"Warn": StatementError,
|
|
201
|
+
}[status]
|
|
202
|
+
return Type(timestamp=datetime_, **data) # type: ignore
|
|
203
|
+
except Exception:
|
|
204
|
+
raise BadResponseError(response=response)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def check_statement_response(response: requests.Response) -> Union[bool, int]:
|
|
208
|
+
"""Validate response received from 2nd step of download.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
True if `response` contains a FlexQueryResponse.
|
|
212
|
+
Retry delay (seconds) if `response` is an error indicating that
|
|
213
|
+
'please try again shortly' means 'within several seconds'.
|
|
214
|
+
|
|
215
|
+
Raises:
|
|
216
|
+
ResponseCodeError if `response` is any other kind of error.
|
|
217
|
+
BadResponseError if we can't parse `response`.
|
|
218
|
+
"""
|
|
219
|
+
# FlexQueryResponses can be massive; avoid parsing them.
|
|
220
|
+
resp_str = str(response.content)
|
|
221
|
+
if 'FlexQueryResponse' in resp_str:
|
|
222
|
+
return True
|
|
223
|
+
elif 'FlexStatementResponse' in resp_str:
|
|
224
|
+
try:
|
|
225
|
+
error = parse_stmt_response(response)
|
|
226
|
+
assert isinstance(error, StatementError)
|
|
227
|
+
except Exception:
|
|
228
|
+
raise BadResponseError(response)
|
|
229
|
+
if error.ErrorCode in SERVER_BUSY:
|
|
230
|
+
# Statement generation in progress. Please try again shortly.
|
|
231
|
+
return 5
|
|
232
|
+
elif error.ErrorCode in CLIENT_THROTTLED:
|
|
233
|
+
# Too many requests have been made from this token. Please try again shortly.
|
|
234
|
+
return 10
|
|
235
|
+
else:
|
|
236
|
+
raise ResponseCodeError(error.ErrorCode, error.ErrorMessage)
|
|
237
|
+
else:
|
|
238
|
+
raise BadResponseError(response)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
##############################################################################
|
|
242
|
+
# CLI SCRIPT
|
|
243
|
+
###############################################################################
|
|
244
|
+
def main():
|
|
245
|
+
from argparse import ArgumentParser
|
|
246
|
+
description = 'Download Flex brokerage statement from Interactive Brokers'
|
|
247
|
+
argparser = ArgumentParser(description=description)
|
|
248
|
+
argparser.add_argument('--token', '-t', required=True,
|
|
249
|
+
help='Current Flex Web Service token')
|
|
250
|
+
argparser.add_argument('--query', '-q', required=True,
|
|
251
|
+
help='Flex Query ID#')
|
|
252
|
+
args = argparser.parse_args()
|
|
253
|
+
|
|
254
|
+
statement = download(args.token, args.query)
|
|
255
|
+
print(statement.decode())
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
if __name__ == '__main__':
|
|
259
|
+
main()
|
ibflex/enums.py
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
"""Enumerated values (Python enum.Enum subclasses) used to define ibflex.Types.
|
|
3
|
+
|
|
4
|
+
Values are the text sent by IB in XML element attribute.
|
|
5
|
+
Names keep the convention of using UPPERCASE for Enums.
|
|
6
|
+
|
|
7
|
+
When creating a new Enum subclass, be sure to add it to ENUMS
|
|
8
|
+
and EnumType (as Optional type) at the end of the file.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"CashAction",
|
|
13
|
+
"Code",
|
|
14
|
+
"AssetClass",
|
|
15
|
+
"TradeType",
|
|
16
|
+
"BuySell",
|
|
17
|
+
"OpenClose",
|
|
18
|
+
"OrderType",
|
|
19
|
+
"Reorg",
|
|
20
|
+
"OptionAction",
|
|
21
|
+
"LongShort",
|
|
22
|
+
"TransferType",
|
|
23
|
+
"ToFrom",
|
|
24
|
+
"InOut",
|
|
25
|
+
"DeliveredReceived",
|
|
26
|
+
"ENUMS",
|
|
27
|
+
"EnumType",
|
|
28
|
+
"PutCall"
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
import enum
|
|
32
|
+
import typing
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@enum.unique
|
|
36
|
+
class CashAction(str, enum.Enum):
|
|
37
|
+
DEPOSITWITHDRAW = "Deposits & Withdrawals"
|
|
38
|
+
BROKERINTPAID = "Broker Interest Paid"
|
|
39
|
+
BROKERINTRCVD = "Broker Interest Received"
|
|
40
|
+
WHTAX = "Withholding Tax"
|
|
41
|
+
BONDINTRCVD = "Bond Interest Received"
|
|
42
|
+
BONDINTPAID = "Bond Interest Paid"
|
|
43
|
+
FEES = "Other Fees"
|
|
44
|
+
DIVIDEND = "Dividends"
|
|
45
|
+
PAYMENTINLIEU = "Payment In Lieu Of Dividends"
|
|
46
|
+
COMMADJ = "Commission Adjustments"
|
|
47
|
+
ADVISORFEES = "Advisor Fees"
|
|
48
|
+
|
|
49
|
+
@enum.unique
|
|
50
|
+
class Code(str, enum.Enum):
|
|
51
|
+
"""Used for both `code` and `notes` attributes.
|
|
52
|
+
"""
|
|
53
|
+
ASSIGNMENT = "A"
|
|
54
|
+
AUTOEXERCISE = "AEx" # Automatic exercise for dividend-related recommendation
|
|
55
|
+
AUTOFX = "AFx" # AutoFX conversion resulting from trading
|
|
56
|
+
ADJUSTMENT = "Adj" # Adjustment
|
|
57
|
+
ALLOCATION = "Al" # Allocation
|
|
58
|
+
AWAY = "Aw" # Away Trade
|
|
59
|
+
BUYIN = "B" # Automatic Buy-in
|
|
60
|
+
BORROW = "Bo" # Direct Borrow
|
|
61
|
+
CLOSING = "C" # Closing Trade
|
|
62
|
+
CASHDELIVERY = "CD" # Cash Delivery
|
|
63
|
+
COMPLEX = "CP" # Complex Position
|
|
64
|
+
CANCEL = "Ca" # Cancelled
|
|
65
|
+
CORRECT = "Co" # Corrected Trade
|
|
66
|
+
CROSSING = "Cx" # Part or all of this transaction was a Crossing executed as dual agent by IB for two IB customers
|
|
67
|
+
DUAL = "D" # IB acted as Dual Agent, UNIQUE TO TRADE CONFIRM REPORT
|
|
68
|
+
ETF = "ETF" # ETF Creation/Redemption
|
|
69
|
+
EXPIRED = "Ep" # Resulted from an Expired Position
|
|
70
|
+
EXERCISE = "Ex" # Exercise
|
|
71
|
+
GUARANTEED = "G" # Trade in Guaranteed Account Segment
|
|
72
|
+
HIGHESTCOST = "HC" # Highest Cost tax lot-matching method
|
|
73
|
+
HFINVESTMENT = "HFI" # Investment Transferred to Hedge Fund
|
|
74
|
+
HFREDEMPTION = "HFR" # Redemption from Hedge Fund
|
|
75
|
+
INTERNAL = "I" # Internal Transfer
|
|
76
|
+
AFFILIATE = "IA" # This transaction was executed against an IB affiliate
|
|
77
|
+
INVESTOR = "INV" # Investment Transfer from Investor
|
|
78
|
+
MARGINLOW = "L" # Ordered by IB (Margin Violation)
|
|
79
|
+
WASHSALE = "LD" # Adjusted by Loss Disallowed from Wash Sale
|
|
80
|
+
LIFO = "LI" # Last In, First Out (LIFO) tax lot-matching method
|
|
81
|
+
LTCG = "LT" # Long-term P/L
|
|
82
|
+
LOAN = "Lo" # Direct Loan
|
|
83
|
+
MANUAL = "M" # Entered manually by IB
|
|
84
|
+
MANUALEXERCISE = "MEx" # Manual exercise for dividend-related recommendation
|
|
85
|
+
MAXLOSS = "ML" # Maximize Losses tax basis election
|
|
86
|
+
MAXLTCG = "MLG" # Maximize Long-Term Gain tax lot-matching method
|
|
87
|
+
MINLTCG = "MLL" # Maximize Long-Term Loss tax lot-matching method
|
|
88
|
+
MAXSTCG = "MSG" # Maximize Short-Term Gain tax lot-matching method
|
|
89
|
+
MINSTCG = "MSL" # Maximize Short-Term Loss tax lot-matching method
|
|
90
|
+
OPENING = "O" # Opening Trade
|
|
91
|
+
PARTIAL = "P" # Partial Execution
|
|
92
|
+
FRACRISKLESSPRINCIPAL = "RP" # IB acted as riskless principal for the fractional share portion of this trade
|
|
93
|
+
FRACPRINCIPAL = "FP" # IB acted as principal for the fractional share portion of this trade
|
|
94
|
+
PRICEIMPROVEMENT = "PI" # Price Improvement
|
|
95
|
+
POSTACCRUAL = "Po" # Interest or Dividend Accrual Posting
|
|
96
|
+
PRINCIPAL = "Pr" # Part or all of this transaction was executed by the Exchange as a Crossing by IB against an IB affiliate and is therefore classified as a Principal and not an agency trade
|
|
97
|
+
REINVESTMENT = "R" # Dividend Reinvestment
|
|
98
|
+
REDEMPTION = "RED" # Redemption to Investor
|
|
99
|
+
REVERSE = "Re" # Interest or Dividend Accrual Reversal
|
|
100
|
+
REIMBURSEMENT = "RI" # Reimbursement
|
|
101
|
+
SOLICITEDIB = "SI" # This order was solicited by Interactive Brokers
|
|
102
|
+
SPECIFICLOT = "SL" # Specific Lot tax lot-matching method
|
|
103
|
+
SOLICITEDOTHER = "SO" # This order was marked as solicited by your Introducing Broker
|
|
104
|
+
SHORTENEDSETTLEMENT = "SS" # Customer designated this trade for shortened settlement and so is subject to execution at prices above the prevailing market
|
|
105
|
+
STCG = "ST" # Short-term P/L
|
|
106
|
+
STOCKYIELD = "SY" # Positions that may be eligible for Stock Yield.
|
|
107
|
+
TRANSFER = "T" # Transfer
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@enum.unique
|
|
111
|
+
class AssetClass(str, enum.Enum):
|
|
112
|
+
CASH = "CASH"
|
|
113
|
+
BILL = "BILL"
|
|
114
|
+
BOND = "BOND"
|
|
115
|
+
STOCK = "STK"
|
|
116
|
+
OPTION = "OPT"
|
|
117
|
+
WARRANT = "WAR"
|
|
118
|
+
FUTURE = "FUT"
|
|
119
|
+
FUTUREOPTION = "FOP"
|
|
120
|
+
CFD = "CFD"
|
|
121
|
+
FOREXCFD = "FXCFD"
|
|
122
|
+
CRYPTOCURRENCY = "CRYPTO"
|
|
123
|
+
STRUCTUREDPRODUCTS = "IOPT"
|
|
124
|
+
METALS = "CMDTY"
|
|
125
|
+
OPTIONSONFUTURES = "FSFOP"
|
|
126
|
+
OPTIONSFUTURESSTYLE = "FSOPT"
|
|
127
|
+
MUTUALFUND = "FUND"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@enum.unique
|
|
131
|
+
class TradeType(str, enum.Enum):
|
|
132
|
+
EXCHTRADE = "ExchTrade"
|
|
133
|
+
TRADECANCEL = "TradeCancel"
|
|
134
|
+
FRACSHARE = "FracShare"
|
|
135
|
+
FRACSHARECANCEL = "FracShareCancel"
|
|
136
|
+
TRADECORRECT = "TradeCorrect"
|
|
137
|
+
BOOKTRADE = "BookTrade"
|
|
138
|
+
DVPTRADE = "DvpTrade"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@enum.unique
|
|
142
|
+
class BuySell(str, enum.Enum):
|
|
143
|
+
BUY = "BUY"
|
|
144
|
+
CANCELBUY = "BUY (Ca.)"
|
|
145
|
+
SELL = "SELL"
|
|
146
|
+
CANCELSELL = "SELL (Ca.)"
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@enum.unique
|
|
150
|
+
class OpenClose(str, enum.Enum):
|
|
151
|
+
OPEN = "O"
|
|
152
|
+
CLOSE = "C"
|
|
153
|
+
OPENCLOSE = "C;O"
|
|
154
|
+
UNKNOWN = "-"
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@enum.unique
|
|
158
|
+
class OrderType(str, enum.Enum):
|
|
159
|
+
LIMIT = "LMT"
|
|
160
|
+
MARKET = "MKT"
|
|
161
|
+
STOP = "STP"
|
|
162
|
+
STOPLIMIT = "STPLMT"
|
|
163
|
+
MARKETONCLOSE = "MOC"
|
|
164
|
+
LIMITONCLOSE = "LOC"
|
|
165
|
+
# MULTIPLE is not an actual IB order type. It is a catch-all value to use when an Order has an orderType like "LMT;MKT".
|
|
166
|
+
# This way OrderType can remian a enum and not be a Tuple.
|
|
167
|
+
MULTIPLE = "MULTIPLE"
|
|
168
|
+
TRAILLMT = "TRAILLMT"
|
|
169
|
+
MIDPX = "MIDPX"
|
|
170
|
+
TRAIL = "TRAIL"
|
|
171
|
+
REL = "REL"
|
|
172
|
+
MIT = "MIT"
|
|
173
|
+
|
|
174
|
+
@enum.unique
|
|
175
|
+
class Reorg(str, enum.Enum):
|
|
176
|
+
BONDCONVERSION = "BC"
|
|
177
|
+
BONDMATURITY = "BM"
|
|
178
|
+
CONTRACTSOULTE = "CA"
|
|
179
|
+
CONTRACTCONSOLIDATION = "CC"
|
|
180
|
+
CASHDIV = "CD"
|
|
181
|
+
CHOICEDIV = "CH"
|
|
182
|
+
CONVERTIBLEISSUE = "CI"
|
|
183
|
+
CONTRACTSPINOFF = "CO"
|
|
184
|
+
COUPONPAYMENT = "CP"
|
|
185
|
+
CONTRACTSPLIT = "CS"
|
|
186
|
+
CFDTERMINATION = "CT"
|
|
187
|
+
DIVRIGHTSISSUE = "DI"
|
|
188
|
+
DELISTWORTHLESS = "DW"
|
|
189
|
+
EXPIREDIVRIGHT = "ED"
|
|
190
|
+
FEEALLOCATION = "FA"
|
|
191
|
+
FORWARDSPLITISSUE = "FI"
|
|
192
|
+
FORWARDSPLIT = "FS"
|
|
193
|
+
GENERICVOLUNTARY = "GV"
|
|
194
|
+
CHOICEDIVDELIVERY = "HD"
|
|
195
|
+
CHOICEDIVISSUE = "HI"
|
|
196
|
+
ISSUECHANGE = "IC"
|
|
197
|
+
ASSETPURCHASE = "OR"
|
|
198
|
+
PURCHASEISSUE = "PI"
|
|
199
|
+
PROXYVOTE = "PV"
|
|
200
|
+
RIGHTSISSUE = "RI"
|
|
201
|
+
REVERSESPLIT = "RS"
|
|
202
|
+
STOCKDIV = "SD"
|
|
203
|
+
SPINOFF = "SO"
|
|
204
|
+
SUBSCRIBERIGHTS = "SR"
|
|
205
|
+
MERGER = "TC"
|
|
206
|
+
TENDERISSUE = "TI"
|
|
207
|
+
TENDER = "TO"
|
|
208
|
+
TBILLMATURITY = "TM"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@enum.unique
|
|
212
|
+
class OptionAction(str, enum.Enum):
|
|
213
|
+
ASSIGN = "Assignment"
|
|
214
|
+
EXERCISE = "Exercise"
|
|
215
|
+
EXPIRE = "Expiration"
|
|
216
|
+
SELL = "Sell"
|
|
217
|
+
BUY = "Buy"
|
|
218
|
+
CASHSETTLEMENT = "Cash Settlement"
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
@enum.unique
|
|
222
|
+
class LongShort(str, enum.Enum):
|
|
223
|
+
LONG = "Long"
|
|
224
|
+
SHORT = "Short"
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@enum.unique
|
|
228
|
+
class ToFrom(str, enum.Enum):
|
|
229
|
+
TO = "To"
|
|
230
|
+
FROM = "From"
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@enum.unique
|
|
234
|
+
class TransferType(str, enum.Enum):
|
|
235
|
+
INTERNAL = "INTERNAL"
|
|
236
|
+
ACATS = "ACATS"
|
|
237
|
+
ATON = "ATON"
|
|
238
|
+
FOP = "FOP"
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@enum.unique
|
|
242
|
+
class InOut(str, enum.Enum):
|
|
243
|
+
IN = "IN"
|
|
244
|
+
OUT = "OUT"
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@enum.unique
|
|
248
|
+
class DeliveredReceived(str, enum.Enum):
|
|
249
|
+
DELIVERED = "Delivered"
|
|
250
|
+
RECEIVED = "Received"
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@enum.unique
|
|
254
|
+
class PutCall(str, enum.Enum):
|
|
255
|
+
PUT = "P"
|
|
256
|
+
CALL = "C"
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
ENUMS = [
|
|
260
|
+
CashAction,
|
|
261
|
+
Code,
|
|
262
|
+
AssetClass,
|
|
263
|
+
TradeType,
|
|
264
|
+
BuySell,
|
|
265
|
+
OpenClose,
|
|
266
|
+
OrderType,
|
|
267
|
+
Reorg,
|
|
268
|
+
OptionAction,
|
|
269
|
+
LongShort,
|
|
270
|
+
ToFrom,
|
|
271
|
+
TransferType,
|
|
272
|
+
InOut,
|
|
273
|
+
DeliveredReceived,
|
|
274
|
+
PutCall,
|
|
275
|
+
]
|
|
276
|
+
"""Used by ibflex.parser.ATTRIB_CONVERTERS"""
|
|
277
|
+
|
|
278
|
+
EnumType = typing.Union[
|
|
279
|
+
typing.Optional[CashAction],
|
|
280
|
+
typing.Optional[Code],
|
|
281
|
+
typing.Optional[AssetClass],
|
|
282
|
+
typing.Optional[TradeType],
|
|
283
|
+
typing.Optional[BuySell],
|
|
284
|
+
typing.Optional[OpenClose],
|
|
285
|
+
typing.Optional[OrderType],
|
|
286
|
+
typing.Optional[Reorg],
|
|
287
|
+
typing.Optional[OptionAction],
|
|
288
|
+
typing.Optional[LongShort],
|
|
289
|
+
typing.Optional[ToFrom],
|
|
290
|
+
typing.Optional[TransferType],
|
|
291
|
+
typing.Optional[InOut],
|
|
292
|
+
typing.Optional[DeliveredReceived],
|
|
293
|
+
typing.Optional[PutCall],
|
|
294
|
+
]
|
|
295
|
+
"""Used by ibflex.parser.DataType"""
|