quantplay 2.0.52__tar.gz → 2.0.53__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.
Files changed (65) hide show
  1. {quantplay-2.0.52 → quantplay-2.0.53}/PKG-INFO +26 -1
  2. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/broker_factory.py +25 -3
  3. quantplay-2.0.53/quantplay/broker/kotak.py +370 -0
  4. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay.egg-info/PKG-INFO +26 -1
  5. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay.egg-info/SOURCES.txt +1 -0
  6. {quantplay-2.0.52 → quantplay-2.0.53}/setup.py +1 -1
  7. {quantplay-2.0.52 → quantplay-2.0.53}/README.md +0 -0
  8. {quantplay-2.0.52 → quantplay-2.0.53}/pyproject.toml +0 -0
  9. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/__init__.py +0 -0
  10. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/__init__.py +0 -0
  11. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/aliceblue.py +0 -0
  12. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/angelone.py +0 -0
  13. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/auto_login/__init__.py +0 -0
  14. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/auto_login/aliceblue.py +0 -0
  15. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/dhan.py +0 -0
  16. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/finvasia_utils/__init__.py +0 -0
  17. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
  18. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/five_paisa.py +0 -0
  19. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/flattrade.py +0 -0
  20. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/ft_utils/__init__.py +0 -0
  21. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
  22. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/ft_utils/ft_noren.py +0 -0
  23. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/generics/__init__.py +0 -0
  24. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/generics/broker.py +0 -0
  25. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/iifl_xts.py +0 -0
  26. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/kite_utils.py +0 -0
  27. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/motilal.py +0 -0
  28. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/noren.py +0 -0
  29. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/shoonya.py +0 -0
  30. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/uplink/__init__.py +0 -0
  31. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/uplink/uplink_utils.py +0 -0
  32. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/upstox.py +0 -0
  33. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/xts.py +0 -0
  34. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/xts_utils/Connect.py +0 -0
  35. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/xts_utils/Exception.py +0 -0
  36. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
  37. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/xts_utils/__init__.py +0 -0
  38. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/broker/zerodha.py +0 -0
  39. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/exception/__init__.py +0 -0
  40. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/exception/exceptions.py +0 -0
  41. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/model/__init__.py +0 -0
  42. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/model/broker.py +0 -0
  43. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/model/generics.py +0 -0
  44. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/model/instrument_data.py +0 -0
  45. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/model/order_event.py +0 -0
  46. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/py.typed +0 -0
  47. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/utils/__init__.py +0 -0
  48. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/utils/caching.py +0 -0
  49. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/utils/constant.py +0 -0
  50. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/utils/exchange.py +0 -0
  51. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/utils/number_utils.py +0 -0
  52. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/utils/pickle_utils.py +0 -0
  53. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/utils/selenium_utils.py +0 -0
  54. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/wrapper/__init__.py +0 -0
  55. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/wrapper/aws/__init__.py +0 -0
  56. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay/wrapper/aws/s3.py +0 -0
  57. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay.egg-info/dependency_links.txt +0 -0
  58. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay.egg-info/requires.txt +0 -0
  59. {quantplay-2.0.52 → quantplay-2.0.53}/quantplay.egg-info/top_level.txt +0 -0
  60. {quantplay-2.0.52 → quantplay-2.0.53}/setup.cfg +0 -0
  61. {quantplay-2.0.52 → quantplay-2.0.53}/tests/__init__.py +0 -0
  62. {quantplay-2.0.52 → quantplay-2.0.53}/tests/conftest.py +0 -0
  63. {quantplay-2.0.52 → quantplay-2.0.53}/tests/wrapper/__init__.py +0 -0
  64. {quantplay-2.0.52 → quantplay-2.0.53}/tests/wrapper/aws/__init__.py +0 -0
  65. {quantplay-2.0.52 → quantplay-2.0.53}/tests/wrapper/aws/s3_test.py +0 -0
@@ -1,11 +1,36 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantplay
3
- Version: 2.0.52
3
+ Version: 2.0.53
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
9
34
 
10
35
  # Quantplay Alpha playground
11
36
 
