firstrade 0.0.21__py3-none-any.whl → 0.0.30__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.
- firstrade/account.py +279 -164
- firstrade/exceptions.py +44 -0
- firstrade/order.py +167 -190
- firstrade/symbols.py +146 -51
- firstrade/urls.py +54 -24
- firstrade-0.0.30.dist-info/METADATA +225 -0
- firstrade-0.0.30.dist-info/RECORD +11 -0
- {firstrade-0.0.21.dist-info → firstrade-0.0.30.dist-info}/WHEEL +1 -1
- firstrade-0.0.21.dist-info/METADATA +0 -81
- firstrade-0.0.21.dist-info/RECORD +0 -10
- {firstrade-0.0.21.dist-info → firstrade-0.0.30.dist-info}/LICENSE +0 -0
- {firstrade-0.0.21.dist-info → firstrade-0.0.30.dist-info}/top_level.txt +0 -0
firstrade/order.py
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
-
from bs4 import BeautifulSoup
|
|
4
|
-
|
|
5
3
|
from firstrade import urls
|
|
6
4
|
from firstrade.account import FTSession
|
|
7
5
|
|
|
8
6
|
|
|
9
7
|
class PriceType(str, Enum):
|
|
10
8
|
"""
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
Enum for valid price types in an order.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
MARKET (str): Market order, executed at the current market price.
|
|
13
|
+
LIMIT (str): Limit order, executed at a specified price or better.
|
|
14
|
+
STOP (str): Stop order, becomes a market order once a specified price is reached.
|
|
15
|
+
STOP_LIMIT (str): Stop-limit order, becomes a limit order once a specified price is reached.
|
|
16
|
+
TRAILING_STOP_DOLLAR (str): Trailing stop order with a specified dollar amount.
|
|
17
|
+
TRAILING_STOP_PERCENT (str): Trailing stop order with a specified percentage.
|
|
13
18
|
"""
|
|
14
19
|
|
|
15
20
|
LIMIT = "2"
|
|
@@ -22,8 +27,14 @@ class PriceType(str, Enum):
|
|
|
22
27
|
|
|
23
28
|
class Duration(str, Enum):
|
|
24
29
|
"""
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
Enum for valid order durations.
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
DAY (str): Day order.
|
|
34
|
+
GT90 (str): Good till 90 days order.
|
|
35
|
+
PRE_MARKET (str): Pre-market order.
|
|
36
|
+
AFTER_MARKET (str): After-market order.
|
|
37
|
+
DAY_EXT (str): Day extended order.
|
|
27
38
|
"""
|
|
28
39
|
|
|
29
40
|
DAY = "0"
|
|
@@ -35,20 +46,33 @@ class Duration(str, Enum):
|
|
|
35
46
|
|
|
36
47
|
class OrderType(str, Enum):
|
|
37
48
|
"""
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
Enum for valid order types.
|
|
50
|
+
|
|
51
|
+
Attributes:
|
|
52
|
+
BUY (str): Buy order.
|
|
53
|
+
SELL (str): Sell order.
|
|
54
|
+
SELL_SHORT (str): Sell short order.
|
|
55
|
+
BUY_TO_COVER (str): Buy to cover order.
|
|
56
|
+
BUY_OPTION (str): Buy option order.
|
|
57
|
+
SELL_OPTION (str): Sell option order.
|
|
40
58
|
"""
|
|
41
59
|
|
|
42
60
|
BUY = "B"
|
|
43
61
|
SELL = "S"
|
|
44
62
|
SELL_SHORT = "SS"
|
|
45
63
|
BUY_TO_COVER = "BC"
|
|
64
|
+
BUY_OPTION = "BO"
|
|
65
|
+
SELL_OPTION = "SO"
|
|
46
66
|
|
|
47
67
|
|
|
48
68
|
class OrderInstructions(str, Enum):
|
|
49
69
|
"""
|
|
50
|
-
|
|
51
|
-
|
|
70
|
+
Enum for valid order instructions.
|
|
71
|
+
|
|
72
|
+
Attributes:
|
|
73
|
+
AON (str): All or none.
|
|
74
|
+
OPG (str): At the Open.
|
|
75
|
+
CLO (str): At the Close.
|
|
52
76
|
"""
|
|
53
77
|
|
|
54
78
|
AON = "1"
|
|
@@ -56,215 +80,168 @@ class OrderInstructions(str, Enum):
|
|
|
56
80
|
CLO = "5"
|
|
57
81
|
|
|
58
82
|
|
|
83
|
+
class OptionType(str, Enum):
|
|
84
|
+
"""
|
|
85
|
+
Enum for valid option types.
|
|
86
|
+
|
|
87
|
+
Attributes:
|
|
88
|
+
CALL (str): Call option.
|
|
89
|
+
PUT (str): Put option.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
CALL = "C"
|
|
93
|
+
PUT = "P"
|
|
94
|
+
|
|
95
|
+
|
|
59
96
|
class Order:
|
|
60
97
|
"""
|
|
61
|
-
|
|
62
|
-
|
|
98
|
+
Represents an order with methods to place it.
|
|
99
|
+
|
|
100
|
+
Attributes:
|
|
101
|
+
ft_session (FTSession): The session object for placing orders.
|
|
63
102
|
"""
|
|
64
103
|
|
|
65
104
|
def __init__(self, ft_session: FTSession):
|
|
66
105
|
self.ft_session = ft_session
|
|
67
|
-
self.order_confirmation = {}
|
|
68
106
|
|
|
69
107
|
def place_order(
|
|
70
108
|
self,
|
|
71
|
-
account,
|
|
72
|
-
symbol,
|
|
109
|
+
account: str,
|
|
110
|
+
symbol: str,
|
|
73
111
|
price_type: PriceType,
|
|
74
112
|
order_type: OrderType,
|
|
75
|
-
quantity,
|
|
76
113
|
duration: Duration,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
114
|
+
quantity: int = 0,
|
|
115
|
+
price: float = 0.00,
|
|
116
|
+
stop_price: float = None,
|
|
117
|
+
dry_run: bool = True,
|
|
118
|
+
notional: bool = False,
|
|
119
|
+
order_instruction: OrderInstructions = "0",
|
|
81
120
|
):
|
|
82
121
|
"""
|
|
83
122
|
Builds and places an order.
|
|
84
|
-
:attr: 'order_confirmation`
|
|
85
|
-
contains the order confirmation data after order placement.
|
|
86
123
|
|
|
87
124
|
Args:
|
|
88
|
-
account (str):
|
|
89
|
-
symbol (str):
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
duration (Duration):
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
125
|
+
account (str): The account number to place the order in.
|
|
126
|
+
symbol (str): The ticker symbol for the order.
|
|
127
|
+
price_type (PriceType): The price type for the order (e.g., LIMIT, MARKET, STOP).
|
|
128
|
+
order_type (OrderType): The type of order (e.g., BUY, SELL).
|
|
129
|
+
duration (Duration): The duration of the order (e.g., DAY, GT90).
|
|
130
|
+
quantity (int, optional): The number of shares to buy or sell. Defaults to 0.
|
|
131
|
+
price (float, optional): The price at which to buy or sell the shares. Defaults to 0.00.
|
|
132
|
+
stop_price (float, optional): The stop price for stop orders. Defaults to None.
|
|
133
|
+
dry_run (bool, optional): If True, the order will not be placed but will be built and validated. Defaults to True.
|
|
134
|
+
notional (bool, optional): If True, the order will be placed based on a notional dollar amount rather than share quantity. Defaults to False.
|
|
135
|
+
order_instruction (OrderInstructions, optional): Additional order instructions (e.g., AON, OPG). Defaults to "0".
|
|
136
|
+
|
|
137
|
+
Raises:
|
|
138
|
+
ValueError: If AON orders are not limit orders or if AON orders have a quantity of 100 shares or less.
|
|
139
|
+
PreviewOrderError: If the order preview fails.
|
|
140
|
+
PlaceOrderError: If the order placement fails.
|
|
96
141
|
|
|
97
142
|
Returns:
|
|
98
|
-
|
|
143
|
+
dict: A dictionary containing the order confirmation data.
|
|
99
144
|
"""
|
|
100
145
|
|
|
101
|
-
if price_type == PriceType.MARKET:
|
|
146
|
+
if price_type == PriceType.MARKET and not notional:
|
|
102
147
|
price = ""
|
|
103
148
|
if order_instruction == OrderInstructions.AON and price_type != PriceType.LIMIT:
|
|
104
149
|
raise ValueError("AON orders must be a limit order.")
|
|
105
150
|
if order_instruction == OrderInstructions.AON and quantity <= 100:
|
|
106
151
|
raise ValueError("AON orders must be greater than 100 shares.")
|
|
107
|
-
|
|
152
|
+
|
|
108
153
|
data = {
|
|
109
|
-
"submiturl": "/cgi-bin/orderbar",
|
|
110
|
-
"orderbar_clordid": "",
|
|
111
|
-
"orderbar_accountid": "",
|
|
112
|
-
"notional": "yes" if notional else "",
|
|
113
|
-
"stockorderpage": "yes",
|
|
114
|
-
"submitOrders": "",
|
|
115
|
-
"previewOrders": "1",
|
|
116
|
-
"lotMethod": "1",
|
|
117
|
-
"accountType": "1",
|
|
118
|
-
"quoteprice": "",
|
|
119
|
-
"viewederror": "",
|
|
120
|
-
"stocksubmittedcompanyname1": "",
|
|
121
|
-
"accountId": account,
|
|
122
|
-
"transactionType": order_type,
|
|
123
|
-
"quantity": quantity,
|
|
124
154
|
"symbol": symbol,
|
|
125
|
-
"
|
|
126
|
-
"
|
|
155
|
+
"transaction": order_type,
|
|
156
|
+
"shares": quantity,
|
|
127
157
|
"duration": duration,
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"cond_and_or0": "1",
|
|
134
|
-
"cond_symbol0_1": "",
|
|
135
|
-
"cond_type0_1": "2",
|
|
136
|
-
"cond_compare_type0_1": "2",
|
|
137
|
-
"cond_compare_value0_1": "",
|
|
158
|
+
"preview": "true",
|
|
159
|
+
"instructions": order_instruction,
|
|
160
|
+
"account": account,
|
|
161
|
+
"price_type": price_type,
|
|
162
|
+
"limit_price": "0",
|
|
138
163
|
}
|
|
164
|
+
if notional:
|
|
165
|
+
data["dollar_amount"] = price
|
|
166
|
+
del data["shares"]
|
|
167
|
+
if price_type in [PriceType.LIMIT, PriceType.STOP_LIMIT]:
|
|
168
|
+
data["limit_price"] = price
|
|
169
|
+
if price_type in [PriceType.STOP, PriceType.STOP_LIMIT]:
|
|
170
|
+
data["stop_price"] = stop_price
|
|
171
|
+
response = self.ft_session.post(url=urls.order(), data=data)
|
|
172
|
+
if response.status_code != 200 or response.json()["error"] != "":
|
|
173
|
+
return response.json()
|
|
174
|
+
preview_data = response.json()
|
|
175
|
+
if dry_run:
|
|
176
|
+
return preview_data
|
|
177
|
+
data["preview"] = "false"
|
|
178
|
+
data["stage"] = "P"
|
|
179
|
+
response = self.ft_session.post(url=urls.order(), data=data)
|
|
180
|
+
return response.json()
|
|
181
|
+
|
|
182
|
+
def place_option_order(
|
|
183
|
+
self,
|
|
184
|
+
account: str,
|
|
185
|
+
option_symbol: str,
|
|
186
|
+
price_type: PriceType,
|
|
187
|
+
order_type: OrderType,
|
|
188
|
+
contracts: int,
|
|
189
|
+
duration: Duration,
|
|
190
|
+
stop_price: float = None,
|
|
191
|
+
price: float = 0.00,
|
|
192
|
+
dry_run: bool = True,
|
|
193
|
+
order_instruction: OrderInstructions = "0",
|
|
194
|
+
):
|
|
195
|
+
"""
|
|
196
|
+
Builds and places an option order.
|
|
139
197
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
).
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
.
|
|
154
|
-
.
|
|
155
|
-
.
|
|
156
|
-
)
|
|
157
|
-
if span:
|
|
158
|
-
order_warning = span.text.strip()
|
|
159
|
-
order_confirmation["warning"] = order_warning
|
|
160
|
-
data["viewederror"] = "1"
|
|
161
|
-
if not dry_run:
|
|
162
|
-
data["previewOrders"] = ""
|
|
163
|
-
data["submitOrders"] = "1"
|
|
164
|
-
order_data = BeautifulSoup(
|
|
165
|
-
self.ft_session.post(
|
|
166
|
-
url=urls.orderbar(), headers=urls.session_headers(), data=data
|
|
167
|
-
).text,
|
|
168
|
-
"xml",
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
order_success = order_data.find("success").text.strip()
|
|
172
|
-
order_confirmation["success"] = order_success
|
|
173
|
-
action_data = order_data.find("actiondata").text.strip()
|
|
174
|
-
if order_success != "No":
|
|
175
|
-
# Extract the table data
|
|
176
|
-
table_start = action_data.find("<table")
|
|
177
|
-
table_end = action_data.find("</table>") + len("</table>")
|
|
178
|
-
table_data = action_data[table_start:table_end]
|
|
179
|
-
table_data = BeautifulSoup(table_data, "xml")
|
|
180
|
-
titles = table_data.find_all("th")
|
|
181
|
-
data = table_data.find_all("td")
|
|
182
|
-
for i, title in enumerate(titles):
|
|
183
|
-
order_confirmation[f"{title.get_text()}"] = data[i].get_text()
|
|
184
|
-
if not dry_run:
|
|
185
|
-
start_index = action_data.find(
|
|
186
|
-
"Your order reference number is: "
|
|
187
|
-
) + len("Your order reference number is: ")
|
|
188
|
-
end_index = action_data.find("</div>", start_index)
|
|
189
|
-
order_number = action_data[start_index:end_index]
|
|
190
|
-
else:
|
|
191
|
-
start_index = action_data.find('id="') + len('id="')
|
|
192
|
-
end_index = action_data.find('" style=', start_index)
|
|
193
|
-
order_number = action_data[start_index:end_index]
|
|
194
|
-
order_confirmation["orderid"] = order_number
|
|
195
|
-
else:
|
|
196
|
-
order_confirmation["actiondata"] = action_data
|
|
197
|
-
order_confirmation["errcode"] = order_data.find("errcode").text.strip()
|
|
198
|
-
self.order_confirmation = order_confirmation
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def get_orders(ft_session, account):
|
|
202
|
-
"""
|
|
203
|
-
Retrieves existing order data for a given account.
|
|
204
|
-
|
|
205
|
-
Args:
|
|
206
|
-
ft_session (FTSession): The session object used for making HTTP requests to Firstrade.
|
|
207
|
-
account (str): Account number of the account to retrieve orders for.
|
|
208
|
-
|
|
209
|
-
Returns:
|
|
210
|
-
list: A list of dictionaries, each containing details about an order.
|
|
211
|
-
"""
|
|
198
|
+
Args:
|
|
199
|
+
account (str): The account number to place the order in.
|
|
200
|
+
option_symbol (str): The option ticker symbol for the order.
|
|
201
|
+
price_type (PriceType): The price type for the order (e.g., LIMIT, MARKET, STOP).
|
|
202
|
+
order_type (OrderType): The type of order (e.g., BUY, SELL).
|
|
203
|
+
contracts (int): The number of option contracts to buy or sell.
|
|
204
|
+
duration (Duration): The duration of the order (e.g., DAY, GT90).
|
|
205
|
+
stop_price (float, optional): The stop price for stop orders. Defaults to None.
|
|
206
|
+
price (float, optional): The price at which to buy or sell the option contracts. Defaults to 0.00.
|
|
207
|
+
dry_run (bool, optional): If True, the order will not be placed but will be built and validated. Defaults to True.
|
|
208
|
+
order_instruction (OrderInstructions, optional): Additional order instructions (e.g., AON, OPG). Defaults to "0".
|
|
209
|
+
|
|
210
|
+
Raises:
|
|
211
|
+
ValueError: If AON orders are not limit orders or if AON orders have a quantity of 100 contracts or less.
|
|
212
|
+
PreviewOrderError: If there is an error during the preview of the order.
|
|
213
|
+
PlaceOrderError: If there is an error during the placement of the order.
|
|
212
214
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
"
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
# print(sub_status)
|
|
247
|
-
sub_status = sub_status.get_text(strip=True)
|
|
248
|
-
# print(sub_status)
|
|
249
|
-
status = (
|
|
250
|
-
status.find("strong").get_text(strip=True)
|
|
251
|
-
if status.find("strong")
|
|
252
|
-
else status.get_text(strip=True)
|
|
253
|
-
)
|
|
254
|
-
order = {
|
|
255
|
-
"Date/Time": cells[0].get_text(strip=True),
|
|
256
|
-
"Reference": order_ref_number,
|
|
257
|
-
"Transaction": cells[1].get_text(strip=True),
|
|
258
|
-
"Quantity": int(cells[2].get_text(strip=True)),
|
|
259
|
-
"Symbol": cells[3].get_text(strip=True),
|
|
260
|
-
"Type": cells[4].get_text(strip=True),
|
|
261
|
-
"Price": float(cells[5].get_text(strip=True)),
|
|
262
|
-
"Duration": cells[6].get_text(strip=True),
|
|
263
|
-
"Instr.": cells[7].get_text(strip=True),
|
|
264
|
-
"Status": status,
|
|
265
|
-
}
|
|
266
|
-
orders.append(order)
|
|
267
|
-
except Exception as e:
|
|
268
|
-
print(f"Error parsing order: {e}")
|
|
269
|
-
|
|
270
|
-
return orders
|
|
215
|
+
Returns:
|
|
216
|
+
dict: A dictionary containing the order confirmation data.
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
if order_instruction == OrderInstructions.AON and price_type != PriceType.LIMIT:
|
|
220
|
+
raise ValueError("AON orders must be a limit order.")
|
|
221
|
+
if order_instruction == OrderInstructions.AON and contracts <= 100:
|
|
222
|
+
raise ValueError("AON orders must be greater than 100 shares.")
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
data = {
|
|
226
|
+
"duration": duration,
|
|
227
|
+
"instructions": order_instruction,
|
|
228
|
+
"transaction": order_type,
|
|
229
|
+
"contracts": contracts,
|
|
230
|
+
"symbol": option_symbol,
|
|
231
|
+
"preview": "true",
|
|
232
|
+
"account": account,
|
|
233
|
+
"price_type": price_type,
|
|
234
|
+
}
|
|
235
|
+
if price_type in [PriceType.LIMIT, PriceType.STOP_LIMIT]:
|
|
236
|
+
data["limit_price"] = price
|
|
237
|
+
if price_type in [PriceType.STOP, PriceType.STOP_LIMIT]:
|
|
238
|
+
data["stop_price"] = stop_price
|
|
239
|
+
|
|
240
|
+
response = self.ft_session.post(url=urls.option_order(), data=data)
|
|
241
|
+
if response.status_code != 200 or response.json()["error"] != "":
|
|
242
|
+
return response.json()
|
|
243
|
+
if dry_run:
|
|
244
|
+
return response.json()
|
|
245
|
+
data["preview"] = "false"
|
|
246
|
+
response = self.ft_session.post(url=urls.option_order(), data=data)
|
|
247
|
+
return response.json()
|
firstrade/symbols.py
CHANGED
|
@@ -1,77 +1,172 @@
|
|
|
1
|
-
from bs4 import BeautifulSoup
|
|
2
|
-
|
|
3
1
|
from firstrade import urls
|
|
4
2
|
from firstrade.account import FTSession
|
|
3
|
+
from firstrade.exceptions import QuoteRequestError, QuoteResponseError
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
class SymbolQuote:
|
|
8
7
|
"""
|
|
9
|
-
|
|
8
|
+
Data class representing a stock quote for a given symbol.
|
|
10
9
|
|
|
11
10
|
Attributes:
|
|
12
|
-
ft_session (FTSession):
|
|
13
|
-
The session object used for making HTTP requests to Firstrade.
|
|
11
|
+
ft_session (FTSession): The session object used for making HTTP requests to Firstrade.
|
|
14
12
|
symbol (str): The symbol for which the quote information is retrieved.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
sec_type (str): The security type of the symbol.
|
|
14
|
+
tick (str): The tick size of the symbol.
|
|
15
|
+
bid (int): The bid price for the symbol.
|
|
16
|
+
bid_size (int): The size of the bid.
|
|
17
|
+
ask (int): The ask price for the symbol.
|
|
18
|
+
ask_size (int): The size of the ask.
|
|
18
19
|
last (float): The last traded price for the symbol.
|
|
19
20
|
change (float): The change in price for the symbol.
|
|
20
21
|
high (float): The highest price for the symbol during the trading day.
|
|
21
22
|
low (float): The lowest price for the symbol during the trading day.
|
|
23
|
+
bid_mmid (str): The market maker ID for the bid.
|
|
24
|
+
ask_mmid (str): The market maker ID for the ask.
|
|
25
|
+
last_mmid (str): The market maker ID for the last trade.
|
|
26
|
+
last_size (int): The size of the last trade.
|
|
27
|
+
change_color (str): The color indicating the change in price.
|
|
22
28
|
volume (str): The volume of shares traded for the symbol.
|
|
29
|
+
today_close (float): The closing price for the symbol today.
|
|
30
|
+
open (str): The opening price for the symbol.
|
|
31
|
+
quote_time (str): The time of the quote.
|
|
32
|
+
last_trade_time (str): The time of the last trade.
|
|
23
33
|
company_name (str): The name of the company associated with the symbol.
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
exchange (str): The exchange where the symbol is traded.
|
|
35
|
+
has_option (bool): Indicates if the symbol has options.
|
|
36
|
+
is_etf (bool): Indicates if the symbol is an ETF.
|
|
37
|
+
is_fractional (bool): Indicates if the stock can be traded fractionally.
|
|
38
|
+
realtime (str): Indicates if the quote is real-time.
|
|
39
|
+
nls (str): Nasdaq last sale.
|
|
40
|
+
shares (int): The number of shares.
|
|
26
41
|
"""
|
|
27
42
|
|
|
28
|
-
def __init__(self, ft_session: FTSession, symbol: str):
|
|
43
|
+
def __init__(self, ft_session: FTSession, account: str, symbol: str):
|
|
29
44
|
"""
|
|
30
45
|
Initializes a new instance of the SymbolQuote class.
|
|
31
46
|
|
|
47
|
+
Args:
|
|
48
|
+
ft_session (FTSession): The session object used for making HTTP requests to Firstrade.
|
|
49
|
+
account (str): The account number for which the quote information is retrieved.
|
|
50
|
+
symbol (str): The symbol for which the quote information is retrieved.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
QuoteRequestError: If the quote request fails with a non-200 status code.
|
|
54
|
+
QuoteResponseError: If the quote response contains an error message.
|
|
55
|
+
"""
|
|
56
|
+
self.ft_session = ft_session
|
|
57
|
+
response = self.ft_session.get(url=urls.quote(account, symbol))
|
|
58
|
+
if response.status_code != 200:
|
|
59
|
+
raise QuoteRequestError(response.status_code)
|
|
60
|
+
if response.json().get("error", "") != "":
|
|
61
|
+
raise QuoteResponseError(symbol, response.json()["error"])
|
|
62
|
+
self.symbol = response.json()["result"]["symbol"]
|
|
63
|
+
self.sec_type = response.json()["result"]["sec_type"]
|
|
64
|
+
self.tick = response.json()["result"]["tick"]
|
|
65
|
+
self.bid = response.json()["result"]["bid"]
|
|
66
|
+
self.bid_size = response.json()["result"]["bid_size"]
|
|
67
|
+
self.ask = response.json()["result"]["ask"]
|
|
68
|
+
self.ask_size = response.json()["result"]["ask_size"]
|
|
69
|
+
self.last = response.json()["result"]["last"]
|
|
70
|
+
self.change = response.json()["result"]["change"]
|
|
71
|
+
self.high = response.json()["result"]["high"]
|
|
72
|
+
self.low = response.json()["result"]["low"]
|
|
73
|
+
self.bid_mmid = response.json()["result"]["bid_mmid:"]
|
|
74
|
+
self.ask_mmid = response.json()["result"]["ask_mmid:"]
|
|
75
|
+
self.last_mmid = response.json()["result"]["last_mmid:"]
|
|
76
|
+
self.last_size = response.json()["result"]["last_size"]
|
|
77
|
+
self.change_color = response.json()["result"]["change_color"]
|
|
78
|
+
self.volume = response.json()["result"]["vol"]
|
|
79
|
+
self.today_close = response.json()["result"]["today_close"]
|
|
80
|
+
self.open = response.json()["result"]["open"]
|
|
81
|
+
self.quote_time = response.json()["result"]["quote_time"]
|
|
82
|
+
self.last_trade_time = response.json()["result"]["last_trade_time"]
|
|
83
|
+
self.company_name = response.json()["result"]["company_name"]
|
|
84
|
+
self.exchange = response.json()["result"]["exchange"]
|
|
85
|
+
self.has_option = response.json()["result"]["has_option"]
|
|
86
|
+
self.is_etf = bool(response.json()["result"]["is_etf"])
|
|
87
|
+
self.is_fractional = bool(response.json()["result"]["is_fractional"])
|
|
88
|
+
self.realtime = response.json()["result"]["realtime"]
|
|
89
|
+
self.nls = response.json()["result"]["nls"]
|
|
90
|
+
self.shares = response.json()["result"]["shares"]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class OptionQuote:
|
|
94
|
+
"""
|
|
95
|
+
Data class representing an option quote for a given symbol.
|
|
96
|
+
|
|
97
|
+
Attributes:
|
|
98
|
+
ft_session (FTSession): The session object used for making HTTP requests to Firstrade.
|
|
99
|
+
symbol (str): The symbol for which the option quote information is retrieved.
|
|
100
|
+
option_dates (dict): A dict of expiration dates for options on the given symbol.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
def __init__(self, ft_session: FTSession, symbol: str):
|
|
104
|
+
"""
|
|
105
|
+
Initializes a new instance of the OptionQuote class.
|
|
106
|
+
|
|
32
107
|
Args:
|
|
33
108
|
ft_session (FTSession):
|
|
34
109
|
The session object used for making HTTP requests to Firstrade.
|
|
35
|
-
symbol (str): The symbol for which the quote information is retrieved.
|
|
110
|
+
symbol (str): The symbol for which the option quote information is retrieved.
|
|
36
111
|
"""
|
|
37
112
|
self.ft_session = ft_session
|
|
38
113
|
self.symbol = symbol
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
114
|
+
self.option_dates = self.get_option_dates(symbol)
|
|
115
|
+
|
|
116
|
+
def get_option_dates(self, symbol: str):
|
|
117
|
+
"""
|
|
118
|
+
Retrieves the expiration dates for options on a given symbol.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
symbol (str): The symbol for which the expiration dates are retrieved.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
dict: A dict of expiration dates and other information for options on the given symbol.
|
|
125
|
+
|
|
126
|
+
Raises:
|
|
127
|
+
QuoteRequestError: If the request for option dates fails with a non-200 status code.
|
|
128
|
+
QuoteResponseError: If the response for option dates contains an error message.
|
|
129
|
+
"""
|
|
130
|
+
response = self.ft_session.get(url=urls.option_dates(symbol))
|
|
131
|
+
return response.json()
|
|
132
|
+
|
|
133
|
+
def get_option_quote(self, symbol: str, date: str):
|
|
134
|
+
"""
|
|
135
|
+
Retrieves the quote for a given option symbol.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
symbol (str): The symbol for which the quote is retrieved.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
dict: A dictionary containing the quote and other information for the given option symbol.
|
|
142
|
+
|
|
143
|
+
Raises:
|
|
144
|
+
QuoteRequestError: If the request for the option quote fails with a non-200 status code.
|
|
145
|
+
QuoteResponseError: If the response for the option quote contains an error message.
|
|
146
|
+
"""
|
|
147
|
+
response = self.ft_session.get(url=urls.option_quotes(symbol, date))
|
|
148
|
+
return response.json()
|
|
149
|
+
|
|
150
|
+
def get_greek_options(self, symbol: str, exp_date: str):
|
|
151
|
+
"""
|
|
152
|
+
Retrieves the greeks for options on a given symbol.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
symbol (str): The symbol for which the greeks are retrieved.
|
|
156
|
+
exp_date (str): The expiration date of the options.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
dict: A dictionary containing the greeks for the options on the given symbol.
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
QuoteRequestError: If the request for the greeks fails with a non-200 status code.
|
|
163
|
+
QuoteResponseError: If the response for the greeks contains an error message.
|
|
164
|
+
"""
|
|
165
|
+
data = {
|
|
166
|
+
"type": "chain",
|
|
167
|
+
"chains_range": "A",
|
|
168
|
+
"root_symbol": symbol,
|
|
169
|
+
"exp_date": exp_date,
|
|
170
|
+
}
|
|
171
|
+
response = self.ft_session.post(url=urls.greek_options(), data=data)
|
|
172
|
+
return response.json()
|