quantplay 2.0.26__tar.gz → 2.0.28__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 (71) hide show
  1. {quantplay-2.0.26 → quantplay-2.0.28}/PKG-INFO +1 -1
  2. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/aliceblue.py +14 -8
  3. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/angelone.py +17 -64
  4. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/five_paisa.py +2 -0
  5. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/motilal.py +4 -9
  6. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/noren.py +2 -0
  7. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/upstox.py +2 -0
  8. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/xts.py +2 -0
  9. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/zerodha.py +2 -0
  10. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay.egg-info/PKG-INFO +1 -1
  11. {quantplay-2.0.26 → quantplay-2.0.28}/setup.py +1 -1
  12. {quantplay-2.0.26 → quantplay-2.0.28}/README.md +0 -0
  13. {quantplay-2.0.26 → quantplay-2.0.28}/pyproject.toml +0 -0
  14. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/__init__.py +0 -0
  15. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/__init__.py +0 -0
  16. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/auto_login/__init__.py +0 -0
  17. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/auto_login/aliceblue.py +0 -0
  18. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/finvasia_utils/__init__.py +0 -0
  19. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
  20. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/flattrade.py +0 -0
  21. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/ft_utils/__init__.py +0 -0
  22. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
  23. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/ft_utils/ft_noren.py +0 -0
  24. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/generics/__init__.py +0 -0
  25. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/generics/broker.py +0 -0
  26. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/iifl_xts.py +0 -0
  27. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/kite_utils.py +0 -0
  28. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/shoonya.py +0 -0
  29. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/uplink/__init__.py +0 -0
  30. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/uplink/uplink_utils.py +0 -0
  31. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/xts_utils/Connect.py +0 -0
  32. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/xts_utils/Exception.py +0 -0
  33. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
  34. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/broker/xts_utils/__init__.py +0 -0
  35. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/exception/__init__.py +0 -0
  36. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/exception/exceptions.py +0 -0
  37. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/model/__init__.py +0 -0
  38. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/model/broker.py +0 -0
  39. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/model/generics.py +0 -0
  40. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/model/order_event.py +0 -0
  41. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/py.typed +0 -0
  42. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/__init__.py +0 -0
  43. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/equities/__init__.py +0 -0
  44. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/equities/intraday/__init__.py +0 -0
  45. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/equities/overnight/__init__.py +0 -0
  46. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/futures/__init__.py +0 -0
  47. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/futures/overnight/__init__.py +0 -0
  48. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/options/__init__.py +0 -0
  49. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/options/intraday/__init__.py +0 -0
  50. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/options/intraday/ladder.py +0 -0
  51. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/options/intraday/musk.py +0 -0
  52. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/strategies/options/intraday/short_straddle.py +0 -0
  53. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/utils/__init__.py +0 -0
  54. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/utils/constant.py +0 -0
  55. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/utils/exchange.py +0 -0
  56. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/utils/number_utils.py +0 -0
  57. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/utils/pickle_utils.py +0 -0
  58. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/utils/selenium_utils.py +0 -0
  59. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/wrapper/__init__.py +0 -0
  60. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/wrapper/aws/__init__.py +0 -0
  61. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay/wrapper/aws/s3.py +0 -0
  62. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay.egg-info/SOURCES.txt +0 -0
  63. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay.egg-info/dependency_links.txt +0 -0
  64. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay.egg-info/requires.txt +0 -0
  65. {quantplay-2.0.26 → quantplay-2.0.28}/quantplay.egg-info/top_level.txt +0 -0
  66. {quantplay-2.0.26 → quantplay-2.0.28}/setup.cfg +0 -0
  67. {quantplay-2.0.26 → quantplay-2.0.28}/tests/__init__.py +0 -0
  68. {quantplay-2.0.26 → quantplay-2.0.28}/tests/conftest.py +0 -0
  69. {quantplay-2.0.26 → quantplay-2.0.28}/tests/wrapper/__init__.py +0 -0
  70. {quantplay-2.0.26 → quantplay-2.0.28}/tests/wrapper/aws/__init__.py +0 -0
  71. {quantplay-2.0.26 → quantplay-2.0.28}/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.26
3
+ Version: 2.0.28
4
4
  Summary: This python package will be stored in AWS CodeArtifact
5
5
  Home-page:
6
6
  Author:
@@ -214,7 +214,10 @@ class Aliceblue(Broker):
214
214
  raise QuantplayOrderPlacementException(exception_message)
215
215
 
216
216
  def ltp(self, exchange, tradingsymbol: str):