@@ -5,9 +5,11 @@ from typing import Any, Dict
5
5
 
6
6
  from quantplay.broker.aliceblue import Aliceblue
7
7
  from quantplay.broker.angelone import AngelOne
8
+ from quantplay.broker.dhan import Dhan
8
9
  from quantplay.broker.five_paisa import FivePaisa
9
10
  from quantplay.broker.flattrade import FlatTrade
10
11
  from quantplay.broker.iifl_xts import IIFL as IIFL_XTS
12
+ from quantplay.broker.kotak import Kotak
11
13
  from quantplay.broker.motilal import Motilal
12
14
  from quantplay.broker.shoonya import FinvAsia
13
15
  from quantplay.broker.upstox import Upstox
@@ -16,6 +18,7 @@ from quantplay.exception.exceptions import InvalidArgumentException
16
18
  from quantplay.utils.caching import InstrumentCache
17
19
  from quantplay.utils.pickle_utils import PickleUtils
18
20
 
21
+
19
22
  BrokerType = (
20
23
  Aliceblue
21
24
  | AngelOne
@@ -26,6 +29,8 @@ BrokerType = (
26
29
  | Zerodha
27
30
  | IIFL_XTS
28
31
  | FivePaisa
32
+ | Kotak
33
+ | Dhan
29
34
  )
30
35
 
31
36
  instrument_cache = InstrumentCache()
@@ -42,6 +47,8 @@ class Broker:
42
47
  IIFL_XTS = "IIFL_XTS"
43
48
  MOTILAL = "Motilal"
44
49
  ANGELONE = "Angelone"
50
+ KOTAK = "Kotak"
51
+ DHAN = "Dhan"
45
52
 
46
53
 
47
54
  class BrokerFactory:
@@ -55,6 +62,7 @@ class BrokerFactory:
55
62
  Broker.ALICEBLUE: "aliceblue_instruments",
56
63
  Broker.UPSTOX: "upstox_instruments",
57
64
  Broker.FIVEPAISA_OPENAPI: "5paisa_instruments",
65
+ Broker.KOTAK: "upstox_instruments",
58
66
  }
59
67
  broker_required_args = {
60
68
  Broker.ZERODHA: set(["user_id", "zerodha_wrapper"]),
@@ -64,6 +72,7 @@ class BrokerFactory:
64
72
  Broker.MOTILAL: set(["user_id", "headers"]),
65
73
  Broker.ALICEBLUE: set(["user_id", "client"]),
66
74
  Broker.UPSTOX: set(["user_id", "access_token"]),
75
+ Broker.DHAN: set(["user_id", "access_token"]),
67
76
  Broker.FIVEPAISA_OPENAPI: set(["user_id", "client"]),
68
77
  Broker.ANGELONE: set(
69
78
  [
@@ -74,6 +83,7 @@ class BrokerFactory:
74
83
  "feed_token",
75
84
  ]
76
85
  ),
86
+ Broker.KOTAK: set(["user_id", "configuration"]),
77
87
  }
78
88
 
79
89
  def __init__(self):
@@ -107,19 +117,31 @@ class BrokerFactory:
107
117
 
108
118
  broker_client: BrokerType | None = None
109
119
 
110
- if broker == "Motilal":
120
+ if broker == Broker.MOTILAL:
111
121
  broker_client = Motilal(
112
122
  headers=broker_data["headers"],
113
123
  load_instrument=load_instrument,
114
124
  )
115
125
 
116
- elif broker == "Zerodha":
126
+ if broker == Broker.DHAN:
127
+ broker_client = Dhan(
128
+ user_id=broker_data["user_id"],
129
+ access_token=broker_data["access_token"],
130
+ load_instrument=load_instrument,
131
+ )
132
+
133
+ if broker == Broker.KOTAK:
134
+ broker_client = Kotak(
135
+ configuration=broker_data["configuration"],
136
+ load_instrument=load_instrument,
137
+ )
138
+ elif broker == Broker.ZERODHA:
117
139
  broker_client = Zerodha(
118
140
  wrapper=broker_data["zerodha_wrapper"],
119
141
  load_instrument=load_instrument,
120
142
  )
