quantplay 2.0.29__tar.gz → 2.0.30__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.29 → quantplay-2.0.30}/PKG-INFO +1 -1
  2. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/aliceblue.py +28 -13
  3. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/motilal.py +8 -5
  4. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/noren.py +7 -3
  5. quantplay-2.0.30/quantplay/strategies/options/intraday/__init__.py +0 -0
  6. quantplay-2.0.30/quantplay/strategies/options/intraday/ladder.py +65 -0
  7. quantplay-2.0.30/quantplay/strategies/options/intraday/musk.py +72 -0
  8. quantplay-2.0.30/quantplay/strategies/options/intraday/short_straddle.py +10 -0
  9. quantplay-2.0.30/quantplay/utils/__init__.py +0 -0
  10. quantplay-2.0.30/quantplay/wrapper/__init__.py +0 -0
  11. quantplay-2.0.30/quantplay/wrapper/aws/__init__.py +0 -0
  12. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay.egg-info/PKG-INFO +1 -1
  13. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay.egg-info/SOURCES.txt +11 -0
  14. {quantplay-2.0.29 → quantplay-2.0.30}/setup.py +1 -1
  15. quantplay-2.0.30/tests/__init__.py +0 -0
  16. quantplay-2.0.30/tests/conftest.py +0 -0
  17. quantplay-2.0.30/tests/wrapper/__init__.py +0 -0
  18. quantplay-2.0.30/tests/wrapper/aws/__init__.py +0 -0
  19. {quantplay-2.0.29 → quantplay-2.0.30}/README.md +0 -0
  20. {quantplay-2.0.29 → quantplay-2.0.30}/pyproject.toml +0 -0
  21. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/__init__.py +0 -0
  22. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/__init__.py +0 -0
  23. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/angelone.py +0 -0
  24. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/auto_login/__init__.py +0 -0
  25. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/auto_login/aliceblue.py +0 -0
  26. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/finvasia_utils/__init__.py +0 -0
  27. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
  28. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/five_paisa.py +0 -0
  29. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/flattrade.py +0 -0
  30. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/ft_utils/__init__.py +0 -0
  31. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
  32. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/ft_utils/ft_noren.py +0 -0
  33. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/generics/__init__.py +0 -0
  34. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/generics/broker.py +0 -0
  35. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/iifl_xts.py +0 -0
  36. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/kite_utils.py +0 -0
  37. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/shoonya.py +0 -0
  38. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/uplink/__init__.py +0 -0
  39. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/uplink/uplink_utils.py +0 -0
  40. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/upstox.py +0 -0
  41. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/xts.py +0 -0
  42. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/xts_utils/Connect.py +0 -0
  43. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/xts_utils/Exception.py +0 -0
  44. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
  45. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/xts_utils/__init__.py +0 -0
  46. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/broker/zerodha.py +0 -0
  47. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/exception/__init__.py +0 -0
  48. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/exception/exceptions.py +0 -0
  49. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/model/__init__.py +0 -0
  50. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/model/broker.py +0 -0
  51. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/model/generics.py +0 -0
  52. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/model/order_event.py +0 -0
  53. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/py.typed +0 -0
  54. {quantplay-2.0.29/quantplay/utils → quantplay-2.0.30/quantplay/strategies}/__init__.py +0 -0
  55. {quantplay-2.0.29/quantplay/wrapper → quantplay-2.0.30/quantplay/strategies/equities}/__init__.py +0 -0
  56. {quantplay-2.0.29/quantplay/wrapper/aws → quantplay-2.0.30/quantplay/strategies/equities/intraday}/__init__.py +0 -0
  57. {quantplay-2.0.29/tests → quantplay-2.0.30/quantplay/strategies/equities/overnight}/__init__.py +0 -0
  58. {quantplay-2.0.29/tests/wrapper → quantplay-2.0.30/quantplay/strategies/futures}/__init__.py +0 -0
  59. {quantplay-2.0.29/tests/wrapper/aws → quantplay-2.0.30/quantplay/strategies/futures/overnight}/__init__.py +0 -0
  60. /quantplay-2.0.29/tests/conftest.py → /quantplay-2.0.30/quantplay/strategies/options/__init__.py +0 -0
  61. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/utils/constant.py +0 -0
  62. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/utils/exchange.py +0 -0
  63. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/utils/number_utils.py +0 -0
  64. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/utils/pickle_utils.py +0 -0
  65. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/utils/selenium_utils.py +0 -0
  66. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay/wrapper/aws/s3.py +0 -0
  67. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay.egg-info/dependency_links.txt +0 -0
  68. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay.egg-info/requires.txt +0 -0
  69. {quantplay-2.0.29 → quantplay-2.0.30}/quantplay.egg-info/top_level.txt +0 -0
  70. {quantplay-2.0.29 → quantplay-2.0.30}/setup.cfg +0 -0
  71. {quantplay-2.0.29 → quantplay-2.0.30}/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.29
