quantplay 2.0.92__tar.gz → 2.0.94__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.
- {quantplay-2.0.92 → quantplay-2.0.94}/PKG-INFO +1 -26
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/dhan.py +13 -16
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/motilal.py +31 -16
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/noren.py +16 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/xts.py +43 -99
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/xts_utils/Connect.py +408 -266
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/wrapper/aws/s3.py +1 -6
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay.egg-info/PKG-INFO +1 -26
- {quantplay-2.0.92 → quantplay-2.0.94}/setup.py +1 -1
- {quantplay-2.0.92 → quantplay-2.0.94}/README.md +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/pyproject.toml +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/aliceblue.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/angelone.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/auto_login/aliceblue.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/broker_factory.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/five_paisa.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/ft_utils/ft_noren.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/generics/broker.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/kotak.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/uplink/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/upstox.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/xts_utils/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/broker/zerodha.py +1 -1
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/model/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/model/broker.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/model/generics.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/model/instrument_data.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/model/order_event.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/py.typed +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/utils/caching.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/utils/constant.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/wrapper/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay.egg-info/SOURCES.txt +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/setup.cfg +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/tests/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/tests/conftest.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/tests/wrapper/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.92 → quantplay-2.0.94}/tests/wrapper/aws/s3_test.py +0 -0
|
@@ -1,36 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: quantplay
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.94
|
|
4
4
|
Summary: This python package will be stored in AWS CodeArtifact
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
7
7
|
Author-email:
|
|
8
8
|
License: MIT
|
|
9
|
-
Requires-Dist: setuptools
|
|
10
|
-
Requires-Dist: path
|
|
11
|
-
Requires-Dist: pyotp
|
|
12
|
-
Requires-Dist: retrying
|
|
13
|
-
Requires-Dist: boto3
|
|
14
|
-
Requires-Dist: numpy
|
|
15
|
-
Requires-Dist: websocket-client
|
|
16
|
-
Requires-Dist: smartapi-python
|
|
17
|
-
Requires-Dist: logzero
|
|
18
|
-
Requires-Dist: selenium
|
|
19
|
-
Requires-Dist: requests
|
|
20
|
-
Requires-Dist: pandas
|
|
21
|
-
Requires-Dist: pyarrow
|
|
22
|
-
Requires-Dist: polars
|
|
23
|
-
Requires-Dist: kiteconnect
|
|
24
|
-
Requires-Dist: pya3
|
|
25
|
-
Requires-Dist: py5paisa
|
|
26
|
-
Requires-Dist: upstox-python-sdk
|
|
27
|
-
Requires-Dist: undetected-chromedriver
|
|
28
|
-
Requires-Dist: cachetools
|
|
29
|
-
Requires-Dist: py_vollib
|
|
30
|
-
Requires-Dist: python-engineio
|
|
31
|
-
Requires-Dist: python-socketio
|
|
32
|
-
Requires-Dist: six
|
|
33
|
-
Requires-Dist: dhanhq
|
|
34
9
|
|
|
35
10
|
# Quantplay Alpha playground
|
|
36
11
|
|
|
@@ -102,14 +102,6 @@ class Dhan(Broker):
|
|
|
102
102
|
self.dhan.DAY,
|
|
103
103
|
)
|
|
104
104
|
|
|
105
|
-
response = self.wrapper.modify_order( # type: ignore
|
|
106
|
-
order_id=order_id,
|
|
107
|
-
variety=order["variety"],
|
|
108
|
-
price=order["price"],
|
|
109
|
-
trigger_price=order["trigger_price"],
|
|
110
|
-
order_type=order["order_type"],
|
|
111
|
-
)
|
|
112
|
-
return response # type:ignore
|
|
113
105
|
except Exception as e:
|
|
114
106
|
exception_message = (
|
|
115
107
|
"OrderModificationFailed for {} failed with exception {}".format(
|
|
@@ -159,8 +151,7 @@ class Dhan(Broker):
|
|
|
159
151
|
return dhanhq.CNC
|
|
160
152
|
elif product == "MIS":
|
|
161
153
|
return dhanhq.INTRA
|
|
162
|
-
|
|
163
|
-
raise InvalidArgumentException(f"Product {product} not supported for trading")
|
|
154
|
+
return product
|
|
164
155
|
|
|
165
156
|
def get_symbol(self, symbol: str, exchange: ExchangeType | None = None):
|
|
166
157
|
if symbol not in self.quantplay_symbol_map:
|
|
@@ -182,19 +173,25 @@ class Dhan(Broker):
|
|
|
182
173
|
trigger_price: float | None = None,
|
|
183
174
|
) -> str | None:
|
|
184
175
|
try:
|
|
185
|
-
Constants.logger.info(
|
|
186
|
-
f"[PLACING_ORDER] {tradingsymbol} {exchange} {quantity} {tag}"
|
|
187
|
-
)
|
|
188
176
|
tradingsymbol = self.get_symbol(tradingsymbol)
|
|
189
177
|
security_id = self.symbol_data[f"{exchange}:{tradingsymbol}"]["token"]
|
|
178
|
+
exchange_segment = self.get_exchange_segment(exchange)
|
|
179
|
+
dhan_order_type = self.get_order_type(order_type)
|
|
180
|
+
product_type = self.get_product(product)
|
|
181
|
+
Constants.logger.info(
|
|
182
|
+
f"[DHAN_PLACING_ORDER] {security_id} {exchange} {transaction_type} {quantity} {dhan_order_type} {product_type} {price} {trigger_price}"
|
|
183
|
+
)
|
|
184
|
+
if trigger_price is None:
|
|
185
|
+
trigger_price = 0
|
|
190
186
|
order_id: str = self.dhan.place_order( # type:ignore
|
|
191
187
|
security_id=security_id, # hdfcbank
|
|
192
|
-
exchange_segment=
|
|
188
|
+
exchange_segment=exchange_segment,
|
|
193
189
|
transaction_type=transaction_type,
|
|
194
190
|
quantity=quantity,
|
|
195
|
-
order_type=
|
|
196
|
-
product_type=
|
|
191
|
+
order_type=dhan_order_type,
|
|
192
|
+
product_type=product_type,
|
|
197
193
|
price=price,
|
|
194
|
+
trigger_price=trigger_price, # type:ignore
|
|
198
195
|
)
|
|
199
196
|
|
|
200
197
|
return order_id # type:ignore
|
|
@@ -285,38 +285,53 @@ class Motilal(Broker):
|
|
|
285
285
|
Constants.logger.info(f"[GET_LTP_RESPONSE] response {response}")
|
|
286
286
|
return response["data"]["ltp"] / 100.0
|
|
287
287
|
|
|
288
|
-
def
|
|
289
|
-
|
|
290
|
-
order_id: str,
|
|
291
|
-
price: float,
|
|
292
|
-
trigger_price: float | None = None,
|
|
293
|
-
order_type: OrderTypeType | None = None,
|
|
294
|
-
):
|
|
288
|
+
def add_existing_order_details(self, order_to_modify: Dict[str, str]):
|
|
289
|
+
order_id = order_to_modify["order_id"]
|
|
295
290
|
orders = self.orders()
|
|
296
291
|
orders = orders.filter(pl.col("order_id") == order_id)
|
|
297
292
|
|
|
298
293
|
if len(orders) != 1:
|
|
299
|
-
|
|
300
|
-
"
|
|
294
|
+
raise InvalidArgumentException(
|
|
295
|
+
f"Invalid modify request, order_id {order_id} not found"
|
|
301
296
|
)
|
|
302
|
-
return
|
|
303
297
|
|
|
304
298
|
order = orders.to_dicts()[0]
|
|
305
299
|
order["last_modified_time"] = str(order["last_modified_time"])
|
|
306
300
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
301
|
+
if "price" in order_to_modify:
|
|
302
|
+
order["price"] = order_to_modify["price"]
|
|
303
|
+
if (
|
|
304
|
+
"trigger_price" in order_to_modify
|
|
305
|
+
and order_to_modify["trigger_price"] is not None # type:ignore
|
|
306
|
+
):
|
|
307
|
+
order["trigger_price"] = order_to_modify["trigger_price"]
|
|
310
308
|
|
|
311
|
-
if
|
|
309
|
+
if "order_type" in order_to_modify and order_to_modify["order_type"] == "SL":
|
|
312
310
|
order["order_type"] = "STOPLOSS"
|
|
313
311
|
|
|
314
|
-
|
|
315
|
-
|
|
312
|
+
return order
|
|
313
|
+
|
|
314
|
+
def modify_price(
|
|
315
|
+
self,
|
|
316
|
+
order_id: str,
|
|
317
|
+
price: float,
|
|
318
|
+
trigger_price: float | None = None,
|
|
319
|
+
order_type: OrderTypeType | None = None,
|
|
320
|
+
):
|
|
321
|
+
order_to_modify = {
|
|
322
|
+
"order_id": order_id,
|
|
323
|
+
"price": price,
|
|
324
|
+
"trigger_price": trigger_price,
|
|
325
|
+
"order_type": order_type,
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
self.modify_order(order_to_modify) # type: ignore
|
|
316
329
|
|
|
317
330
|
# TODO
|
|
318
331
|
def modify_order(self, order: Any) -> str:
|
|
319
332
|
order = copy.deepcopy(order) # type:ignore
|
|
333
|
+
order = self.add_existing_order_details(order)
|
|
334
|
+
|
|
320
335
|
data = {
|
|
321
336
|
"uniqueorderid": order["order_id"],
|
|
322
337
|
"newordertype": order["order_type"].upper(),
|
|
@@ -250,6 +250,11 @@ class Noren(Broker):
|
|
|
250
250
|
f"[PLACE_ORDER_FAILED] {exception_message}"
|
|
251
251
|
)
|
|
252
252
|
|
|
253
|
+
@retry(
|
|
254
|
+
wait_exponential_multiplier=3000,
|
|
255
|
+
wait_exponential_max=10000,
|
|
256
|
+
stop_max_attempt_number=3,
|
|
257
|
+
)
|
|
253
258
|
def ltp(self, exchange: ExchangeType, tradingsymbol: str):
|
|
254
259
|
tradingsymbol = self.get_symbol(tradingsymbol, exchange)
|
|
255
260
|
|
|
@@ -375,6 +380,11 @@ class Noren(Broker):
|
|
|
375
380
|
|
|
376
381
|
return response
|
|
377
382
|
|
|
383
|
+
@retry(
|
|
384
|
+
wait_exponential_multiplier=3000,
|
|
385
|
+
wait_exponential_max=10000,
|
|
386
|
+
stop_max_attempt_number=3,
|
|
387
|
+
)
|
|
378
388
|
def holdings(self):
|
|
379
389
|
holdings = self.invoke_noren_api(self.api.get_holdings)
|
|
380
390
|
if holdings is None or len(holdings) == 0:
|
|
@@ -685,6 +695,12 @@ class Noren(Broker):
|
|
|
685
695
|
traceback.print_exc()
|
|
686
696
|
raise RetryableException("Failed to Receive Data from broker. Retrying Again")
|
|
687
697
|
|
|
698
|
+
@retry(
|
|
699
|
+
wait_exponential_multiplier=1000,
|
|
700
|
+
wait_exponential_max=10000,
|
|
701
|
+
stop_max_attempt_number=3,
|
|
702
|
+
retry_on_exception=retry_exception,
|
|
703
|
+
)
|
|
688
704
|
def margins(self) -> MarginsResponse:
|
|
689
705
|
api_margins = self.invoke_noren_api(self.api.get_limits)
|
|
690
706
|
|
|
@@ -12,12 +12,6 @@ from retrying import retry # type: ignore
|
|
|
12
12
|
|
|
13
13
|
from quantplay.broker.generics.broker import Broker
|
|
14
14
|
from quantplay.broker.xts_utils.Connect import XTSConnect
|
|
15
|
-
from quantplay.broker.xts_utils.Exception import (
|
|
16
|
-
XTSDataException,
|
|
17
|
-
XTSGeneralException,
|
|
18
|
-
XTSNetworkException,
|
|
19
|
-
XTSTokenException,
|
|
20
|
-
)
|
|
21
15
|
from quantplay.broker.xts_utils.InteractiveSocketClient import OrderSocket_io
|
|
22
16
|
from quantplay.exception.exceptions import (
|
|
23
17
|
BrokerException,
|
|
@@ -82,11 +76,8 @@ class XTS(Broker):
|
|
|
82
76
|
self.load_instrument()
|
|
83
77
|
|
|
84
78
|
def set_wrapper(self, serialized_wrapper: str, serialized_md_wrapper: str):
|
|
85
|
-
self.wrapper
|
|
86
|
-
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
self.md_wrapper: XTSConnect = pickle.loads(
|
|
79
|
+
self.wrapper = pickle.loads(codecs.decode(serialized_wrapper.encode(), "base64"))
|
|
80
|
+
self.md_wrapper = pickle.loads(
|
|
90
81
|
codecs.decode(serialized_md_wrapper.encode(), "base64")
|
|
91
82
|
)
|
|
92
83
|
|
|
@@ -110,34 +101,29 @@ class XTS(Broker):
|
|
|
110
101
|
|
|
111
102
|
ins_type = instrument["instrument_type"]
|
|
112
103
|
name = instrument["name"]
|
|
113
|
-
|
|
114
104
|
if ins_type in ["CE", "PE"]:
|
|
115
105
|
expiry = datetime.strftime(
|
|
116
106
|
datetime.strptime(str(instrument["expiry"]), "%Y-%m-%d"),
|
|
117
107
|
"%d%b%Y",
|
|
118
108
|
).upper()
|
|
119
109
|
strike = str(instrument["strike"]).rstrip("0")
|
|
120
|
-
|
|
121
110
|
if strike[-1] == ".":
|
|
122
111
|
strike = strike[:-1]
|
|
123
|
-
|
|
124
112
|
instrument["broker_symbol"] = f"{name} {expiry} {ins_type} {strike}"
|
|
125
|
-
|
|
126
113
|
elif ins_type == "FUT":
|
|
127
114
|
expiry = datetime.strftime(
|
|
128
115
|
datetime.strptime(str(instrument["expiry"]), "%Y-%m-%d"),
|
|
129
116
|
"%d%b%Y",
|
|
130
117
|
).upper()
|
|
131
118
|
instrument["broker_symbol"] = f"{name} {expiry}"
|
|
132
|
-
|
|
133
119
|
else:
|
|
134
120
|
instrument["broker_symbol"] = tradingsymbol
|
|
135
121
|
|
|
122
|
+
# TODO: Types
|
|
136
123
|
self.symbol_data[f"{exchange}:{tradingsymbol}"] = instrument # type: ignore
|
|
137
124
|
|
|
138
125
|
PickleUtils.save_data(self.symbol_data, "xts_instruments")
|
|
139
126
|
Constants.logger.info("[LOADING_INSTRUMENTS] loading data from server")
|
|
140
|
-
|
|
141
127
|
self.initialize_broker_symbol_map()
|
|
142
128
|
|
|
143
129
|
def login(self, api_key: str, api_secret: str, md_api_key: str, md_api_secret: str):
|
|
@@ -147,53 +133,48 @@ class XTS(Broker):
|
|
|
147
133
|
secretKey=api_secret,
|
|
148
134
|
root=self.root_url,
|
|
149
135
|
)
|
|
150
|
-
xt_core_response = self.
|
|
151
|
-
|
|
136
|
+
xt_core_response = self.wrapper.interactive_login()
|
|
152
137
|
self.md_wrapper = XTSConnect(
|
|
153
138
|
apiKey=md_api_key,
|
|
154
139
|
secretKey=md_api_secret,
|
|
155
140
|
root=self.root_url,
|
|
156
141
|
)
|
|
157
|
-
md_response = self.
|
|
158
|
-
|
|
142
|
+
md_response = self.md_wrapper.marketdata_login()
|
|
159
143
|
if "type" not in xt_core_response or xt_core_response["type"] != "success":
|
|
160
144
|
print(f"api login response {xt_core_response}")
|
|
161
145
|
raise TokenException("Api key credentials are incorrect")
|
|
162
|
-
|
|
163
146
|
if "type" not in md_response or md_response["type"] != "success":
|
|
164
147
|
print(f"market data login response {md_response}")
|
|
165
148
|
raise TokenException("Market data api credentials are invalid")
|
|
166
|
-
|
|
167
149
|
self.ClientID = xt_core_response["result"]["userID"]
|
|
168
|
-
|
|
169
150
|
except TokenException:
|
|
170
151
|
raise
|
|
171
|
-
|
|
172
152
|
except Exception:
|
|
173
153
|
raise InvalidArgumentException("Invalid api key/secret")
|
|
174
154
|
|
|
175
155
|
def handle_exception(self, response: Dict[str, Any]):
|
|
176
156
|
if "data" in response and "description" in response["data"]:
|
|
177
157
|
data = response["data"]
|
|
178
|
-
|
|
179
158
|
if "max limit" in data["description"].lower():
|
|
180
159
|
user_id = self.profile()["user_id"]
|
|
181
160
|
print("Rate limit problem")
|
|
182
161
|
raise RetryableException(f"{user_id}: Request limit exceeded")
|
|
183
|
-
|
|
184
162
|
if (
|
|
185
163
|
"description" in response
|
|
186
164
|
and "Authorization not found" in response["description"]
|
|
187
165
|
):
|
|
188
166
|
raise TokenException(response["description"])
|
|
189
|
-
|
|
190
167
|
if "type" in response and response["type"] == "error":
|
|
191
168
|
raise Exception(f"[XTS_Error]: {response['description']}")
|
|
192
169
|
|
|
170
|
+
@retry(
|
|
171
|
+
wait_exponential_multiplier=3000,
|
|
172
|
+
wait_exponential_max=10000,
|
|
173
|
+
stop_max_attempt_number=3,
|
|
174
|
+
retry_on_exception=retry_exception,
|
|
175
|
+
)
|
|
193
176
|
def margins(self) -> MarginsResponse:
|
|
194
|
-
api_response = self.
|
|
195
|
-
self.wrapper.get_balance, clientID=self.ClientID
|
|
196
|
-
)
|
|
177
|
+
api_response = self.wrapper.get_balance(clientID=self.ClientID)
|
|
197
178
|
self.handle_exception(api_response)
|
|
198
179
|
|
|
199
180
|
if not api_response:
|
|
@@ -213,10 +194,14 @@ class XTS(Broker):
|
|
|
213
194
|
"cash": 0,
|
|
214
195
|
}
|
|
215
196
|
|
|
197
|
+
@retry(
|
|
198
|
+
wait_exponential_multiplier=3000,
|
|
199
|
+
wait_exponential_max=10000,
|
|
200
|
+
stop_max_attempt_number=3,
|
|
201
|
+
retry_on_exception=retry_exception,
|
|
202
|
+
)
|
|
216
203
|
def profile(self) -> UserBrokerProfileResponse:
|
|
217
|
-
api_response = self.
|
|
218
|
-
self.wrapper.get_profile, clientID=self.ClientID
|
|
219
|
-
)
|
|
204
|
+
api_response = self.wrapper.get_profile(self.ClientID)
|
|
220
205
|
self.handle_exception(api_response)
|
|
221
206
|
api_response = api_response["result"]
|
|
222
207
|
|
|
@@ -228,10 +213,14 @@ class XTS(Broker):
|
|
|
228
213
|
|
|
229
214
|
return response
|
|
230
215
|
|
|
216
|
+
@retry(
|
|
217
|
+
wait_exponential_multiplier=3000,
|
|
218
|
+
wait_exponential_max=10000,
|
|
219
|
+
stop_max_attempt_number=3,
|
|
220
|
+
retry_on_exception=retry_exception,
|
|
221
|
+
)
|
|
231
222
|
def orders(self, tag: str | None = None, add_ltp: bool = True) -> pl.DataFrame:
|
|
232
|
-
api_response = self.
|
|
233
|
-
self.wrapper.get_order_book, clientID=self.ClientID
|
|
234
|
-
)
|
|
223
|
+
api_response = self.wrapper.get_order_book(self.ClientID)
|
|
235
224
|
self.handle_exception(api_response)
|
|
236
225
|
|
|
237
226
|
api_response = api_response["result"]
|
|
@@ -356,13 +345,22 @@ class XTS(Broker):
|
|
|
356
345
|
|
|
357
346
|
return orders_df[list(self.orders_schema.keys())].cast(self.orders_schema)
|
|
358
347
|
|
|
348
|
+
@retry(
|
|
349
|
+
wait_exponential_multiplier=3000,
|
|
350
|
+
wait_exponential_max=10000,
|
|
351
|
+
stop_max_attempt_number=3,
|
|
352
|
+
)
|
|
359
353
|
def holdings(self):
|
|
360
354
|
return pl.DataFrame(schema=self.holidings_schema)
|
|
361
355
|
|
|
356
|
+
@retry(
|
|
357
|
+
wait_exponential_multiplier=3000,
|
|
358
|
+
wait_exponential_max=10000,
|
|
359
|
+
stop_max_attempt_number=3,
|
|
360
|
+
retry_on_exception=retry_exception,
|
|
361
|
+
)
|
|
362
362
|
def positions(self, drop_cnc: bool = True) -> pl.DataFrame:
|
|
363
|
-
api_response = self.
|
|
364
|
-
self.wrapper.get_position_daywise, clientID=self.ClientID
|
|
365
|
-
)
|
|
363
|
+
api_response = self.wrapper.get_position_daywise(self.ClientID)
|
|
366
364
|
self.handle_exception(api_response)
|
|
367
365
|
|
|
368
366
|
api_response = api_response["result"]["positionList"]
|
|
@@ -480,9 +478,7 @@ class XTS(Broker):
|
|
|
480
478
|
}
|
|
481
479
|
for x in symbols
|
|
482
480
|
]
|
|
483
|
-
|
|
484
|
-
api_response = self.invoke_xts_api(
|
|
485
|
-
self.md_wrapper.get_quote,
|
|
481
|
+
api_response = self.md_wrapper.get_quote(
|
|
486
482
|
Instruments=instruments,
|
|
487
483
|
xtsMessageCode=1512,
|
|
488
484
|
publishFormat="JSON",
|
|
@@ -490,7 +486,6 @@ class XTS(Broker):
|
|
|
490
486
|
|
|
491
487
|
if "type" in api_response and api_response["type"] == "error":
|
|
492
488
|
raise TokenException(api_response["description"])
|
|
493
|
-
|
|
494
489
|
api_response = api_response["result"]
|
|
495
490
|
|
|
496
491
|
ltp_json = api_response["listQuotes"]
|
|
@@ -546,8 +541,7 @@ class XTS(Broker):
|
|
|
546
541
|
"", # TODO
|
|
547
542
|
)
|
|
548
543
|
|
|
549
|
-
api_response = self.
|
|
550
|
-
self.md_wrapper.get_quote,
|
|
544
|
+
api_response = self.md_wrapper.get_quote(
|
|
551
545
|
Instruments=[
|
|
552
546
|
{
|
|
553
547
|
"exchangeSegment": exchange_code,
|
|
@@ -567,7 +561,6 @@ class XTS(Broker):
|
|
|
567
561
|
|
|
568
562
|
try:
|
|
569
563
|
ltp_json = api_response["listQuotes"][0]
|
|
570
|
-
|
|
571
564
|
except IndexError as e:
|
|
572
565
|
print(api_response, e)
|
|
573
566
|
raise BrokerException("Broker Provided Invalid Response")
|
|
@@ -600,8 +593,7 @@ class XTS(Broker):
|
|
|
600
593
|
if tag is None:
|
|
601
594
|
tag = ""
|
|
602
595
|
|
|
603
|
-
api_response = self.
|
|
604
|
-
self.wrapper.place_order,
|
|
596
|
+
api_response = self.wrapper.place_order(
|
|
605
597
|
exchangeSegment=exchange_name,
|
|
606
598
|
exchangeInstrumentID=exchange_token,
|
|
607
599
|
orderType=xts_order_type,
|
|
@@ -634,8 +626,7 @@ class XTS(Broker):
|
|
|
634
626
|
|
|
635
627
|
tag = order_data["tag"]
|
|
636
628
|
|
|
637
|
-
api_response = self.
|
|
638
|
-
self.wrapper.cancel_order,
|
|
629
|
+
api_response = self.wrapper.cancel_order(
|
|
639
630
|
appOrderID=int(order_id),
|
|
640
631
|
clientID=order_data["user_id"],
|
|
641
632
|
orderUniqueIdentifier=tag,
|
|
@@ -687,8 +678,7 @@ class XTS(Broker):
|
|
|
687
678
|
time_in_force = "DAY"
|
|
688
679
|
disclosed_quantity = 0
|
|
689
680
|
|
|
690
|
-
api_response = self.
|
|
691
|
-
self.wrapper.modify_order,
|
|
681
|
+
api_response = self.wrapper.modify_order(
|
|
692
682
|
appOrderID=int(order_id),
|
|
693
683
|
modifiedTimeInForce=time_in_force,
|
|
694
684
|
modifiedDisclosedQuantity=disclosed_quantity,
|
|
@@ -816,49 +806,3 @@ class XTS(Broker):
|
|
|
816
806
|
except Exception as e:
|
|
817
807
|
print(e)
|
|
818
808
|
Constants.logger.error("[ORDER_UPDATE_PROCESSING_FAILED] {}".format(e))
|
|
819
|
-
|
|
820
|
-
@retry(
|
|
821
|
-
wait_exponential_multiplier=3000,
|
|
822
|
-
wait_exponential_max=10000,
|
|
823
|
-
stop_max_attempt_number=3,
|
|
824
|
-
retry_on_exception=retry_exception,
|
|
825
|
-
)
|
|
826
|
-
def invoke_xts_api(self, fn: Any, *args: Any, **kwargs: Any) -> Dict[str, Any]:
|
|
827
|
-
try:
|
|
828
|
-
response = fn(*args, **kwargs)
|
|
829
|
-
|
|
830
|
-
if "data" in response and "description" in response["data"]:
|
|
831
|
-
data = response["data"]
|
|
832
|
-
|
|
833
|
-
if "max limit" in data["description"].lower():
|
|
834
|
-
user_id = self.profile()["user_id"]
|
|
835
|
-
print("Rate limit problem")
|
|
836
|
-
raise RetryableException(f"{user_id}: Request limit exceeded")
|
|
837
|
-
|
|
838
|
-
if (
|
|
839
|
-
"description" in response
|
|
840
|
-
and "Authorization not found" in response["description"]
|
|
841
|
-
):
|
|
842
|
-
raise TokenException(response["description"])
|
|
843
|
-
|
|
844
|
-
if "type" in response and response["type"] == "error":
|
|
845
|
-
raise Exception(f"[XTS_Error]: {response['description']}")
|
|
846
|
-
|
|
847
|
-
return response
|
|
848
|
-
|
|
849
|
-
except XTSTokenException as e:
|
|
850
|
-
raise TokenException(str(e))
|
|
851
|
-
|
|
852
|
-
except (TokenException, RetryableException):
|
|
853
|
-
raise
|
|
854
|
-
|
|
855
|
-
except (
|
|
856
|
-
XTSGeneralException,
|
|
857
|
-
XTSDataException,
|
|
858
|
-
XTSNetworkException,
|
|
859
|
-
) as e:
|
|
860
|
-
raise BrokerException(str(e))
|
|
861
|
-
|
|
862
|
-
except Exception:
|
|
863
|
-
traceback.print_exc()
|
|
864
|
-
raise
|