121
143
 
122
- elif broker == "Angelone":
144
+ elif broker == Broker.ANGELONE:
123
145
  broker_client = AngelOne(
124
146
  user_id=broker_data["user_id"],
125
147
  api_key=broker_data["api_key"],
@@ -0,0 +1,370 @@
1
+ import json
2
+ from queue import Queue
3
+ from typing import Any, Dict, Literal
4
+ import polars as pl
5
+ import requests
6
+ from quantplay.broker.generics.broker import Broker
7
+ from quantplay.model.broker import ModifyOrderRequest, UserBrokerProfileResponse
8
+ from quantplay.model.generics import (
9
+ ExchangeType,
10
+ OrderTypeType,
11
+ ProductType,
12
+ TransactionType,
13
+ )
14
+ from quantplay.model.order_event import OrderUpdateEvent
15
+
16
+ from urllib.parse import urlencode
17
+
18
+ import base64
19
+
20
+ PROD_BASE_URL = "https://gw-napi.kotaksecurities.com/"
21
+ SESSION_PROD_BASE_URL = "https://napi.kotaksecurities.com/"
22
+
23
+
24
+ # EvOUzPVqkwvlFl_6cZYZSCO5mwQa
25
+ # pVwafvF3ssA_jFVbKPrwhKt7igwa
26
+ # Kotak@123
27
+ # +918149949114
28
+ # 491700
29
+
30
+
31
+ class Kotak(Broker):
32
+ def __init__(
33
+ self,
34
+ order_updates: Queue[OrderUpdateEvent] | None = None,
35
+ consumer_key: str | None = None,
36
+ consumer_secret: str | None = None,
37
+ mobilenumber: str | None = None,
38
+ password: str | None = None,
39
+ mpin: str | None = None,
40
+ configuration: Dict[str, str] | None = None,
41
+ load_instrument: bool = True,
42
+ ):
43
+ super().__init__()
44
+
45
+ self.configuration: Dict[str, str] = {
46
+ "fin_key": "X6Nk8cQhUgGmJ2vBdWw4sfzrz4L5En",
47
+ }
48
+
49
+ if configuration:
50
+ self.configuration = {
51
+ "fin_key": "X6Nk8cQhUgGmJ2vBdWw4sfzrz4L5En",
52
+ "bearer_token": configuration["bearer_token"],
53
+ "view_token": configuration["view_token"],
54
+ "sid": configuration["sid"],
55
+ "edit_token": configuration["edit_token"],
56
+ "edit_sid": configuration["edit_sid"],
57
+ "edit_rid": configuration["edit_rid"],
58
+ "serverId": configuration["serverId"],
59
+ }
60
+
61
+ elif consumer_key and consumer_secret and mobilenumber and password and mpin:
62
+ self.login(consumer_key, consumer_secret, mobilenumber, password, mpin)
63
+
64
+ def login(
65
+ self,
66
+ consumer_key: str,
67
+ consumer_secret: str,
68
+ mobilenumber: str,
69
+ password: str,
70
+ mpin: str,
71
+ ):
72
+ base64_string = str(consumer_key) + ":" + str(consumer_secret)
73
+ base64_token = base64_string.encode("ascii")
74
+
75
+ base64_bytes = base64.b64encode(base64_token)
76
+ final_base64_token = base64_bytes.decode("ascii")
77
+
78
+ session_init = requests.post(
79
+ url=f"{SESSION_PROD_BASE_URL}oauth2/token",
80
+ headers={
81
+ "Authorization": "Basic " + final_base64_token,
82
+ "Content-Type": "application/json",
83
+ },
84
+ data=json.dumps({"grant_type": "client_credentials"}),
85
+ )
86
+
87
+ print(session_init)
88
+
89
+ if not session_init.ok:
90
+ raise Exception("")
91
+
92
+ json_resp = json.loads(session_init.text)
93
+ self.configuration["bearer_token"] = json_resp.get("access_token")
94
+
95
+ view_token_resp = requests.post(
96
+ url=f"{PROD_BASE_URL}login/1.0/login/v2/validate",
97
+ headers={
98
+ "Authorization": "Bearer " + self.configuration["bearer_token"],
99
+ "Content-Type": "application/json",
100
+ },
101
+ data=json.dumps({"mobileNumber": mobilenumber, "password": password}),
102
+ )
103
+ view_token = json.loads(view_token_resp.text)
104
+
105
+ self.configuration["view_token"] = view_token.get("data").get("token")
106
+ self.configuration["sid"] = view_token.get("data").get("sid")
107
+
108
+ view_token_resp = requests.post(
109
+ url=f"{PROD_BASE_URL}login/1.0/login/v2/validate",
110
+ headers={
111
+ "Authorization": "Bearer " + self.configuration["bearer_token"],
112
+ "sid": self.configuration["sid"],
113
+ "Auth": self.configuration["view_token"],
114
+ "Content-Type": "application/json",
115
+ },
116
+ data=json.dumps({"mobileNumber": mobilenumber, "password": password}),
117
+ )
118
+
119
+ login_resp = requests.post(
120
+ url=f"{PROD_BASE_URL}login/1.0/login/v2/validate",
121
+ headers={"Authorization": "Bearer " + self.configuration["bearer_token"]},
122
+ data=json.dumps({"mobileNumber": mobilenumber, "mpin": mpin}),
123
+ )
124
+ edit_token_resp = json.loads(login_resp.text)
125
+
126
+ if "error" not in edit_token_resp:
127
+ self.configuration["edit_token"] = edit_token_resp.get("data").get("token")
128
+ self.configuration["edit_sid"] = edit_token_resp.get("data").get("sid")
129
+ self.configuration["edit_rid"] = edit_token_resp.get("data").get("rid")
130
+ self.configuration["serverId"] = edit_token_resp.get("data").get("hsServerId")
131
+ self.user_id = edit_token_resp.get("data").get("ucc")
132
+
133
+ # decode_jwt = jwt.decode( # type: ignore
134
+ # self.configuration["view_token"], options={"verify_signature": False}
135
+ # )
136
+ # userid = decode_jwt.get("sub")
137
+ # self.kotakUserId = userid
138
+
139
+ # generate_otp_resp = requests.post(
140
+ # url=f"{PROD_BASE_URL}login/1.0/login/otp/generate",
141
+ # headers={"Authorization": "Bearer " + self.configuration["bearer_token"]},
142
+ # data=json.dumps({"userId": userid, "sendEmail": True, "isWhitelisted": True}),
143
+ # )
144
+
145
+ # generate_otp = json.loads(generate_otp_resp.text)
146
+
147
+ def get_base64_token(self, consumer_key: str, consumer_secret: str):
148
+ """The Base64 Token Generation.
149
+ This function will generate the Base64 Token this will be used to generate the Bearer Token.
150
+ Return the Token in a String Format
151
+ """
152
+
153
+ # **
154
+ # ** GET Api's
155
+ # **
156
+
157
+ def orders(self, tag: str | None = None, add_ltp: bool = True) -> pl.DataFrame:
158
+ orders_resp = self.request("order_book")
159
+
160
+ if orders_resp["stat"] == "Not_Ok" and orders_resp["errMsg"] == "No Data":
161
+ return pl.DataFrame(schema=self.orders_schema)
162
+
163
+ return pl.DataFrame(schema=self.orders_schema)
164
+
165
+ def positions(self, drop_cnc: bool = True) -> pl.DataFrame:
166
+ positions_resp = self.request("order_book")
167
+
168
+ if positions_resp["stat"] == "Not_Ok" and positions_resp["errMsg"] == "No Data":
169
+ return pl.DataFrame(schema=self.positions_schema)
170
+
171
+ return pl.DataFrame(schema=self.positions_schema)
172
+
173
+ def holdings(self) -> pl.DataFrame:
174
+ holdings_resp = self.request("order_book")
175
+
176
+ if holdings_resp["stat"] == "Not_Ok" and holdings_resp["errMsg"] == "No Data":
177
+ return pl.DataFrame(schema=self.holidings_schema)
178
+
179
+ return pl.DataFrame(schema=self.holidings_schema)
180
+
181
+ def ltp(self, exchange: ExchangeType, tradingsymbol: str) -> float:
182
+ raise NotImplementedError()
183
+
184
+ def profile(self) -> UserBrokerProfileResponse:
185
+ return {"user_id": self.user_id or ""}
186
+
187
+ def margins(self) -> Dict[str, float]:
188
+ return self.request("limits", body={"seg": "ALL", "exch": "ALL", "prod": "ALL"})
189
+
190
+ # **
191
+ # ** POST/PUT Api's
192
+ # **
193
+
194
+ def place_order(
195
+ self,
196
+ tradingsymbol: str,
197
+ exchange: ExchangeType,
198
+ quantity: int,
199
+ order_type: OrderTypeType,
200
+ transaction_type: TransactionType,
201
+ tag: str | None,
202
+ product: ProductType,
203
+ price: float,
204
+ trigger_price: float | None = None,
205
+ ) -> str | None:
206
+ place_order_body = {
207
+ "am": "NO",
208
+ "dq": "0",
209
+ "es": self.get_exchange(exchange),
210
+ "mp": "0",
211
+ "pc": self.get_product(product),
212
+ "pf": "N",
213
+ "pr": str(price),
214
+ "pt": self.get_order_type(order_type),
215
+ "qt": str(quantity),
216
+ "rt": "DAY",
217
+ "tp": str(trigger_price or "0"),
218
+ "ts": tradingsymbol,
219
+ "tt": self.get_transaction_type(transaction_type),
220
+ "ig": tag,
221
+ }
222
+
223
+ place_order_resp = self.request("place_order", body=place_order_body)
224
+ print(place_order_resp)
225
+
226
+ return ""
227
+
228
+ def cancel_order(self, order_id: str, variety: str | None = None) -> None:
229
+ return
230
+
231
+ def modify_order(self, order: ModifyOrderRequest) -> str:
232
+ return ""
233
+
234
+ # **
235
+ # ** General Utils
236
+ # **
237
+
238
+ def get_transaction_type(self, transaction_type: TransactionType) -> str:
239
+ transaction_type_map: Dict[TransactionType, str] = {
240
+ "BUY": "B",
241
+ "SELL": "S",
242
+ }
243
+ return transaction_type_map.get(transaction_type, transaction_type)
244
+
245
+ def get_order_type(self, order_type: OrderTypeType) -> str:
246
+ order_type_map: Dict[OrderTypeType, str] = {
247
+ "LIMIT": "L",
248
+ "MARKET": "MKT",
249
+ "SL": "SL",
250
+ "SL-M": "SL-M",
251
+ }
252
+
253
+ return order_type_map.get(order_type, order_type)
254
+
255
+ def get_exchange(self, exchange: ExchangeType) -> str:
256
+ exchange_segment_map: Dict[ExchangeType, str] = {
257
+ "NSE": "nse_cm",
258
+ "BSE": "bse_cm",
259
+ "NFO": "nse_fo",
260
+ "BFO": "bse_fo",
261
+ "CDS": "cde_fo",
262
+ "BCD": "bcs-fo",
263
+ "MCX": "mcx",
264
+ }
265
+
266
+ return exchange_segment_map.get(exchange, exchange)
267
+
268
+ def get_product(self, product: ProductType) -> str:
269
+ product_map: Dict[ProductType, str] = {
270
+ "NRML": "NRML",
271
+ "CNC": "CNC",
272
+ "MIS": "MIS",
273
+ }
274
+
275
+ return product_map.get(product, product)
276
+
277
+ # **
278
+ # ** Kotak Utils
279
+ # **
280
+
281
+ def request(
282
+ self,
283
+ item: Literal[
284
+ "place_order",
285
+ "cancel_order",
286
+ "modify_order",
287
+ "order_history",
288
+ "order_book",
289
+ "trade_report",
290
+ "positions",
291
+ "holdings",
292
+ "margin",
293
+ "scrip_master",
294
+ "limits",
295
+ "logout",
296
+ ],
297
+ params: Dict[str, str | int | float] | None = None,
298
+ body: Dict[str, Any] | None = None,
299
+ ) -> Dict[str, Any]:
300
+ url_map = {
301
+ "place_order": ("Orders/2.0/quick/order/rule/ms/place", "POST", False),
302
+ "cancel_order": ("Orders/2.0/quick/order/cancel", "POST", False),
303
+ "modify_order": ("Orders/2.0/quick/order/vr/modify", "POST", False),
304
+ "order_history": ("Orders/2.0/quick/order/history", "GET", True),
305
+ "order_book": ("Orders/2.0/quick/user/orders", "GET", True),
306
+ "trade_report": ("Orders/2.0/quick/user/trades", "GET", True),
307
+ "positions": ("Orders/2.0/quick/user/positions", "GET", True),
308
+ "holdings": ("Portfolio/1.0/portfolio/v1/holdings", "GET", True),
309
+ "margin": ("Orders/2.0/quick/user/check-margin", "GET", True),
310
+ "scrip_master": ("Files/1.0/masterscrip/v1/file-paths", "GET", True),
311
+ "limits": ("Orders/2.0/quick/user/limits", "POST", False),
312
+ "logout": ("login/1.0/logout", "GET", True),
313
+ }
314
+
315
+ url, method, is_content_type_json = url_map[item]
316
+ content_type = (
317
+ "application/json"
318
+ if is_content_type_json
319
+ else "application/x-www-form-urlencoded"
320
+ )
321
+
322
+ url = f"{PROD_BASE_URL}{url}"
323
+
324
+ request_headers = {
325
+ "Authorization": "Bearer " + self.configuration["bearer_token"],
326
+ "Sid": self.configuration["edit_sid"],
327
+ "Auth": self.configuration["edit_token"],
328
+ "neo-fin-key": self.configuration["fin_key"],
329
+ "Content-Type": content_type,
330
+ "accept": "application/json",
331
+ }
332
+
333
+ query_params = {"sId": self.configuration["serverId"]}
334
+
335
+ request_body = None
336
+ request_params = None
337
+
338
+ if params is not None:
339
+ request_params = urlencode({**params, **query_params})
340
+ else:
341
+ request_params = urlencode(query_params)
342
+
343
+ if body is not None:
344
+ if content_type == "application/json":
345
+ request_body = json.dumps(body)
346
+
347
+ elif content_type == "application/x-www-form-urlencoded":
348
+ request_body = {"jData": json.dumps(body)}
349
+
350
+ resp = None
351
+ resp_data = None
352
+
353
+ if method == "GET":
354
+ resp = requests.get(url=url, params=request_params, headers=request_headers)
355
+
356
+ elif method == "POST":
357
+ resp = requests.post(
358
+ url=url,
359
+ headers=request_headers,
360
+ data=request_body,
361
+ params=request_params,
362
+ )
363
+
364
+ if resp and resp.ok:
365
+ resp_data = resp.json()
366
+
367
+ if resp_data is None:
368
+ raise Exception("")
369
+
370
+ return resp_data
@@ -1,11 +1,36 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantplay
3
- Version: 2.0.52
3
+ Version: 2.0.53
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
9
34
 
10
35
  # Quantplay Alpha playground
11
36
 
@@ -17,6 +17,7 @@ quantplay/broker/five_paisa.py
17
17
  quantplay/broker/flattrade.py
18
18
  quantplay/broker/iifl_xts.py
19
19
  quantplay/broker/kite_utils.py
20
+ quantplay/broker/kotak.py
20
21
  quantplay/broker/motilal.py
21
22
  quantplay/broker/noren.py
22
23
  quantplay/broker/shoonya.py
@@ -21,7 +21,7 @@ requirements = [
21
21
  setup(
22
22
  name="quantplay",
23
23
  long_description=Path("README.md").read_text(),
24
- version="2.0.52",
24
+ version="2.0.53",
25
25
  setup_requires=["pytest-runner"],
26
26
  install_requires=requirements,
27
27
  tests_require=[],
File without changes
File without changes
File without changes
File without changes
File without changes