217
- inst = self.alice.get_instrument_by_symbol(exchange, tradingsymbol)
217
+ tradingsymbol = self.get_symbol(tradingsymbol, exchange=exchange)
218
+ inst = self.invoke_aliceblue_api(
219
+ self.alice.get_instrument_by_symbol, exchange=exchange, symbol=tradingsymbol
220
+ )
218
221
  info = self.invoke_aliceblue_api(self.alice.get_scrip_info, instrument=inst)
219
222
 
220
223
  return float(info["LTP"])
@@ -453,6 +456,8 @@ class Aliceblue(Broker):
453
456
  orders_df = orders_df.join(
454
457
  positions.select(["tradingsymbol", "ltp"]), on="tradingsymbol", how="left"
455
458
  )
459
+ else:
460
+ orders_df = orders_df.with_columns(pl.lit(None).cast(pl.Float64).alias("ltp"))
456
461
 
457
462
  if "rorgqty" in orders_df.columns:
458
463
  orders_df = orders_df.with_columns(
@@ -547,10 +552,6 @@ class Aliceblue(Broker):
547
552
  def margins(self):
548
553
  margins = self.invoke_aliceblue_api(self.alice.get_balance)
549
554
 
550
- if "emsg" in margins and "expired" in margins["emsg"].lower():
551
- raise TokenException("Session expired")
552
- if "stat" in margins and "not_ok" in margins["stat"].lower():
553
- raise TokenException(f"Aliceblue broker error: {margins['emsg']}")
554
555
  margins = [a for a in margins if a["segment"] == "ALL"][0]
555
556
 
556
557
  response = {
@@ -570,6 +571,11 @@ class Aliceblue(Broker):
570
571
  def invoke_aliceblue_api(self, fn: Callable, *args, **kwargs) -> Any:
571
572
  try:
572
573
  response = fn(*args, **kwargs)
574
+
575
+ if "emsg" in response and "expired" in response["emsg"].lower():
576
+ raise TokenException("Session expired")
577
+ if "stat" in response and response["stat"].lower() == "not_ok":
578
+ raise InvalidArgumentException(response["emsg"])
573
579
  if response is None:
574
580
  raise InvalidArgumentException(
575
581
  "Invalid data response. Aliceblue sent incorrect data, Please check."
@@ -577,9 +583,9 @@ class Aliceblue(Broker):
577
583
 
578
584
  return response
579
585
 
580
- except TokenException:
581
- raise QuantplayTokenException("Token Expired")
586
+ except (TokenException, InvalidArgumentException):
587
+ raise
582
588
 
583
589
  except Exception:
584
590
  traceback.print_exc()
585
- raise RetryableException("Failed to fetch user profile")
591
+ raise RetryableException("Failed to fetch data from Aliceblue")
@@ -23,7 +23,6 @@ from quantplay.exception.exceptions import (
23
23
  TokenException,
24
24
  retry_exception,
25
25
  )
26
- from quantplay.exception.exceptions import TokenException as QuantplayTokenException
27
26
  from quantplay.model.broker import ModifyOrderRequest, UserBrokerProfileResponse
28
27
  from quantplay.model.order_event import OrderUpdateEvent
29
28
  from quantplay.utils.constant import Constants, OrderType
@@ -162,11 +161,6 @@ class AngelOne(Broker):
162
161
  "Product {} not supported for trading".format(product)
163
162
  )
164
163
 
165
- @retry(
166
- wait_exponential_multiplier=3000,
167
- wait_exponential_max=10000,
168
- stop_max_attempt_number=3,
169
- )
170
164
  def ltp(self, exchange, tradingsymbol: str) -> float:
171
165
  if tradingsymbol in MarketConstants.INDEX_SYMBOL_TO_DERIVATIVE_SYMBOL_MAP:
172
166
  tradingsymbol = MarketConstants.INDEX_SYMBOL_TO_DERIVATIVE_SYMBOL_MAP[
@@ -185,11 +179,6 @@ class AngelOne(Broker):
185
179
  symboltoken=symboltoken,
186
180
  )
187
181
 
188
- if "status" in response and response["status"] is False:
189
- raise InvalidArgumentException(
190
- "Failed to fetch ltp broker error {}".format(response)
191
- )
192
-
193
182
  return response["data"]["ltp"]
194
183
 
195
184
  def place_order(
@@ -310,18 +299,8 @@ class AngelOne(Broker):
310
299
  def cancel_order(self, order_id, variety="NORMAL"):
311
300
  self.wrapper.cancelOrder(order_id=order_id, variety=variety)
312
301
 
313
- @retry(
314
- wait_exponential_multiplier=3000,
315
- wait_exponential_max=15000,
316
- stop_max_attempt_number=5,
317
- retry_on_exception=retry_exception,
318
- )
319
302
  def holdings(self):
320
- try:
321
- holdings = self.invoke_angelone_api(self.wrapper.holding)
322
- except Exception:
323
- raise RetryableException("Access Denied retrying")
324
- self.handle_exception(holdings)
303
+ holdings = self.invoke_angelone_api(self.wrapper.holding)
325
304
 
326
305
  if holdings["data"] is None or len(holdings["data"]) == 0:
327
306
  return pl.DataFrame(schema=self.holidings_schema)
@@ -350,15 +329,11 @@ class AngelOne(Broker):
350
329
  @retry(
351
330
  wait_exponential_multiplier=3000,
352
331
  wait_exponential_max=15000,
353
- stop_max_attempt_number=5,
332
+ stop_max_attempt_number=2,
354
333
  retry_on_exception=retry_exception,
355
334
  )
356
335
  def positions(self, drop_cnc: bool = True):
357
- try:
358
- positions = self.invoke_angelone_api(self.wrapper.position)
359
- except Exception:
360
- raise RetryableException("Access Denied retrying")
361
- self.handle_exception(positions)
336
+ positions = self.invoke_angelone_api(self.wrapper.position)
362
337
 
363
338
  if positions["data"] is None:
364
339
  return pl.DataFrame(schema=self.positions_schema)
@@ -427,18 +402,8 @@ class AngelOne(Broker):
427
402
  self.positions_schema
428
403
  )
429
404
 
430
- @retry(
431
- wait_exponential_multiplier=3000,
432
- wait_exponential_max=10000,
433
- stop_max_attempt_number=3,
434
- retry_on_exception=retry_exception,
435
- )
436
405
  def orders(self, tag: str | None = None, add_ltp: bool = True) -> pl.DataFrame:
437
- try:
438
- order_book = self.invoke_angelone_api(self.wrapper.orderBook)
439
- except Exception:
440
- raise RetryableException("Access Denied retrying")
441
- self.handle_exception(order_book)
406
+ order_book = self.invoke_angelone_api(self.wrapper.orderBook)
442
407
 
443
408
  if order_book["data"]:
444
409
  orders_df = pl.DataFrame(order_book["data"])
@@ -534,21 +499,10 @@ class AngelOne(Broker):
534
499
  traceback.print_exc()
535
500
  raise ServiceException("Unknown error while fetching order book [{}]")
536
501
 
537
- @retry(
538
- wait_exponential_multiplier=3000,
539
- wait_exponential_max=10000,
540
- stop_max_attempt_number=3,
541
- retry_on_exception=retry_exception,
542
- )
543
502
  def profile(self):
544
- try:
545
- profile_data = self.invoke_angelone_api(
546
- self.wrapper.getProfile, refreshToken=self.refresh_token
547
- )
548
- except Exception:
549
- raise RetryableException("Access Denied retrying")
550
-
551
- self.handle_exception(profile_data)
503
+ profile_data = self.invoke_angelone_api(
504
+ self.wrapper.getProfile, refreshToken=self.refresh_token
505
+ )
552
506
 
553
507
  profile_data = profile_data["data"]
554
508
  response: UserBrokerProfileResponse = {
@@ -559,15 +513,8 @@ class AngelOne(Broker):
559
513
 
560
514
  return response
561
515
 
562
- @retry(
563
- wait_exponential_multiplier=3000,
564
- wait_exponential_max=10000,
565
- stop_max_attempt_number=3,
566
- retry_on_exception=retry_exception,
567
- )
568
516
  def margins(self):
569
517
  api_margins = self.invoke_angelone_api(self.wrapper.rmsLimit)
570
- self.handle_exception(api_margins)
571
518
 
572
519
  if "data" in api_margins and api_margins["data"] is None:
573
520
  if "errorcode" in api_margins and api_margins["errorcode"] == "AB1004":
@@ -610,19 +557,25 @@ class AngelOne(Broker):
610
557
 
611
558
  return response
612
559
 
560
+ @retry(
561
+ wait_exponential_multiplier=3000,
562
+ wait_exponential_max=10000,
563
+ stop_max_attempt_number=3,
564
+ retry_on_exception=retry_exception,
565
+ )
613
566
  def invoke_angelone_api(self, fn: Callable, *args, **kwargs) -> Dict:
614
567
  try:
615
568
  response = fn(*args, **kwargs)
569
+ if "errorCode" in response and response["errorCode"] == "AG8001":
570
+ raise TokenException(f"{self.user_id}: Invalid Token")
616
571
  if isinstance(response, bytes):
617
572
  raise InvalidArgumentException(
618
573
  "Invalid data response. AngelOne sent incorrect data, Please check."
619
574
  )
620
575
 
621
576
  return response
622
-
623
- except TokenException:
624
- raise QuantplayTokenException("Token Expired")
625
-
577
+ except (TokenException, InvalidArgumentException):
578
+ raise
626
579
  except Exception:
627
580
  traceback.print_exc()
628
581
  raise RetryableException("Failed to fetch user profile")
@@ -413,6 +413,8 @@ class FivePaisa(Broker):
413
413
  .then(-pl.col("pnl"))
414
414
  .otherwise(pl.col("pnl"))
415
415
  )
416
+ else:
417
+ orders = orders.with_columns(pl.lit(None).cast(pl.Float64).alias("ltp"))
416
418
 
417
419
  return orders
418
420
 
@@ -89,7 +89,7 @@ class Motilal(Broker):
89
89
  self.verify_otp_url = (
90
90
  "https://{}openapi.motilaloswal.com/rest/login/v3/verifyotp".format(uat)
91
91
  )
92
- self.ltp_utl = (
92
+ self.ltp_url = (
93
93
  "https://{}openapi.motilaloswal.com/rest/report/v1/getltpdata".format(uat)
94
94
  )
95
95
  self.place_order_url = (
@@ -263,11 +263,6 @@ class Motilal(Broker):
263
263
  Constants.logger.info(response)
264
264
  return response
265
265
 
266
- @retry(
267
- wait_exponential_multiplier=3000,
268
- wait_exponential_max=10000,
269
- stop_max_attempt_number=3,
270
- )
271
266
  def ltp(self, exchange, tradingsymbol: str) -> float:
272
267
  tradingsymbol = self.get_symbol(tradingsymbol)
273
268
  token = self.symbol_data["{}:{}".format(exchange, tradingsymbol)]["token"]
@@ -279,9 +274,7 @@ class Motilal(Broker):
279
274
  }
280
275
 
281
276
  Constants.logger.info("[GET_LTP_REQUEST] response {}".format(data))
282
- response = requests.post(
283
- self.ltp_utl, headers=self.headers, data=json.dumps(data)
284
- )
277
+ response = self.__post_request(self.ltp_url, json.dumps(data))
285
278
  Constants.logger.info("[GET_LTP_RESPONSE] response {}".format(response.json()))
286
279
  return response.json()["data"]["ltp"] / 100.0
287
280
 
@@ -737,6 +730,8 @@ class Motilal(Broker):
737
730
  orders_df = orders_df.join(
738
731
  positions.select(["tradingsymbol", "ltp"]), on="tradingsymbol", how="left"
739
732
  )
733
+ else:
734
+ orders_df = orders_df.with_columns(pl.lit(None).cast(pl.Float64).alias("ltp"))
740
735
 
741
736
  orders_df = orders_df.with_columns(
742
737
  pl.when(pl.col("product") == "VALUEPLUS")
@@ -525,6 +525,8 @@ class Noren(Broker):
525
525
  orders_df = orders_df.join(
526
526
  positions.select(["tradingsymbol", "ltp"]), on="tradingsymbol", how="left"
527
527
  )
528
+ else:
529
+ orders_df = orders_df.with_columns(pl.lit(None).cast(pl.Float64).alias("ltp"))
528
530
 
529
531
  orders_df = orders_df.with_columns(pl.lit(None).alias("variety"))
530
532
 
@@ -465,6 +465,8 @@ class Upstox(Broker):
465
465
  orders_df = orders_df.join(
466
466
  positions.select(["tradingsymbol", "ltp"]), on="tradingsymbol", how="left"
467
467
  )
468
+ else:
469
+ orders_df = orders_df.with_columns(pl.lit(None).cast(pl.Float64).alias("ltp"))
468
470
  orders_df = orders_df.rename({"placed_by": "user_id"})
469
471
 
470
472
  orders_df = orders_df.with_columns(
@@ -275,6 +275,8 @@ class XTS(Broker):
275
275
  orders_df = orders_df.join(
276
276
  positions.select(["tradingsymbol", "ltp"]), on="tradingsymbol", how="left"
277
277
  )
278
+ else:
279
+ orders_df = orders_df.with_columns(pl.lit(None).cast(pl.Float64).alias("ltp"))
278
280
 
279
281
  orders_df = orders_df.with_columns(
280
282
  pl.col("filled_quantity").cast(pl.Int64).alias("filled_quantity"),
@@ -495,6 +495,8 @@ class Zerodha(Broker):
495
495
  orders_df = orders_df.join(
496
496
  positions.select(["tradingsymbol", "ltp"]), on="tradingsymbol", how="left"
497
497
  )
498
+ else:
499
+ orders_df = orders_df.with_columns(pl.lit(None).cast(pl.Float64).alias("ltp"))
498
500
 
499
501
  orders_df = orders_df.with_columns(
500
502
  (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantplay
3
- Version: 2.0.26
3
+ Version: 2.0.28
4
4
  Summary: This python package will be stored in AWS CodeArtifact
5
5
  Home-page:
6
6
  Author:
@@ -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.26",
24
+ version="2.0.28",
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