3
+ Version: 2.0.30
4
4
  Summary: This python package will be stored in AWS CodeArtifact
5
5
  Home-page:
6
6
  Author:
@@ -9,7 +9,7 @@ import polars as pl
9
9
  from pya3 import Aliceblue as Alice
10
10
  from pya3 import OrderType as AliceOrderType
11
11
  from pya3 import ProductType, TransactionType
12
- from retrying import retry # type: ignore
12
+ from retrying import retry
13
13
 
14
14
  from quantplay.broker.generics.broker import Broker
15
15
  from quantplay.exception.exceptions import (
@@ -19,8 +19,8 @@ from quantplay.exception.exceptions import (
19
19
  TokenException,
20
20
  retry_exception,
21
21
  )
22
- from quantplay.exception.exceptions import TokenException as QuantplayTokenException
23
22
  from quantplay.model.broker import ModifyOrderRequest, UserBrokerProfileResponse
23
+ from quantplay.model.generics import ExchangeType
24
24
  from quantplay.model.order_event import OrderUpdateEvent
25
25
  from quantplay.utils.constant import Constants, OrderType
26
26
  from quantplay.utils.pickle_utils import InstrumentData
@@ -94,8 +94,10 @@ class Aliceblue(Broker):
94
94
  if exchange == "NSE":
95
95
  if "-EQ" not in symbol:
96
96
  return f"{symbol}-EQ"
97
+
97
98
  elif symbol not in self.quantplay_symbol_map:
98
99
  return symbol
100
+
99
101
  return self.quantplay_symbol_map[symbol]
100
102
 
101
103
  def load_instrument(self, file_name: str | None = None):
@@ -213,11 +215,20 @@ class Aliceblue(Broker):
213
215
  exception_message = f"Order placement failed [{str(e)}]"
214
216
  raise QuantplayOrderPlacementException(exception_message)
215
217
 
216
- def ltp(self, exchange, tradingsymbol: str):
218
+ def ltp(self, exchange: ExchangeType, tradingsymbol: str) -> float:
217
219
  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
- )
220
+ try:
221
+ inst = self.invoke_aliceblue_api(
222
+ self.alice.get_instrument_by_symbol,
223
+ exchange=exchange,
224
+ symbol=tradingsymbol,
225
+ )
226
+ except Exception:
227
+ inst = self.invoke_aliceblue_api(
228
+ self.alice.get_instrument_by_symbol,
229
+ exchange=exchange,
230
+ symbol=tradingsymbol.replace("-EQ", ""),
231
+ )
221
232
  info = self.invoke_aliceblue_api(self.alice.get_scrip_info, instrument=inst)
222
233
 
223
234
  return float(info["LTP"])
@@ -308,7 +319,8 @@ class Aliceblue(Broker):
308
319
  holdings_response = self.invoke_aliceblue_api(self.alice.get_holding_positions)
309
320
 
310
321
  if (
311
- "HoldingVal" not in holdings_response
322
+ holdings_response is None
323
+ or "HoldingVal" not in holdings_response
312
324
  or len(holdings_response["HoldingVal"]) == 0
313
325
  ):
314
326
  return pl.DataFrame(schema=self.holidings_schema)
@@ -325,7 +337,9 @@ class Aliceblue(Broker):
325
337
  "HUqty": "quantity",
