quantplay 2.0.151__tar.gz → 2.0.161__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.151 → quantplay-2.0.161}/PKG-INFO +1 -1
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/icici_direct.py +32 -21
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/kotak.py +173 -18
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay.egg-info/PKG-INFO +1 -1
- {quantplay-2.0.151 → quantplay-2.0.161}/setup.py +1 -1
- {quantplay-2.0.151 → quantplay-2.0.161}/README.md +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/pyproject.toml +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/aliceblue.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/angelone.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/auto_login/aliceblue.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/breeze/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/breeze/breeze_utils.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/broker_factory.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/dhan.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/five_paisa.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/ft_utils/ft_noren.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/generics/broker.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/jainam_xts.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/motilal.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/noren.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/uplink/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/upstox.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/xts.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/xts_utils/Connect.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/xts_utils/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/zerodha.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/model/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/model/broker.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/model/broker_response.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/model/generics.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/model/instrument_data.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/model/order_event.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/py.typed +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/utils/caching.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/utils/constant.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/wrapper/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay/wrapper/aws/s3.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay.egg-info/SOURCES.txt +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/setup.cfg +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/tests/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/tests/conftest.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/tests/wrapper/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.151 → quantplay-2.0.161}/tests/wrapper/aws/s3_test.py +0 -0
|
@@ -146,12 +146,12 @@ class ICICI(Broker):
|
|
|
146
146
|
|
|
147
147
|
return self.quantplay_symbol_map[symbol]
|
|
148
148
|
|
|
149
|
-
def
|
|
149
|
+
def orders_by_exchange(self, exchange: ExchangeType):
|
|
150
150
|
to_date = datetime.now().isoformat()[:19] + ".000Z"
|
|
151
151
|
from_date = (datetime.now() - timedelta(hours=10)).isoformat()[:19] + ".000Z"
|
|
152
152
|
|
|
153
153
|
orders: Dict[str, Any] = self.wrapper.get_order_list( # type:ignore
|
|
154
|
-
exchange_code=
|
|
154
|
+
exchange_code=exchange,
|
|
155
155
|
from_date=from_date,
|
|
156
156
|
to_date=to_date,
|
|
157
157
|
)
|
|
@@ -230,20 +230,21 @@ class ICICI(Broker):
|
|
|
230
230
|
|
|
231
231
|
return orders_df
|
|
232
232
|
|
|
233
|
+
def orders(self, tag: str | None = None, add_ltp: bool = True) -> pl.DataFrame:
|
|
234
|
+
nfo_orders = self.orders_by_exchange("NFO")
|
|
235
|
+
bfo_orders = self.orders_by_exchange("BFO")
|
|
236
|
+
|
|
237
|
+
return pl.concat([nfo_orders, bfo_orders])
|
|
238
|
+
|
|
233
239
|
def positions(self, drop_cnc: bool = True) -> pl.DataFrame:
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
positions: Dict[str, Any] = self.wrapper.get_portfolio_holdings( # type:ignore
|
|
237
|
-
exchange_code="NFO",
|
|
238
|
-
from_date=from_date,
|
|
239
|
-
to_date=to_date,
|
|
240
|
-
stock_code="",
|
|
241
|
-
portfolio_type="",
|
|
242
|
-
)
|
|
240
|
+
positions: Dict[str, Any] = self.wrapper.get_portfolio_positions() # type:ignore
|
|
241
|
+
|
|
243
242
|
if "Success" in positions and positions["Success"] is None:
|
|
244
243
|
return pl.DataFrame(schema=self.positions_schema)
|
|
245
244
|
positions_df = pl.DataFrame(positions["Success"])
|
|
246
|
-
|
|
245
|
+
if "realized_profit" not in positions_df:
|
|
246
|
+
positions_df = positions_df.with_columns(pl.lit(0.0).alias("realized_profit"))
|
|
247
|
+
positions_df = positions_df.filter(pl.col("exchange_code").is_in(["NFO", "BFO"]))
|
|
247
248
|
positions_df = positions_df.rename(
|
|
248
249
|
{
|
|
249
250
|
"exchange_code": "exchange",
|
|
@@ -252,6 +253,9 @@ class ICICI(Broker):
|
|
|
252
253
|
"product_type": "product",
|
|
253
254
|
}
|
|
254
255
|
)
|
|
256
|
+
positions_df = positions_df.with_columns(
|
|
257
|
+
pl.col("quantity").cast(pl.Int32).alias("quantity")
|
|
258
|
+
)
|
|
255
259
|
positions_df = positions_df.with_columns(
|
|
256
260
|
pl.col("strike").cast(pl.Float32).alias("strike"),
|
|
257
261
|
pl.col("expiry").str.strptime(pl.Date, format="%d-%b-%Y").alias("expiry"),
|
|
@@ -260,11 +264,11 @@ class ICICI(Broker):
|
|
|
260
264
|
.when(pl.col("right") == "Put")
|
|
261
265
|
.then(pl.lit("PE"))
|
|
262
266
|
.alias("instrument_type"),
|
|
263
|
-
(
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
pl.
|
|
267
|
+
pl.when(pl.col("action") == "Sell")
|
|
268
|
+
.then(abs(pl.col("quantity").cast(pl.Float32)) * -1)
|
|
269
|
+
.otherwise(abs(pl.col("quantity").cast(pl.Float32)))
|
|
270
|
+
.alias("quantity"),
|
|
271
|
+
pl.lit(0).alias("pnl"),
|
|
268
272
|
pl.col("average_price").cast(pl.Float32).alias("average_price"),
|
|
269
273
|
)
|
|
270
274
|
|
|
@@ -341,9 +345,14 @@ class ICICI(Broker):
|
|
|
341
345
|
if tag is None:
|
|
342
346
|
tag = ""
|
|
343
347
|
icici_tradingsymbol = self.get_symbol(tradingsymbol)
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
348
|
+
try:
|
|
349
|
+
symbol_data: Dict[str, Any] = self.symbol_data[ # type:ignore
|
|
350
|
+
f"{exchange}:{icici_tradingsymbol}"
|
|
351
|
+
]
|
|
352
|
+
except KeyError:
|
|
353
|
+
raise QuantplayOrderPlacementException(
|
|
354
|
+
f"Failed to find tradingsymbol {tradingsymbol}"
|
|
355
|
+
)
|
|
347
356
|
icici_product = "cash"
|
|
348
357
|
if exchange in ["NFO", "BFO"]:
|
|
349
358
|
icici_product = "futures"
|
|
@@ -365,7 +374,7 @@ class ICICI(Broker):
|
|
|
365
374
|
else:
|
|
366
375
|
response: Dict[str, Any] = self.wrapper.place_order( # type:ignore
|
|
367
376
|
stock_code=symbol_data["symbol_code"],
|
|
368
|
-
exchange_code=
|
|
377
|
+
exchange_code=exchange,
|
|
369
378
|
product=icici_product,
|
|
370
379
|
action=transaction_type.lower(),
|
|
371
380
|
order_type=order_type.lower(),
|
|
@@ -380,6 +389,8 @@ class ICICI(Broker):
|
|
|
380
389
|
)
|
|
381
390
|
if "Success" in response and "order_id" in response["Success"]:
|
|
382
391
|
return response["Success"]["order_id"]
|
|
392
|
+
elif "Error" in response:
|
|
393
|
+
raise QuantplayOrderPlacementException(response["Error"])
|
|
383
394
|
else:
|
|
384
395
|
raise QuantplayOrderPlacementException(
|
|
385
396
|
f"ICICI: order placement failed {response}"
|
|
@@ -6,6 +6,7 @@ from urllib.parse import urlencode
|
|
|
6
6
|
|
|
7
7
|
import polars as pl
|
|
8
8
|
import requests
|
|
9
|
+
import urllib
|
|
9
10
|
|
|
10
11
|
from quantplay.broker.generics.broker import Broker
|
|
11
12
|
from quantplay.model.broker import (
|
|
@@ -20,6 +21,15 @@ from quantplay.model.generics import (
|
|
|
20
21
|
TransactionType,
|
|
21
22
|
)
|
|
22
23
|
from quantplay.model.order_event import OrderUpdateEvent
|
|
24
|
+
from quantplay.exception.exceptions import (
|
|
25
|
+
InvalidArgumentException,
|
|
26
|
+
BrokerException,
|
|
27
|
+
QuantplayOrderPlacementException,
|
|
28
|
+
)
|
|
29
|
+
from quantplay.utils.constant import Constants
|
|
30
|
+
from quantplay.utils.pickle_utils import InstrumentData
|
|
31
|
+
from quantplay.wrapper.aws.s3 import S3Utils
|
|
32
|
+
import uuid
|
|
23
33
|
|
|
24
34
|
PROD_BASE_URL = "https://gw-napi.kotaksecurities.com/"
|
|
25
35
|
SESSION_PROD_BASE_URL = "https://napi.kotaksecurities.com/"
|
|
@@ -59,6 +69,27 @@ class Kotak(Broker):
|
|
|
59
69
|
elif consumer_key and consumer_secret and mobilenumber and password and mpin:
|
|
60
70
|
self.login(consumer_key, consumer_secret, mobilenumber, password, mpin)
|
|
61
71
|
|
|
72
|
+
if load_instrument:
|
|
73
|
+
self.load_instrument()
|
|
74
|
+
|
|
75
|
+
def load_instrument(self, file_name: str | None = None) -> None:
|
|
76
|
+
try:
|
|
77
|
+
self.symbol_data = InstrumentData.get_instance().load_data( # type: ignore
|
|
78
|
+
"kotak_instruments"
|
|
79
|
+
)
|
|
80
|
+
Constants.logger.info("[LOADING_INSTRUMENTS] loading data from cache")
|
|
81
|
+
except Exception:
|
|
82
|
+
inst_data_df = S3Utils.get_parquet(
|
|
83
|
+
"quantplay-market-data/symbol_data/kotak_instruments.parquet"
|
|
84
|
+
)
|
|
85
|
+
inst_data_df = inst_data_df.with_columns(
|
|
86
|
+
pl.col("tradingsymbol").alias("broker_symbol")
|
|
87
|
+
)
|
|
88
|
+
self.instrument_data = inst_data_df
|
|
89
|
+
self.initialize_symbol_data_v2(save_as="kotak_instruments")
|
|
90
|
+
|
|
91
|
+
self.initialize_broker_symbol_map()
|
|
92
|
+
|
|
62
93
|
def login(
|
|
63
94
|
self,
|
|
64
95
|
consumer_key: str,
|
|
@@ -83,7 +114,7 @@ class Kotak(Broker):
|
|
|
83
114
|
)
|
|
84
115
|
|
|
85
116
|
if not session_init.ok:
|
|
86
|
-
raise
|
|
117
|
+
raise InvalidArgumentException(json.loads(session_init.content))
|
|
87
118
|
|
|
88
119
|
json_resp = json.loads(session_init.text)
|
|
89
120
|
self.configuration["bearer_token"] = json_resp.get("access_token")
|
|
@@ -146,6 +177,11 @@ class Kotak(Broker):
|
|
|
146
177
|
Return the Token in a String Format
|
|
147
178
|
"""
|
|
148
179
|
|
|
180
|
+
def order_history(self, order_id: str):
|
|
181
|
+
body = {"nOrdNo": order_id}
|
|
182
|
+
order_history = self.request("order_history", body=body)["data"] # type:ignore
|
|
183
|
+
return pl.DataFrame(order_history)
|
|
184
|
+
|
|
149
185
|
# **
|
|
150
186
|
# ** GET Api's
|
|
151
187
|
# **
|
|
@@ -187,6 +223,7 @@ class Kotak(Broker):
|
|
|
187
223
|
pl.col("order_timestamp")
|
|
188
224
|
.str.strptime(pl.Datetime(time_unit="ms"), format="%d-%b-%Y %H:%M:%S")
|
|
189
225
|
.alias("order_timestamp"),
|
|
226
|
+
pl.col("status").str.to_uppercase().alias("status"),
|
|
190
227
|
)
|
|
191
228
|
orders_df = orders_df.with_columns(
|
|
192
229
|
pl.col("order_timestamp").alias("update_timestamp"),
|
|
@@ -228,15 +265,79 @@ class Kotak(Broker):
|
|
|
228
265
|
return orders_df
|
|
229
266
|
|
|
230
267
|
def positions(self, drop_cnc: bool = True) -> pl.DataFrame:
|
|
231
|
-
positions_resp = self.request("
|
|
268
|
+
positions_resp = self.request("positions")
|
|
232
269
|
|
|
233
270
|
if positions_resp["stat"] == "Not_Ok" and positions_resp["errMsg"] == "No Data":
|
|
234
271
|
return pl.DataFrame(schema=self.positions_schema)
|
|
272
|
+
positions_df = pl.DataFrame(positions_resp["data"])
|
|
273
|
+
|
|
274
|
+
positions_df = positions_df.rename(
|
|
275
|
+
{
|
|
276
|
+
"trdSym": "tradingsymbol",
|
|
277
|
+
"buyAmt": "buy_value",
|
|
278
|
+
"sellAmt": "sell_value",
|
|
279
|
+
"prod": "product",
|
|
280
|
+
"tok": "token",
|
|
281
|
+
"exSeg": "exchange",
|
|
282
|
+
"optTp": "option_type",
|
|
283
|
+
}
|
|
284
|
+
)
|
|
285
|
+
positions_df = positions_df.with_columns(
|
|
286
|
+
(
|
|
287
|
+
pl.col("flBuyQty").fill_null(0).cast(pl.Int64)
|
|
288
|
+
+ pl.col("cfBuyQty").fill_null(0).cast(pl.Int64)
|
|
289
|
+
).alias("buy_quantity"),
|
|
290
|
+
(
|
|
291
|
+
pl.col("flSellQty").fill_null(0).cast(pl.Int64)
|
|
292
|
+
+ pl.col("cfSellQty").fill_null(0).cast(pl.Int64)
|
|
293
|
+
).alias("sell_quantity"),
|
|
294
|
+
pl.lit(None).alias("ltp"),
|
|
295
|
+
pl.lit(None).alias("pnl"),
|
|
296
|
+
pl.when(pl.col("exchange") == "nse_cm")
|
|
297
|
+
.then(pl.lit("NSE"))
|
|
298
|
+
.when(pl.col("exchange") == "bse_cm")
|
|
299
|
+
.then(pl.lit("BSE"))
|
|
300
|
+
.when(pl.col("exchange") == "nse_fo")
|
|
301
|
+
.then(pl.lit("NFO"))
|
|
302
|
+
.when(pl.col("exchange") == "bse_fo")
|
|
303
|
+
.then(pl.lit("BFO"))
|
|
304
|
+
.when(pl.col("exchange") == "cde_fo")
|
|
305
|
+
.then(pl.lit("CDS"))
|
|
306
|
+
.when(pl.col("exchange") == "bcs-fo")
|
|
307
|
+
.then(pl.lit("BCD"))
|
|
308
|
+
.when(pl.col("exchange") == "mcx")
|
|
309
|
+
.then(pl.lit("MCX"))
|
|
310
|
+
.otherwise(pl.col("exchange"))
|
|
311
|
+
.alias("exchange"),
|
|
312
|
+
pl.when(pl.col("option_type") == "XX")
|
|
313
|
+
.then(pl.lit(None))
|
|
314
|
+
.otherwise(pl.col("option_type"))
|
|
315
|
+
.alias("option_type"),
|
|
316
|
+
)
|
|
317
|
+
positions_df = positions_df.with_columns(
|
|
318
|
+
(pl.col("buy_quantity") - pl.col("sell_quantity")).alias("quantity")
|
|
319
|
+
)
|
|
320
|
+
positions_df = positions_df.with_columns(
|
|
321
|
+
(
|
|
322
|
+
(
|
|
323
|
+
pl.col("buy_value").cast(pl.Float32)
|
|
324
|
+
- pl.col("sell_value").cast(pl.Float32)
|
|
325
|
+
)
|
|
326
|
+
/ pl.col("quantity")
|
|
327
|
+
).alias("average_price")
|
|
328
|
+
)
|
|
329
|
+
positions_df = positions_df[list(self.positions_schema.keys())].cast(
|
|
330
|
+
self.positions_schema
|
|
331
|
+
)
|
|
332
|
+
return positions_df
|
|
333
|
+
|
|
334
|
+
def trades(self) -> pl.DataFrame:
|
|
335
|
+
self.request("trade_report")
|
|
235
336
|
|
|
236
337
|
return pl.DataFrame(schema=self.positions_schema)
|
|
237
338
|
|
|
238
339
|
def holdings(self) -> pl.DataFrame:
|
|
239
|
-
holdings_resp = self.request("
|
|
340
|
+
holdings_resp = self.request("holdings")
|
|
240
341
|
|
|
241
342
|
if holdings_resp["stat"] == "Not_Ok" and holdings_resp["errMsg"] == "No Data":
|
|
242
343
|
return pl.DataFrame(schema=self.holidings_schema)
|
|
@@ -289,18 +390,25 @@ class Kotak(Broker):
|
|
|
289
390
|
"qt": str(quantity),
|
|
290
391
|
"rt": "DAY",
|
|
291
392
|
"tp": str(trigger_price or "0"),
|
|
292
|
-
"ts": tradingsymbol,
|
|
393
|
+
"ts": self.get_symbol(tradingsymbol, exchange),
|
|
293
394
|
"tt": self.get_transaction_type(transaction_type),
|
|
294
|
-
"ig":
|
|
395
|
+
"ig": str(uuid.uuid4()),
|
|
295
396
|
}
|
|
296
397
|
|
|
297
|
-
place_order_resp = self.request(
|
|
398
|
+
place_order_resp = self.request( # type:ignore
|
|
399
|
+
"place_order", body=place_order_body
|
|
400
|
+
) # type:ignore
|
|
298
401
|
print(place_order_resp)
|
|
299
402
|
|
|
300
|
-
|
|
403
|
+
if place_order_resp["stat"] == "Not_Ok":
|
|
404
|
+
raise QuantplayOrderPlacementException(place_order_resp["errMsg"])
|
|
405
|
+
|
|
406
|
+
return place_order_resp["nOrdNo"]
|
|
301
407
|
|
|
302
408
|
def cancel_order(self, order_id: str, variety: str | None = None) -> None:
|
|
303
|
-
|
|
409
|
+
body = {"on": order_id, "am": "No"}
|
|
410
|
+
|
|
411
|
+
self.request("cancel_order", body=body)
|
|
304
412
|
|
|
305
413
|
def modify_order(self, order: ModifyOrderRequest) -> str:
|
|
306
414
|
return ""
|
|
@@ -339,6 +447,34 @@ class Kotak(Broker):
|
|
|
339
447
|
|
|
340
448
|
return exchange_segment_map.get(exchange, exchange)
|
|
341
449
|
|
|
450
|
+
def get_quantplay_exchange(self, exchange: str) -> str:
|
|
451
|
+
exchange_segment_map: dict[str, str] = {
|
|
452
|
+
"nse_cm": "NSE",
|
|
453
|
+
"bse_cm": "BSE",
|
|
454
|
+
"nse_fo": "NFO",
|
|
455
|
+
"bse_fo": "BFO",
|
|
456
|
+
"cde_fo": "CDS",
|
|
457
|
+
"mcx": "MCX",
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return exchange_segment_map.get(exchange, exchange)
|
|
461
|
+
|
|
462
|
+
def get_lot_size(self, exchange: str, tradingsymbol: str):
|
|
463
|
+
tradingsymbol = self.get_quantplay_symbol(tradingsymbol)
|
|
464
|
+
exchange = self.get_quantplay_exchange(exchange)
|
|
465
|
+
|
|
466
|
+
try:
|
|
467
|
+
return int(
|
|
468
|
+
self.symbol_data["{}:{}".format(exchange, tradingsymbol)]["lot_size"]
|
|
469
|
+
)
|
|
470
|
+
except Exception as e:
|
|
471
|
+
Constants.logger.error(
|
|
472
|
+
"[GET_LOT_SIZE] unable to get lot size for {} {}".format(
|
|
473
|
+
exchange, tradingsymbol
|
|
474
|
+
)
|
|
475
|
+
)
|
|
476
|
+
raise e
|
|
477
|
+
|
|
342
478
|
def get_product(self, product: ProductType) -> str:
|
|
343
479
|
product_map: dict[ProductType, str] = {
|
|
344
480
|
"NRML": "NRML",
|
|
@@ -348,6 +484,21 @@ class Kotak(Broker):
|
|
|
348
484
|
|
|
349
485
|
return product_map.get(product, product)
|
|
350
486
|
|
|
487
|
+
def get_symbol(self, symbol: str, exchange: ExchangeType | None = None):
|
|
488
|
+
if exchange == "NSE":
|
|
489
|
+
if symbol in ["NIFTY", "BANKNIFTY"]:
|
|
490
|
+
return symbol
|
|
491
|
+
if "-EQ" not in symbol:
|
|
492
|
+
return f"{symbol}-EQ"
|
|
493
|
+
else:
|
|
494
|
+
return symbol
|
|
495
|
+
if exchange == "BSE":
|
|
496
|
+
return symbol
|
|
497
|
+
|
|
498
|
+
if symbol not in self.quantplay_symbol_map:
|
|
499
|
+
return symbol
|
|
500
|
+
return self.quantplay_symbol_map[symbol]
|
|
501
|
+
|
|
351
502
|
# **
|
|
352
503
|
# ** Kotak Utils
|
|
353
504
|
# **
|
|
@@ -375,7 +526,7 @@ class Kotak(Broker):
|
|
|
375
526
|
"place_order": ("Orders/2.0/quick/order/rule/ms/place", "POST", False),
|
|
376
527
|
"cancel_order": ("Orders/2.0/quick/order/cancel", "POST", False),
|
|
377
528
|
"modify_order": ("Orders/2.0/quick/order/vr/modify", "POST", False),
|
|
378
|
-
"order_history": ("Orders/2.0/quick/order/history", "
|
|
529
|
+
"order_history": ("Orders/2.0/quick/order/history", "POST", False),
|
|
379
530
|
"order_book": ("Orders/2.0/quick/user/orders", "GET", True),
|
|
380
531
|
"trade_report": ("Orders/2.0/quick/user/trades", "GET", True),
|
|
381
532
|
"positions": ("Orders/2.0/quick/user/positions", "GET", True),
|
|
@@ -406,23 +557,26 @@ class Kotak(Broker):
|
|
|
406
557
|
|
|
407
558
|
query_params = {"sId": self.configuration["serverId"]}
|
|
408
559
|
if item == "place_order":
|
|
409
|
-
|
|
410
|
-
request_headers["neo-fin-key"] = "neotradeapi"
|
|
560
|
+
request_headers.pop("accept", None)
|
|
411
561
|
|
|
412
562
|
request_body = None
|
|
413
|
-
request_params = None
|
|
414
563
|
|
|
415
564
|
if params is not None:
|
|
416
565
|
request_params = urlencode({**params, **query_params})
|
|
417
566
|
else:
|
|
418
567
|
request_params = urlencode(query_params)
|
|
419
568
|
|
|
569
|
+
request_body = {}
|
|
420
570
|
if body is not None:
|
|
421
571
|
if content_type == "application/json":
|
|
422
572
|
request_body = json.dumps(body)
|
|
423
|
-
|
|
573
|
+
elif item in ["place_order"]:
|
|
574
|
+
request_body["jData"] = json.dumps(body)
|
|
424
575
|
elif content_type == "application/x-www-form-urlencoded":
|
|
425
|
-
request_body =
|
|
576
|
+
request_body = urllib.parse.urlencode( # type:ignore
|
|
577
|
+
{"jData": json.dumps(body)},
|
|
578
|
+
quote_via=urllib.parse.quote, # type:ignore
|
|
579
|
+
)
|
|
426
580
|
|
|
427
581
|
resp = None
|
|
428
582
|
resp_data = None
|
|
@@ -431,17 +585,18 @@ class Kotak(Broker):
|
|
|
431
585
|
resp = requests.get(url=url, params=request_params, headers=request_headers)
|
|
432
586
|
|
|
433
587
|
elif method == "POST":
|
|
588
|
+
url += "?" + urlencode(query_params)
|
|
589
|
+
|
|
434
590
|
resp = requests.post(
|
|
435
|
-
url
|
|
591
|
+
url,
|
|
436
592
|
headers=request_headers,
|
|
437
|
-
data=request_body,
|
|
438
|
-
params=request_params,
|
|
593
|
+
data=request_body, # type:ignore
|
|
439
594
|
)
|
|
440
595
|
|
|
441
596
|
if resp and resp.ok:
|
|
442
597
|
resp_data = resp.json()
|
|
443
598
|
|
|
444
599
|
if resp_data is None:
|
|
445
|
-
raise
|
|
600
|
+
raise BrokerException("Request Failed: No response from Kotak server")
|
|
446
601
|
|
|
447
602
|
return resp_data
|
|
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
|
|
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
|
|
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
|
{quantplay-2.0.151 → quantplay-2.0.161}/quantplay/broker/xts_utils/InteractiveSocketClient.py
RENAMED
|
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
|
|
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
|
|
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
|