firstrade 0.0.19__tar.gz → 0.0.21__tar.gz
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-0.0.19 → firstrade-0.0.21}/PKG-INFO +2 -2
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade/order.py +72 -29
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade.egg-info/PKG-INFO +2 -2
- {firstrade-0.0.19 → firstrade-0.0.21}/setup.py +2 -2
- {firstrade-0.0.19 → firstrade-0.0.21}/LICENSE +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/README.md +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade/__init__.py +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade/account.py +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade/symbols.py +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade/urls.py +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade.egg-info/SOURCES.txt +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade.egg-info/dependency_links.txt +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade.egg-info/requires.txt +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/firstrade.egg-info/top_level.txt +0 -0
- {firstrade-0.0.19 → firstrade-0.0.21}/setup.cfg +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: firstrade
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.21
|
|
4
4
|
Summary: An unofficial API for Firstrade
|
|
5
5
|
Home-page: https://github.com/MaxxRK/firstrade-api
|
|
6
|
-
Download-URL: https://github.com/MaxxRK/firstrade-api/archive/refs/tags/
|
|
6
|
+
Download-URL: https://github.com/MaxxRK/firstrade-api/archive/refs/tags/0021.tar.gz
|
|
7
7
|
Author: MaxxRK
|
|
8
8
|
Author-email: maxxrk@pm.me
|
|
9
9
|
License: MIT
|
|
@@ -45,6 +45,17 @@ class OrderType(str, Enum):
|
|
|
45
45
|
BUY_TO_COVER = "BC"
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
class OrderInstructions(str, Enum):
|
|
49
|
+
"""
|
|
50
|
+
This is an :class:'~enum.Enum'
|
|
51
|
+
that contains the valid instructions for an order.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
AON = "1"
|
|
55
|
+
OPG = "4"
|
|
56
|
+
CLO = "5"
|
|
57
|
+
|
|
58
|
+
|
|
48
59
|
class Order:
|
|
49
60
|
"""
|
|
50
61
|
This class contains information about an order.
|
|
@@ -66,6 +77,7 @@ class Order:
|
|
|
66
77
|
price=0.00,
|
|
67
78
|
dry_run=True,
|
|
68
79
|
notional=False,
|
|
80
|
+
order_instruction: OrderInstructions = None,
|
|
69
81
|
):
|
|
70
82
|
"""
|
|
71
83
|
Builds and places an order.
|
|
@@ -86,13 +98,12 @@ class Order:
|
|
|
86
98
|
Order:order_confirmation: Dictionary containing the order confirmation data.
|
|
87
99
|
"""
|
|
88
100
|
|
|
89
|
-
if dry_run:
|
|
90
|
-
previewOrders = "1"
|
|
91
|
-
else:
|
|
92
|
-
previewOrders = ""
|
|
93
|
-
|
|
94
101
|
if price_type == PriceType.MARKET:
|
|
95
102
|
price = ""
|
|
103
|
+
if order_instruction == OrderInstructions.AON and price_type != PriceType.LIMIT:
|
|
104
|
+
raise ValueError("AON orders must be a limit order.")
|
|
105
|
+
if order_instruction == OrderInstructions.AON and quantity <= 100:
|
|
106
|
+
raise ValueError("AON orders must be greater than 100 shares.")
|
|
96
107
|
|
|
97
108
|
data = {
|
|
98
109
|
"submiturl": "/cgi-bin/orderbar",
|
|
@@ -100,8 +111,8 @@ class Order:
|
|
|
100
111
|
"orderbar_accountid": "",
|
|
101
112
|
"notional": "yes" if notional else "",
|
|
102
113
|
"stockorderpage": "yes",
|
|
103
|
-
"submitOrders": "
|
|
104
|
-
"previewOrders":
|
|
114
|
+
"submitOrders": "",
|
|
115
|
+
"previewOrders": "1",
|
|
105
116
|
"lotMethod": "1",
|
|
106
117
|
"accountType": "1",
|
|
107
118
|
"quoteprice": "",
|
|
@@ -114,7 +125,7 @@ class Order:
|
|
|
114
125
|
"priceType": price_type,
|
|
115
126
|
"limitPrice": price,
|
|
116
127
|
"duration": duration,
|
|
117
|
-
"qualifier": "0",
|
|
128
|
+
"qualifier": "0" if order_instruction is None else order_instruction,
|
|
118
129
|
"cond_symbol0_0": "",
|
|
119
130
|
"cond_type0_0": "2",
|
|
120
131
|
"cond_compare_type0_0": "2",
|
|
@@ -133,6 +144,30 @@ class Order:
|
|
|
133
144
|
"xml",
|
|
134
145
|
)
|
|
135
146
|
order_confirmation = {}
|
|
147
|
+
cdata = order_data.find("actiondata").string
|
|
148
|
+
cdata_soup = BeautifulSoup(cdata, "html.parser")
|
|
149
|
+
span = (
|
|
150
|
+
cdata_soup.find("div", class_="msg_bg")
|
|
151
|
+
.find("div", class_="yellow box")
|
|
152
|
+
.find("div", class_="error_msg")
|
|
153
|
+
.find("div", class_="outbox")
|
|
154
|
+
.find("div", class_="inbox")
|
|
155
|
+
.find("span")
|
|
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
|
+
|
|
136
171
|
order_success = order_data.find("success").text.strip()
|
|
137
172
|
order_confirmation["success"] = order_success
|
|
138
173
|
action_data = order_data.find("actiondata").text.strip()
|
|
@@ -177,48 +212,56 @@ def get_orders(ft_session, account):
|
|
|
177
212
|
|
|
178
213
|
# Data dictionary to send with the request
|
|
179
214
|
data = {
|
|
180
|
-
|
|
215
|
+
"accountId": account,
|
|
181
216
|
}
|
|
182
217
|
|
|
183
218
|
# Post request to retrieve the order data
|
|
184
|
-
response = ft_session.post(
|
|
219
|
+
response = ft_session.post(
|
|
220
|
+
url=urls.order_list(), headers=urls.session_headers(), data=data
|
|
221
|
+
).text
|
|
185
222
|
|
|
186
223
|
# Parse the response using BeautifulSoup
|
|
187
224
|
soup = BeautifulSoup(response, "html.parser")
|
|
188
225
|
|
|
189
226
|
# Find the table containing orders
|
|
190
|
-
table = soup.find(
|
|
227
|
+
table = soup.find("table", class_="tablesorter")
|
|
191
228
|
if not table:
|
|
192
229
|
return []
|
|
193
230
|
|
|
194
|
-
rows = table.find_all(
|
|
231
|
+
rows = table.find_all("tr")[1:] # skip the header row
|
|
195
232
|
|
|
196
233
|
orders = []
|
|
197
234
|
for row in rows:
|
|
198
235
|
try:
|
|
199
|
-
cells = row.find_all(
|
|
200
|
-
tooltip_content = row.find(
|
|
201
|
-
tooltip_soup = BeautifulSoup(
|
|
202
|
-
|
|
203
|
-
|
|
236
|
+
cells = row.find_all("td")
|
|
237
|
+
tooltip_content = row.find("a", {"class": "info"}).get("onmouseover")
|
|
238
|
+
tooltip_soup = BeautifulSoup(
|
|
239
|
+
tooltip_content.split("tooltip.show(")[1].strip("');"), "html.parser"
|
|
240
|
+
)
|
|
241
|
+
order_ref = tooltip_soup.find(text=lambda text: "Order Ref" in text)
|
|
242
|
+
order_ref_number = order_ref.split("#: ")[1] if order_ref else None
|
|
204
243
|
status = cells[8]
|
|
205
244
|
# print(status)
|
|
206
|
-
sub_status = status.find(
|
|
245
|
+
sub_status = status.find("strong")
|
|
207
246
|
# print(sub_status)
|
|
208
247
|
sub_status = sub_status.get_text(strip=True)
|
|
209
248
|
# print(sub_status)
|
|
210
|
-
status =
|
|
249
|
+
status = (
|
|
250
|
+
status.find("strong").get_text(strip=True)
|
|
251
|
+
if status.find("strong")
|
|
252
|
+
else status.get_text(strip=True)
|
|
253
|
+
)
|
|
211
254
|
order = {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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,
|
|
222
265
|
}
|
|
223
266
|
orders.append(order)
|
|
224
267
|
except Exception as e:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: firstrade
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.21
|
|
4
4
|
Summary: An unofficial API for Firstrade
|
|
5
5
|
Home-page: https://github.com/MaxxRK/firstrade-api
|
|
6
|
-
Download-URL: https://github.com/MaxxRK/firstrade-api/archive/refs/tags/
|
|
6
|
+
Download-URL: https://github.com/MaxxRK/firstrade-api/archive/refs/tags/0021.tar.gz
|
|
7
7
|
Author: MaxxRK
|
|
8
8
|
Author-email: maxxrk@pm.me
|
|
9
9
|
License: MIT
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as f:
|
|
|
5
5
|
|
|
6
6
|
setuptools.setup(
|
|
7
7
|
name="firstrade",
|
|
8
|
-
version="0.0.
|
|
8
|
+
version="0.0.21",
|
|
9
9
|
author="MaxxRK",
|
|
10
10
|
author_email="maxxrk@pm.me",
|
|
11
11
|
description="An unofficial API for Firstrade",
|
|
@@ -13,7 +13,7 @@ setuptools.setup(
|
|
|
13
13
|
long_description_content_type="text/markdown",
|
|
14
14
|
license="MIT",
|
|
15
15
|
url="https://github.com/MaxxRK/firstrade-api",
|
|
16
|
-
download_url="https://github.com/MaxxRK/firstrade-api/archive/refs/tags/
|
|
16
|
+
download_url="https://github.com/MaxxRK/firstrade-api/archive/refs/tags/0021.tar.gz",
|
|
17
17
|
keywords=["FIRSTRADE", "API"],
|
|
18
18
|
install_requires=["requests", "beautifulsoup4", "lxml"],
|
|
19
19
|
packages=["firstrade"],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|