326
338
  },
327
339
  )
328
-
340
+ holdings_df = holdings_df.with_columns(
341
+ pl.col("tradingsymbol").str.replace("-EQ", "").alias("tradingsymbol")
342
+ )
329
343
  holdings_df = holdings_df.with_columns(pl.lit("NSE").alias("exchange"))
330
344
  holdings_df = holdings_df.with_columns(
331
345
  pl.struct(["exchange", "tradingsymbol"])
@@ -335,7 +349,6 @@ class Aliceblue(Broker):
335
349
  )
336
350
  .alias("price")
337
351
  )
338
-
339
352
  holdings_df = holdings_df.with_columns(
340
353
  pl.col("quantity").cast(pl.Int64).alias("quantity"),
341
354
  pl.col("average_price").cast(pl.Float64).alias("average_price"),
@@ -565,6 +578,11 @@ class Aliceblue(Broker):
565
578
  try:
566
579
  response = fn(*args, **kwargs)
567
580
 
581
+ if response is None:
582
+ raise InvalidArgumentException(
583
+ "Invalid data response. Aliceblue sent incorrect data, Please check."
584
+ )
585
+
568
586
  if "emsg" in response and "expired" in response["emsg"].lower():
569
587
  raise TokenException("Session expired")
570
588
  elif (
@@ -577,12 +595,9 @@ class Aliceblue(Broker):
577
595
  )
578
596
  ):
579
597
  return None
598
+
580
599
  elif "stat" in response and response["stat"].lower() == "not_ok":
581
600
  raise InvalidArgumentException(response["emsg"])
582
- if response is None:
583
- raise InvalidArgumentException(
584
- "Invalid data response. Aliceblue sent incorrect data, Please check."
585
- )
586
601
 
587
602
  return response
588
603
 
@@ -273,10 +273,10 @@ class Motilal(Broker):
273
273
  "scripcode": token,
274
274
  }
275
275
 
276
- Constants.logger.info("[GET_LTP_REQUEST] response {}".format(data))
277
- response = self.__post_request(self.ltp_url, json.dumps(data))
278
- Constants.logger.info("[GET_LTP_RESPONSE] response {}".format(response.json()))
279
- return response.json()["data"]["ltp"] / 100.0
276
+ Constants.logger.info(f"[GET_LTP_REQUEST] response {data}")
277
+ response = self.__post_request(self.ltp_url, data)
278
+ Constants.logger.info(f"[GET_LTP_RESPONSE] response {response}")
279
+ return response["data"]["ltp"] / 100.0
280
280
 
281
281
  def modify_price(
282
282
  self,
@@ -533,10 +533,13 @@ class Motilal(Broker):
533
533
  retry_on_exception=retry_exception,
534
534
  )
535
535
  def __post_request(self, url, data):
536
+ if not data:
537
+ data = {"Clientcode": self.headers["vendorinfo"]}
538
+ data = json.dumps(data)
536
539
  api_response = requests.post(
537
540
  url,
538
541
  headers=self.headers,
539
- data=json.dumps({"Clientcode": self.headers["vendorinfo"]}),
542
+ data=data,
540
543
  ).json()
541
544
 
