quantplay 2.0.51__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.51 → quantplay-2.0.53}/PKG-INFO +1 -1
  2. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/broker_factory.py +25 -3
  3. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/generics/broker.py +2 -2
  4. quantplay-2.0.53/quantplay/broker/kotak.py +370 -0
  5. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay.egg-info/PKG-INFO +1 -1
  6. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay.egg-info/SOURCES.txt +1 -0
  7. {quantplay-2.0.51 → quantplay-2.0.53}/setup.py +1 -1
  8. {quantplay-2.0.51 → quantplay-2.0.53}/README.md +0 -0
  9. {quantplay-2.0.51 → quantplay-2.0.53}/pyproject.toml +0 -0
  10. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/__init__.py +0 -0
  11. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/__init__.py +0 -0
  12. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/aliceblue.py +0 -0
  13. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/angelone.py +0 -0
  14. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/auto_login/__init__.py +0 -0
  15. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/auto_login/aliceblue.py +0 -0
  16. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/dhan.py +0 -0
  17. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/finvasia_utils/__init__.py +0 -0
  18. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
  19. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/five_paisa.py +0 -0
  20. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/flattrade.py +0 -0
  21. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/ft_utils/__init__.py +0 -0
  22. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
  23. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/ft_utils/ft_noren.py +0 -0
  24. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/generics/__init__.py +0 -0
  25. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/iifl_xts.py +0 -0
  26. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/kite_utils.py +0 -0
  27. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/motilal.py +0 -0
  28. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/noren.py +0 -0
  29. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/shoonya.py +0 -0
  30. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/uplink/__init__.py +0 -0
  31. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/uplink/uplink_utils.py +0 -0
  32. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/upstox.py +0 -0
  33. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/xts.py +0 -0
  34. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/xts_utils/Connect.py +0 -0
  35. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/xts_utils/Exception.py +0 -0
  36. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
  37. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/xts_utils/__init__.py +0 -0
  38. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/broker/zerodha.py +0 -0
  39. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/exception/__init__.py +0 -0
  40. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/exception/exceptions.py +0 -0
  41. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/model/__init__.py +0 -0
  42. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/model/broker.py +0 -0
  43. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/model/generics.py +0 -0
  44. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/model/instrument_data.py +0 -0
  45. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/model/order_event.py +0 -0
  46. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/py.typed +0 -0
  47. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/utils/__init__.py +0 -0
  48. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/utils/caching.py +0 -0
  49. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/utils/constant.py +0 -0
  50. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/utils/exchange.py +0 -0
  51. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/utils/number_utils.py +0 -0
  52. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/utils/pickle_utils.py +0 -0
  53. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/utils/selenium_utils.py +0 -0
  54. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/wrapper/__init__.py +0 -0
  55. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/wrapper/aws/__init__.py +0 -0
  56. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay/wrapper/aws/s3.py +0 -0
  57. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay.egg-info/dependency_links.txt +0 -0
  58. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay.egg-info/requires.txt +0 -0
  59. {quantplay-2.0.51 → quantplay-2.0.53}/quantplay.egg-info/top_level.txt +0 -0
  60. {quantplay-2.0.51 → quantplay-2.0.53}/setup.cfg +0 -0
  61. {quantplay-2.0.51 → quantplay-2.0.53}/tests/__init__.py +0 -0
  62. {quantplay-2.0.51 → quantplay-2.0.53}/tests/conftest.py +0 -0
  63. {quantplay-2.0.51 → quantplay-2.0.53}/tests/wrapper/__init__.py +0 -0
  64. {quantplay-2.0.51 → quantplay-2.0.53}/tests/wrapper/aws/__init__.py +0 -0
  65. {quantplay-2.0.51 → quantplay-2.0.53}/tests/wrapper/aws/s3_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantplay
3
- Version: 2.0.51
3
+ Version: 2.0.53
4
4
  Summary: This python package will be stored in AWS CodeArtifact
5
5
  Home-page:
6
6
  Author:
@@ -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"],
@@ -250,7 +250,7 @@ class Broker(ABC):
250
250
  positions = self.positions()
251
251
  pnl = positions["pnl"].sum()
252
252
 
253
- positions = positions[positions["product"] != "CNC"]
253
+ positions = positions.filter(pl.col("product") != "CNC")
254
254
  if keep_hedges:
255
255
  positions = positions.filter(
256
256
  (~pl.col("option_type").is_in(["CE", "PE"])) & (pl.col("quantity").gt(0))
@@ -953,7 +953,7 @@ class Broker(ABC):
953
953
  drop_cnc (bool, optional): CNC positions to be dropped or not. Defaults to True.
954
954
 
955
955
  Returns:
956
- pd.DataFrame: returns user positions
956
+ pl.DataFrame: returns user positions
957
957
  """
958
958
  ...
959
959
 
@@ -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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantplay
3
- Version: 2.0.51
3
+ Version: 2.0.53
4
4
  Summary: This python package will be stored in AWS CodeArtifact
5
5
  Home-page:
6
6
  Author:
@@ -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.51",
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