542
545
  if api_response["status"] == "ERROR" and api_response["errorcode"] in [
@@ -251,7 +251,13 @@ class Noren(Broker):
251
251
  def ltp(self, exchange, tradingsymbol):
252
252
  tradingsymbol = self.get_symbol(tradingsymbol, exchange)
253
253
 
254
- token = self.symbol_data["{}:{}".format(exchange, tradingsymbol)]["token"]
254
+ try:
255
+ token = self.symbol_data["{}:{}".format(exchange, tradingsymbol)]["token"]
256
+ except KeyError:
257
+ token = self.symbol_data["{}:{}".format(exchange, tradingsymbol[:-3])][
258
+ "token"
259
+ ]
260
+
255
261
  quote = self.api.get_quotes(exchange, str(token))
256
262
 
257
263
  if quote is None:
@@ -300,7 +306,6 @@ class Noren(Broker):
300
306
  order_id = order_to_modify["order_id"]
301
307
  existing_details = self.order_history(order_id)
302
308
 
303
- # TODO
304
309
  order_to_modify["order_type"] = self.get_order_type(order_to_modify["order_type"]) # type: ignore
305
310
 
306
311
  if "trigger_price" not in order_to_modify:
@@ -663,7 +668,6 @@ class Noren(Broker):
663
668
  response = fn(*args, **kwargs)
664
669
  if response is None:
665
670
  return response
666
- # TODO: Verify
667
671
  if "stat" in response and "not_ok" == response["stat"].lower():
668
672
  raise TokenException(response["emsg"] if response is not None else "")
669
673
 
@@ -0,0 +1,65 @@
1
+ from quantplay.service import market
2
+ import pandas as pd
3
+ import time
4
+ from quantplay.broker.client import broker_client
5
+
6
+ backtest_date = "2022-01-20"
7
+
8
+ def load_data(data_date):
9
+ # Load data
10
+ data = market.data(interval="minute", symbols_by_security_type={"EQ": ["NIFTY BANK"]})
11
+ data = data[data.date > "{} 08:15:00".format(data_date)]
12
+ data = data[data.date < "{} 15:15:00".format(data_date)]
13
+ data.loc[:, "day_of_week"] = data.date.dt.day_name()
14
+ data = data[data.date.dt.hour < 17]
15
+
16
+ # Add additional attributes
17
+ data = market.add_expiry(data, security_type="OPT", days_offset=0)
18
+
19
+ return data
20
+
21
+ data = load_data(backtest_date)
22
+
23
+ data_seq = data.to_dict('records')
24
+
25
+ for d in data_seq:
26
+ timestamp = d['date']
27
+ broker_client.ping(timestamp)
28
+ ltp = d['open']
29
+ strike_gap = d['strike_gap']
30
+ expiry = d['expiry_date']
31
+ if timestamp.hour == 9 and timestamp.minute < 30:
32
+ print("waiting for market to cool down")
33
+ continue
34
+
35
+ if timestamp.hour > 13:
36
+ print("market is about to close, let's not place any orders")
37
+ continue
38
+
39
+ orders = broker_client.orders(tag="ladder")
40
+
41
+ if len(orders) == 0:
42
+ atm = int(round(ltp / strike_gap) * strike_gap)
43
+ pe_symbol = broker_client.option_symbol("NIFTY BANK", expiry, atm, "PE")
44
+ ce_symbol = broker_client.option_symbol("NIFTY BANK", expiry, atm, "CE")
45
+
46
+ broker_client.execute_order(
47
+ tradingsymbol=pe_symbol,
48
+ exchange="NSE",
49
+ quantity=100,
50
+ order_type='MARKET',
51
+ transaction_type='SELL',
52
+ stoploss=0.8,
53
+ tag="ladder",
54
+ product="NRML"
55
+ )
56
+ broker_client.execute_order(
57
+ tradingsymbol=ce_symbol,
58
+ exchange="NSE",
59
+ quantity=100,
60
+ order_type='MARKET',
61
+ transaction_type='SELL',
62
+ stoploss=0.8,
63
+ tag="ladder",
64
+ product="NRML"
65
+ )
@@ -0,0 +1,72 @@
1
+ from quantplay.strategy.base import QuantplayAlgorithm
2
+ from quantplay.utils.constant import TickInterval
3
+ from quantplay.service import market
4
+ from quantplay.order_execution.mean_price import MeanPriceExecutionAlgo
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+
9
+ class Musk(QuantplayAlgorithm):
10
+ def __init__(self):
11
+
12
+ # Mandatory Attributes
13
+ self.interval = TickInterval.minute
14
+ self.entry_time = "09:29"
15
+ self.exit_time = "15:15"
16
+ self.strategy_trigger_times = [self.entry_time]
17
+ self.exchange_to_trade_on = "NFO"
18
+ self.option_nearest_expiry_offset = 0
19
+ self.option_chain_depth = 0
20
+ self.backtest_after_date = "2021-01-01"
21
+ self.backtest_before_date = "2022-02-25"
22
+ self.stream_symbols_by_security_type = {"EQ": ["NIFTY BANK"]}
23
+ self.columns_for_uuid = ["date", "symbol"]
24
+ self.exact_number_of_orders_per_uuid = 2
25
+ self.strategy_type = "intraday"
26
+ self.strategy_tag = "musk"
27
+ self.execution_algo = MeanPriceExecutionAlgo(7)
28
+
29
+ self.data_required_for_days = 20
30
+
31
+ super(Musk, self).__init__()
32
+
33
+ def get_trades(self, market_data):
34
+ equity_data = market_data[(market_data.security_type == "EQ") & (market_data.symbol != "SBIN")]
35
+
36
+ unique_equity_symbols = list(equity_data.symbol.unique())
37
+ assert len(unique_equity_symbols) == 2
38
+ assert set(unique_equity_symbols) == {"NIFTY 50", "NIFTY BANK"}
39
+
40
+ trades = market.get_trades(equity_data, self.entry_time)
41
+
42
+ trades = self.add_expiry(trades, security_type="OPT")
43
+ trades.to_csv("/tmp/{}.csv".format(self.strategy_tag))
44
+ trades = trades[trades.date.dt.year >= 2019]
45
+
46
+ trades = trades[trades.strike_gap > 0]
47
+ trades.loc[:, "atm_price"] = (
48
+ round(trades.close / trades.strike_gap) * trades.strike_gap
49
+ )
50
+ trades.loc[:, "atm_price"] = trades.atm_price.astype(int)
51
+
52
+ pe_trades = market.option_symbol(
53
+ trades, price_column="atm_price", option_type="PE"
54
+ )
55
+ ce_trades = market.option_symbol(
56
+ trades, price_column="atm_price", option_type="CE"
57
+ )
58
+
59
+ trades = pd.concat([pe_trades, ce_trades])
60
+
61
+ trades.loc[:, "day_of_week"] = trades.date.dt.day_name()
62
+ trades = trades[trades.day_of_week.isin(["Monday", "Tuesday", "Wednesday", "Thursday"])]
63
+
64
+ trades.loc[:, "transaction_type"] = "SELL"
65
+ trades.loc[:, "stoploss"] = np.where(trades.symbol == "NIFTY 50", 0.5, 0.8)
66
+ trades.loc[:, "quantity"] = np.where(trades.symbol == "NIFTY 50", 100, 50)
67
+
68
+ trades = self.filter_uuids_not_matching_count(trades)
69
+
70
+ return trades
71
+
72
+
@@ -0,0 +1,10 @@
1
+ from quantplay.service import market
2
+
3
+ market.broker.execute_order(tradingsymbol="SBIN",
4
+ exchange="NSE",
5
+ quantity=1,
6
+ order_type="MARKET",
7
+ transaction_type="BUY",
8
+ stoploss=0.03,
9
+ tag='straddle',
10
+ product="MIS")
File without changes
File without changes
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantplay
3
- Version: 2.0.29
3
+ Version: 2.0.30
4
4
  Summary: This python package will be stored in AWS CodeArtifact
5
5
  Home-page:
6
6
  Author:
@@ -42,6 +42,17 @@ quantplay/model/__init__.py
42
42
  quantplay/model/broker.py
43
43
  quantplay/model/generics.py
44
44
  quantplay/model/order_event.py
45
+ quantplay/strategies/__init__.py
46
+ quantplay/strategies/equities/__init__.py
47
+ quantplay/strategies/equities/intraday/__init__.py
48
+ quantplay/strategies/equities/overnight/__init__.py
49
+ quantplay/strategies/futures/__init__.py
50
+ quantplay/strategies/futures/overnight/__init__.py
51
+ quantplay/strategies/options/__init__.py
52
+ quantplay/strategies/options/intraday/__init__.py
53
+ quantplay/strategies/options/intraday/ladder.py
54
+ quantplay/strategies/options/intraday/musk.py
55
+ quantplay/strategies/options/intraday/short_straddle.py
45
56
  quantplay/utils/__init__.py
46
57
  quantplay/utils/constant.py
47
58
  quantplay/utils/exchange.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.29",
24
+ version="2.0.30",
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
File without changes
File without changes