quantplay 2.0.42__tar.gz → 2.0.45__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.42 → quantplay-2.0.45}/PKG-INFO +26 -1
- {quantplay-2.0.42 → quantplay-2.0.45}/pyproject.toml +1 -1
- quantplay-2.0.45/quantplay/broker/__init__.py +25 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/aliceblue.py +13 -4
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/angelone.py +6 -3
- {quantplay-2.0.42/quantplay/broker/generics → quantplay-2.0.45/quantplay/broker}/broker_factory.py +107 -69
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/dhan.py +2 -35
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/finvasia_utils/fa_noren.py +3 -2
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/five_paisa.py +3 -5
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/flattrade.py +3 -3
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/ft_utils/ft_noren.py +3 -2
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/generics/broker.py +5 -5
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/motilal.py +16 -15
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/noren.py +7 -3
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/upstox.py +3 -3
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/xts.py +1 -1
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/xts_utils/Connect.py +1 -2
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/xts_utils/InteractiveSocketClient.py +1 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/zerodha.py +1 -1
- quantplay-2.0.45/quantplay/exception/exceptions.py +100 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/model/instrument_data.py +2 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/wrapper/aws/s3.py +4 -3
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay.egg-info/PKG-INFO +26 -1
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay.egg-info/SOURCES.txt +1 -1
- {quantplay-2.0.42 → quantplay-2.0.45}/setup.py +2 -2
- quantplay-2.0.42/quantplay/exception/exceptions.py +0 -114
- quantplay-2.0.42/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/README.md +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/__init__.py +0 -0
- {quantplay-2.0.42/quantplay/broker → quantplay-2.0.45/quantplay/broker/auto_login}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/auto_login/aliceblue.py +1 -1
- {quantplay-2.0.42/quantplay/broker/auto_login → quantplay-2.0.45/quantplay/broker/finvasia_utils}/__init__.py +0 -0
- {quantplay-2.0.42/quantplay/broker/finvasia_utils → quantplay-2.0.45/quantplay/broker/ft_utils}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.0.42/quantplay/broker/ft_utils → quantplay-2.0.45/quantplay/broker/generics}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.0.42/quantplay/broker/generics → quantplay-2.0.45/quantplay/broker/uplink}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.0.42/quantplay/broker/uplink → quantplay-2.0.45/quantplay/broker/xts_utils}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.0.42/quantplay/broker/xts_utils → quantplay-2.0.45/quantplay/model}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/model/broker.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/model/generics.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/model/order_event.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/py.typed +0 -0
- {quantplay-2.0.42/quantplay/model → quantplay-2.0.45/quantplay/utils}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/utils/caching.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/utils/constant.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/utils/pickle_utils.py +1 -1
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.0.42/quantplay/utils → quantplay-2.0.45/quantplay/wrapper}/__init__.py +0 -0
- {quantplay-2.0.42/quantplay/wrapper → quantplay-2.0.45/quantplay/wrapper/aws}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/setup.cfg +0 -0
- {quantplay-2.0.42/quantplay/wrapper/aws → quantplay-2.0.45/tests}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/tests/conftest.py +0 -0
- {quantplay-2.0.42/tests → quantplay-2.0.45/tests/wrapper}/__init__.py +0 -0
- {quantplay-2.0.42/tests/wrapper → quantplay-2.0.45/tests/wrapper/aws}/__init__.py +0 -0
- {quantplay-2.0.42 → quantplay-2.0.45}/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.
|
|
3
|
+
Version: 2.0.45
|
|
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
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .aliceblue import Aliceblue
|
|
2
|
+
from .angelone import AngelOne
|
|
3
|
+
from .broker_factory import BrokerFactory
|
|
4
|
+
from .dhan import Dhan
|
|
5
|
+
from .five_paisa import FivePaisa
|
|
6
|
+
from .flattrade import FlatTrade
|
|
7
|
+
from .iifl_xts import IIFL
|
|
8
|
+
from .motilal import Motilal
|
|
9
|
+
from .shoonya import FinvAsia
|
|
10
|
+
from .upstox import Upstox
|
|
11
|
+
from .zerodha import Zerodha
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"Aliceblue",
|
|
15
|
+
"AngelOne",
|
|
16
|
+
"BrokerFactory",
|
|
17
|
+
"Dhan",
|
|
18
|
+
"FivePaisa",
|
|
19
|
+
"FlatTrade",
|
|
20
|
+
"FinvAsia",
|
|
21
|
+
"Motilal",
|
|
22
|
+
"Zerodha",
|
|
23
|
+
"Upstox",
|
|
24
|
+
"IIFL",
|
|
25
|
+
]
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import codecs
|
|
2
2
|
import copy
|
|
3
3
|
import pickle
|
|
4
|
-
from queue import Queue
|
|
5
4
|
import traceback
|
|
5
|
+
from queue import Queue
|
|
6
6
|
from typing import Any, Dict, Literal
|
|
7
7
|
|
|
8
8
|
import polars as pl
|
|
9
9
|
from pya3 import (
|
|
10
10
|
Aliceblue as Alice,
|
|
11
|
+
)
|
|
12
|
+
from pya3 import (
|
|
11
13
|
OrderType as AliceOrderType,
|
|
12
|
-
|
|
14
|
+
)
|
|
15
|
+
from pya3 import (
|
|
13
16
|
ProductType as AliceProductType,
|
|
14
17
|
)
|
|
18
|
+
from pya3 import (
|
|
19
|
+
TransactionType as AliceTransactionType,
|
|
20
|
+
)
|
|
15
21
|
from retrying import retry # type: ignore
|
|
16
22
|
|
|
17
23
|
from quantplay.broker.generics.broker import Broker
|
|
@@ -50,8 +56,9 @@ class Aliceblue(Broker):
|
|
|
50
56
|
api_key: str | None = None,
|
|
51
57
|
order_updates: Queue[OrderUpdateEvent] | None = None,
|
|
52
58
|
client: str | None = None,
|
|
59
|
+
load_instrument: bool = True,
|
|
53
60
|
):
|
|
54
|
-
super(
|
|
61
|
+
super().__init__()
|
|
55
62
|
self.order_updates = order_updates
|
|
56
63
|
|
|
57
64
|
try:
|
|
@@ -82,7 +89,9 @@ class Aliceblue(Broker):
|
|
|
82
89
|
raise RetryableException(str(e))
|
|
83
90
|
|
|
84
91
|
self.user_id = self.alice.user_id
|
|
85
|
-
|
|
92
|
+
|
|
93
|
+
if load_instrument:
|
|
94
|
+
self.load_instrument()
|
|
86
95
|
|
|
87
96
|
def set_client(self, serialized_client: str):
|
|
88
97
|
try:
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import binascii
|
|
2
2
|
import copy
|
|
3
3
|
import json
|
|
4
|
-
from queue import Queue
|
|
5
4
|
import traceback
|
|
5
|
+
from queue import Queue
|
|
6
6
|
from typing import Any, Dict
|
|
7
7
|
|
|
8
|
-
from SmartApi.smartExceptions import DataException # type: ignore
|
|
9
8
|
import polars as pl
|
|
10
9
|
import pyotp
|
|
11
10
|
from requests.exceptions import ConnectionError, ConnectTimeout
|
|
12
11
|
from retrying import retry # type: ignore
|
|
13
12
|
from SmartApi import SmartConnect # type: ignore
|
|
13
|
+
from SmartApi.smartExceptions import DataException # type: ignore
|
|
14
14
|
|
|
15
15
|
from quantplay.broker.generics.broker import Broker
|
|
16
16
|
from quantplay.exception.exceptions import (
|
|
@@ -58,7 +58,7 @@ class AngelOne(Broker):
|
|
|
58
58
|
access_token: str | None = None,
|
|
59
59
|
load_instrument: bool = True,
|
|
60
60
|
):
|
|
61
|
-
super(
|
|
61
|
+
super().__init__()
|
|
62
62
|
self.order_updates = order_updates
|
|
63
63
|
|
|
64
64
|
try:
|
|
@@ -73,6 +73,7 @@ class AngelOne(Broker):
|
|
|
73
73
|
else:
|
|
74
74
|
if totp is None:
|
|
75
75
|
raise InvalidArgumentException("TOTP Key is Missing")
|
|
76
|
+
|
|
76
77
|
self.wrapper = SmartConnect(api_key=api_key)
|
|
77
78
|
response = self.invoke_angelone_api(
|
|
78
79
|
self.wrapper.generateSession, # type: ignore
|
|
@@ -80,10 +81,12 @@ class AngelOne(Broker):
|
|
|
80
81
|
password=mpin,
|
|
81
82
|
totp=pyotp.TOTP(totp).now(),
|
|
82
83
|
)
|
|
84
|
+
|
|
83
85
|
if response["status"] is False:
|
|
84
86
|
if "message" in response:
|
|
85
87
|
raise InvalidArgumentException(response["message"])
|
|
86
88
|
raise InvalidArgumentException("Invalid API credentials")
|
|
89
|
+
|
|
87
90
|
token_data = self.invoke_angelone_api(
|
|
88
91
|
self.wrapper.generateToken, # type: ignore
|
|
89
92
|
refresh_token=self.wrapper.refresh_token, # type: ignore
|
{quantplay-2.0.42/quantplay/broker/generics → quantplay-2.0.45/quantplay/broker}/broker_factory.py
RENAMED
|
@@ -5,7 +5,6 @@ from typing import Any, Dict
|
|
|
5
5
|
|
|
6
6
|
from quantplay.broker.aliceblue import Aliceblue
|
|
7
7
|
from quantplay.broker.angelone import AngelOne
|
|
8
|
-
|
|
9
8
|
from quantplay.broker.five_paisa import FivePaisa
|
|
10
9
|
from quantplay.broker.flattrade import FlatTrade
|
|
11
10
|
from quantplay.broker.iifl_xts import IIFL as IIFL_XTS
|
|
@@ -14,9 +13,8 @@ from quantplay.broker.shoonya import FinvAsia
|
|
|
14
13
|
from quantplay.broker.upstox import Upstox
|
|
15
14
|
from quantplay.broker.zerodha import Zerodha
|
|
16
15
|
from quantplay.exception.exceptions import InvalidArgumentException
|
|
17
|
-
|
|
18
|
-
from quantplay.utils.pickle_utils import PickleUtils
|
|
19
16
|
from quantplay.utils.caching import InstrumentCache
|
|
17
|
+
from quantplay.utils.pickle_utils import PickleUtils
|
|
20
18
|
|
|
21
19
|
BrokerType = (
|
|
22
20
|
Aliceblue
|
|
@@ -58,62 +56,47 @@ class BrokerFactory:
|
|
|
58
56
|
Broker.UPSTOX: "upstox_instruments",
|
|
59
57
|
Broker.FIVEPAISA_OPENAPI: "5paisa_instruments",
|
|
60
58
|
}
|
|
59
|
+
broker_required_args = {
|
|
60
|
+
Broker.ZERODHA: set(["user_id", "zerodha_wrapper"]),
|
|
61
|
+
Broker.FINVASIA: set(["user_id", "user_token"]),
|
|
62
|
+
Broker.FLATTRADE: set(["user_id", "user_token"]),
|
|
63
|
+
Broker.IIFL_XTS: set(["user_id", "wrapper", "md_wrapper"]),
|
|
64
|
+
Broker.MOTILAL: set(["user_id", "headers"]),
|
|
65
|
+
Broker.ALICEBLUE: set(["user_id", "client"]),
|
|
66
|
+
Broker.UPSTOX: set(["user_id", "access_token"]),
|
|
67
|
+
Broker.FIVEPAISA_OPENAPI: set(["user_id", "client"]),
|
|
68
|
+
Broker.ANGELONE: set(
|
|
69
|
+
[
|
|
70
|
+
"user_id",
|
|
71
|
+
"api_key",
|
|
72
|
+
"access_token",
|
|
73
|
+
"refresh_token",
|
|
74
|
+
"feed_token",
|
|
75
|
+
]
|
|
76
|
+
),
|
|
77
|
+
}
|
|
61
78
|
|
|
62
79
|
def __init__(self):
|
|
63
80
|
self.client_broker_data: Dict[str, BrokerType] = {}
|
|
64
81
|
|
|
65
82
|
def get_broker_key(self, username: str, broker_name: str) -> str:
|
|
66
|
-
return "{}:{}"
|
|
67
|
-
|
|
68
|
-
def set_broker_instruments(self, broker_name: str, broker: BrokerType) -> None:
|
|
69
|
-
symbol_data_key = f"{broker_name}_instruments"
|
|
70
|
-
quantplay_symbol_key = f"{broker_name}_qplay_symbols"
|
|
71
|
-
broker_symbol_key = f"{broker_name}_broker_symbols"
|
|
83
|
+
return f"{username}:{broker_name}"
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if symbol_data is not None:
|
|
78
|
-
broker.symbol_data = symbol_data
|
|
79
|
-
|
|
80
|
-
if broker_name != "Zerodha":
|
|
81
|
-
if quantplay_symbol_map is not None and broker_symbol_map is not None:
|
|
82
|
-
broker.quantplay_symbol_map = quantplay_symbol_map
|
|
83
|
-
broker.broker_symbol_map = broker_symbol_map
|
|
84
|
-
|
|
85
|
-
else:
|
|
86
|
-
broker.initialize_broker_symbol_map()
|
|
87
|
-
instrument_cache.set(
|
|
88
|
-
quantplay_symbol_key, broker.quantplay_symbol_map
|
|
89
|
-
)
|
|
90
|
-
instrument_cache.set(broker_symbol_key, broker.broker_symbol_map)
|
|
85
|
+
def validate_broker_args(self, broker_info: Dict[str, Any]):
|
|
86
|
+
broker = broker_info["broker"]
|
|
87
|
+
broker_data = broker_info["broker_data"]
|
|
91
88
|
|
|
92
|
-
|
|
89
|
+
if broker not in self.broker_required_args.keys():
|
|
90
|
+
raise InvalidArgumentException(f"Unsupported Broker: '{broker}'")
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
if not self.broker_required_args[broker].issubset(broker_data.keys()):
|
|
93
|
+
raise InvalidArgumentException(
|
|
94
|
+
f"Missing Arguments for {broker_info['username']}:{broker_info['nickname']} in broker '{broker}' -> {self.broker_required_args[broker].difference(broker_info.keys())}"
|
|
97
95
|
)
|
|
98
|
-
broker.symbol_data = symbol_data
|
|
99
|
-
|
|
100
|
-
if broker_name != "Zerodha":
|
|
101
|
-
broker.initialize_broker_symbol_map()
|
|
102
|
-
instrument_cache.set(quantplay_symbol_key, broker.quantplay_symbol_map)
|
|
103
|
-
|
|
104
|
-
instrument_cache.set(symbol_data_key, symbol_data)
|
|
105
|
-
|
|
106
|
-
except Exception:
|
|
107
|
-
traceback.print_exc()
|
|
108
|
-
|
|
109
|
-
if broker_name != "Zerodha":
|
|
110
|
-
broker.load_instrument(BrokerFactory.broker_instruments_map[broker_name])
|
|
111
|
-
else:
|
|
112
|
-
broker.initialize_symbol_data()
|
|
113
96
|
|
|
114
97
|
def store_broker_client(
|
|
115
98
|
self, broker_info: Dict[str, Any], load_instrument: bool = True
|
|
116
|
-
) -> None:
|
|
99
|
+
) -> BrokerType | None:
|
|
117
100
|
username = broker_info["username"]
|
|
118
101
|
nickname = broker_info["nickname"]
|
|
119
102
|
|
|
@@ -125,9 +108,9 @@ class BrokerFactory:
|
|
|
125
108
|
broker_client: BrokerType | None = None
|
|
126
109
|
|
|
127
110
|
if broker == "Motilal":
|
|
128
|
-
motial_headers = broker_data["headers"]
|
|
129
111
|
broker_client = Motilal(
|
|
130
|
-
headers=
|
|
112
|
+
headers=broker_data["headers"],
|
|
113
|
+
load_instrument=load_instrument,
|
|
131
114
|
)
|
|
132
115
|
|
|
133
116
|
elif broker == "Zerodha":
|
|
@@ -147,31 +130,29 @@ class BrokerFactory:
|
|
|
147
130
|
)
|
|
148
131
|
|
|
149
132
|
elif broker == Broker.ALICEBLUE:
|
|
150
|
-
broker_client = Aliceblue(
|
|
133
|
+
broker_client = Aliceblue(
|
|
134
|
+
client=broker_data["client"],
|
|
135
|
+
load_instrument=load_instrument,
|
|
136
|
+
)
|
|
151
137
|
|
|
152
138
|
elif broker == Broker.UPSTOX:
|
|
153
139
|
broker_client = Upstox(
|
|
154
140
|
access_token=broker_data["access_token"],
|
|
155
141
|
user_id=broker_data["user_id"],
|
|
142
|
+
load_instrument=load_instrument,
|
|
156
143
|
)
|
|
157
144
|
|
|
158
145
|
elif broker == Broker.FINVASIA:
|
|
159
|
-
finvasia_data = broker_data
|
|
160
146
|
broker_client = FinvAsia(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
password=finvasia_data["password"],
|
|
164
|
-
user_token=finvasia_data["user_token"],
|
|
147
|
+
user_id=broker_data["user_id"],
|
|
148
|
+
user_token=broker_data["user_token"],
|
|
165
149
|
load_instrument=load_instrument,
|
|
166
150
|
)
|
|
167
151
|
|
|
168
152
|
elif broker == Broker.FLATTRADE:
|
|
169
|
-
flattrade_data = broker_data
|
|
170
153
|
broker_client = FlatTrade(
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
password=flattrade_data["password"],
|
|
174
|
-
user_token=flattrade_data["user_token"],
|
|
154
|
+
user_id=broker_data["user_id"],
|
|
155
|
+
user_token=broker_data["user_token"],
|
|
175
156
|
load_instrument=load_instrument,
|
|
176
157
|
)
|
|
177
158
|
|
|
@@ -181,22 +162,30 @@ class BrokerFactory:
|
|
|
181
162
|
load_instrument=load_instrument,
|
|
182
163
|
)
|
|
183
164
|
|
|
184
|
-
self.client_broker_data[broker_key] = broker_client
|
|
185
|
-
|
|
186
165
|
elif broker == Broker.IIFL_XTS:
|
|
187
|
-
iifl_xts_data = broker_data
|
|
188
166
|
broker_client = IIFL_XTS(
|
|
189
167
|
wrapper=broker_data["wrapper"],
|
|
190
168
|
md_wrapper=broker_data["md_wrapper"],
|
|
191
|
-
client_id=
|
|
169
|
+
client_id=broker_data["user_id"],
|
|
192
170
|
load_instrument=load_instrument,
|
|
193
171
|
)
|
|
194
172
|
|
|
195
173
|
else:
|
|
196
|
-
raise InvalidArgumentException(f"Broker {broker} not supported")
|
|
174
|
+
raise InvalidArgumentException(f"Broker '{broker}' not supported")
|
|
175
|
+
|
|
176
|
+
if not load_instrument:
|
|
177
|
+
broker_client = self.set_broker_instruments(
|
|
178
|
+
broker_name=broker, broker=broker_client
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
broker_client.username = broker_info["username"]
|
|
182
|
+
broker_client.nickname = broker_info["nickname"]
|
|
183
|
+
broker_client.broker_name = broker_info["broker"]
|
|
184
|
+
broker_client.user_id = broker_data["user_id"]
|
|
197
185
|
|
|
198
186
|
self.client_broker_data[broker_key] = broker_client
|
|
199
|
-
|
|
187
|
+
|
|
188
|
+
return broker_client
|
|
200
189
|
|
|
201
190
|
def get_broker_client(self, broker_info: Dict[str, Any]) -> BrokerType:
|
|
202
191
|
username = broker_info["username"]
|
|
@@ -207,13 +196,62 @@ class BrokerFactory:
|
|
|
207
196
|
if broker_key in self.client_broker_data:
|
|
208
197
|
return self.client_broker_data[broker_key]
|
|
209
198
|
|
|
210
|
-
self.
|
|
199
|
+
self.validate_broker_args(broker_info)
|
|
200
|
+
broker_client = self.store_broker_client(broker_info, load_instrument=False)
|
|
211
201
|
|
|
212
|
-
if
|
|
213
|
-
return
|
|
202
|
+
if broker_client is not None:
|
|
203
|
+
return broker_client
|
|
214
204
|
else:
|
|
215
205
|
raise InvalidArgumentException("Invalid broker API configuration")
|
|
216
206
|
|
|
207
|
+
def set_broker_instruments(self, broker_name: str, broker: BrokerType) -> BrokerType:
|
|
208
|
+
symbol_data_key = f"{broker_name}_instruments"
|
|
209
|
+
quantplay_symbol_key = f"{broker_name}_qplay_symbols"
|
|
210
|
+
broker_symbol_key = f"{broker_name}_broker_symbols"
|
|
211
|
+
|
|
212
|
+
symbol_data = instrument_cache.get(symbol_data_key)
|
|
213
|
+
quantplay_symbol_map = instrument_cache.get(quantplay_symbol_key)
|
|
214
|
+
broker_symbol_map = instrument_cache.get(broker_symbol_key)
|
|
215
|
+
|
|
216
|
+
if symbol_data is not None:
|
|
217
|
+
broker.symbol_data = symbol_data
|
|
218
|
+
|
|
219
|
+
if broker_name != "Zerodha":
|
|
220
|
+
if quantplay_symbol_map is not None and broker_symbol_map is not None:
|
|
221
|
+
broker.quantplay_symbol_map = quantplay_symbol_map
|
|
222
|
+
broker.broker_symbol_map = broker_symbol_map
|
|
223
|
+
|
|
224
|
+
else:
|
|
225
|
+
broker.initialize_broker_symbol_map()
|
|
226
|
+
instrument_cache.set(
|
|
227
|
+
quantplay_symbol_key, broker.quantplay_symbol_map
|
|
228
|
+
)
|
|
229
|
+
instrument_cache.set(broker_symbol_key, broker.broker_symbol_map)
|
|
230
|
+
|
|
231
|
+
return broker
|
|
232
|
+
|
|
233
|
+
try:
|
|
234
|
+
symbol_data = PickleUtils.load_data(
|
|
235
|
+
BrokerFactory.broker_instruments_map[broker_name]
|
|
236
|
+
)
|
|
237
|
+
broker.symbol_data = symbol_data
|
|
238
|
+
|
|
239
|
+
if broker_name != "Zerodha":
|
|
240
|
+
broker.initialize_broker_symbol_map()
|
|
241
|
+
instrument_cache.set(quantplay_symbol_key, broker.quantplay_symbol_map)
|
|
242
|
+
|
|
243
|
+
instrument_cache.set(symbol_data_key, symbol_data)
|
|
244
|
+
|
|
245
|
+
except Exception:
|
|
246
|
+
traceback.print_exc()
|
|
247
|
+
|
|
248
|
+
if broker_name != "Zerodha":
|
|
249
|
+
broker.load_instrument(BrokerFactory.broker_instruments_map[broker_name])
|
|
250
|
+
else:
|
|
251
|
+
broker.initialize_symbol_data()
|
|
252
|
+
|
|
253
|
+
return broker
|
|
254
|
+
|
|
217
255
|
def clear_instrument_cache(self, broker: str) -> None:
|
|
218
256
|
symbol_data_key = f"{broker}_instruments"
|
|
219
257
|
instrument_cache.delete(symbol_data_key)
|
|
@@ -4,8 +4,7 @@ import traceback
|
|
|
4
4
|
from typing import Any, Dict, Hashable, List
|
|
5
5
|
|
|
6
6
|
import polars as pl
|
|
7
|
-
from
|
|
8
|
-
from kiteconnect.exceptions import TokenException # type: ignore
|
|
7
|
+
from dhanhq import dhanhq # type:ignore
|
|
9
8
|
from retrying import retry # type: ignore
|
|
10
9
|
|
|
11
10
|
from quantplay.broker.generics.broker import Broker
|
|
@@ -15,7 +14,6 @@ from quantplay.exception.exceptions import (
|
|
|
15
14
|
RetryableException,
|
|
16
15
|
retry_exception,
|
|
17
16
|
)
|
|
18
|
-
from quantplay.exception.exceptions import TokenException as QuantplayTokenException
|
|
19
17
|
from quantplay.model.broker import (
|
|
20
18
|
ExchangeType,
|
|
21
19
|
)
|
|
@@ -27,11 +25,11 @@ from quantplay.model.generics import (
|
|
|
27
25
|
)
|
|
28
26
|
from quantplay.utils.constant import Constants, OrderType
|
|
29
27
|
from quantplay.utils.pickle_utils import InstrumentData, PickleUtils
|
|
30
|
-
from dhanhq import dhanhq # type:ignore
|
|
31
28
|
|
|
32
29
|
|
|
33
30
|
class Dhan(Broker):
|
|
34
31
|
def __init__(self):
|
|
32
|
+
super().__init__()
|
|
35
33
|
self.dhan = dhanhq(
|
|
36
34
|
client_id="1102866282",
|
|
37
35
|
access_token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJkaGFuIiwicGFydG5lcklkIjoiIiwiZXhwIjoxNzIzODgxNjgxLCJ0b2tlbkNvbnN1bWVyVHlwZSI6IlNFTEYiLCJ3ZWJob29rVXJsIjoiIiwiZGhhbkNsaWVudElkIjoiMTEwMjg2NjI4MiJ9.0dNR4gOdIQ3KeaAokEwbRt6v_6ESn73r6yOL9-7lzphVCAmP-pahgK6OIOxVUExBJa0SaxX0TNX7Vk0RBQ-lxQ",
|
|
@@ -41,8 +39,6 @@ class Dhan(Broker):
|
|
|
41
39
|
access_token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJkaGFuIiwicGFydG5lcklkIjoiIiwiZXhwIjoxNzIxMzc3ODM5LCJ0b2tlbkNvbnN1bWVyVHlwZSI6IlNFTEYiLCJ3ZWJob29rVXJsIjoiIiwiZGhhbkNsaWVudElkIjoiMTEwMDc5OTExNiJ9.ykd4NYsnl7s1UegkUUY9tbP4OxxjqtskGi8JK0lyC9bRRPQRyxDv022JyDIl6crdFsQXfG7-6BsipPYxOtLR8g",
|
|
42
40
|
)
|
|
43
41
|
|
|
44
|
-
super(Dhan, self).__init__()
|
|
45
|
-
|
|
46
42
|
def set_wrapper(self, serialized_wrapper: str):
|
|
47
43
|
self.wrapper = pickle.loads(codecs.decode(serialized_wrapper.encode(), "base64"))
|
|
48
44
|
|
|
@@ -69,33 +65,6 @@ class Dhan(Broker):
|
|
|
69
65
|
def get_username(self):
|
|
70
66
|
return self.username
|
|
71
67
|
|
|
72
|
-
def on_ticks(self, kws: KiteTicker, ticks: Any):
|
|
73
|
-
"""Callback on live ticks"""
|
|
74
|
-
# logger.info("[TEST_TICK] {}".format(ticks))
|
|
75
|
-
pass
|
|
76
|
-
|
|
77
|
-
def on_order_update(self, kws: KiteTicker, data: Any):
|
|
78
|
-
"""Callback on order update"""
|
|
79
|
-
Constants.logger.info(f"[UPDATE_RECEIVED] {data}")
|
|
80
|
-
|
|
81
|
-
if self.order_updates is None:
|
|
82
|
-
raise Exception("Event Queue Not Initalised")
|
|
83
|
-
|
|
84
|
-
self.order_updates.put(data)
|
|
85
|
-
|
|
86
|
-
def on_connect(self, kws: KiteTicker, response: Any):
|
|
87
|
-
"""Callback on successfull connect"""
|
|
88
|
-
kws.subscribe([256265]) # type: ignore
|
|
89
|
-
kws.set_mode(kws.MODE_FULL, [256265]) # type: ignore
|
|
90
|
-
|
|
91
|
-
def stream_order_data(self):
|
|
92
|
-
kite_ticker = KiteTicker(self.wrapper.api_key, self.wrapper.access_token)
|
|
93
|
-
kite_ticker.on_order_update = self.on_order_update # type:ignore
|
|
94
|
-
kite_ticker.on_ticks = self.on_ticks # type:ignore
|
|
95
|
-
kite_ticker.on_connect = self.on_connect # type:ignore
|
|
96
|
-
|
|
97
|
-
kite_ticker.connect(threaded=True) # type: ignore
|
|
98
|
-
|
|
99
68
|
@retry(
|
|
100
69
|
wait_exponential_multiplier=3000,
|
|
101
70
|
wait_exponential_max=10000,
|
|
@@ -135,8 +104,6 @@ class Dhan(Broker):
|
|
|
135
104
|
)
|
|
136
105
|
|
|
137
106
|
return api_response[key]["last_price"]
|
|
138
|
-
except TokenException:
|
|
139
|
-
raise QuantplayTokenException("Zerodha token expired")
|
|
140
107
|
except Exception as e:
|
|
141
108
|
exception_message = "GetLtp call failed for [{}] with error [{}]".format(
|
|
142
109
|
tradingsymbol, str(e)
|
|
@@ -8,11 +8,12 @@ import urllib.parse
|
|
|
8
8
|
from datetime import datetime as dt
|
|
9
9
|
from time import sleep
|
|
10
10
|
from typing import Any, Callable, Dict, List, Literal, TypedDict
|
|
11
|
-
|
|
12
|
-
from quantplay.model.generics import ExchangeType
|
|
11
|
+
|
|
13
12
|
import requests
|
|
14
13
|
import websocket
|
|
15
14
|
|
|
15
|
+
from quantplay.model.generics import ExchangeType, NorenTypes
|
|
16
|
+
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
18
19
|
|
|
@@ -10,7 +10,6 @@ from retrying import retry # type: ignore
|
|
|
10
10
|
|
|
11
11
|
from quantplay.broker.generics.broker import Broker
|
|
12
12
|
from quantplay.exception.exceptions import (
|
|
13
|
-
BrokerException,
|
|
14
13
|
InvalidArgumentException,
|
|
15
14
|
QuantplayOrderPlacementException,
|
|
16
15
|
RetryableException,
|
|
@@ -49,6 +48,7 @@ class FivePaisa(Broker):
|
|
|
49
48
|
client: str | None = None,
|
|
50
49
|
load_instrument: bool = True,
|
|
51
50
|
):
|
|
51
|
+
super().__init__()
|
|
52
52
|
self.broker_name = "FivePaisa_OpenAPI"
|
|
53
53
|
try:
|
|
54
54
|
if client:
|
|
@@ -96,7 +96,6 @@ class FivePaisa(Broker):
|
|
|
96
96
|
|
|
97
97
|
if load_instrument:
|
|
98
98
|
self.load_instrument()
|
|
99
|
-
super(FivePaisa, self).__init__()
|
|
100
99
|
|
|
101
100
|
def get_exchange(self, exchange: ExchangeType) -> Any:
|
|
102
101
|
return exchange
|
|
@@ -310,10 +309,9 @@ class FivePaisa(Broker):
|
|
|
310
309
|
)
|
|
311
310
|
def orders(self, tag: str | None = None, add_ltp: bool = True):
|
|
312
311
|
orders = self.client.order_book()
|
|
312
|
+
|
|
313
313
|
if orders is None:
|
|
314
|
-
raise
|
|
315
|
-
"Invalid data response. AngelOne sent incorrect data, Please check."
|
|
316
|
-
)
|
|
314
|
+
raise TokenException("5Paisa Token expired")
|
|
317
315
|
|
|
318
316
|
if len(orders) == 0:
|
|
319
317
|
return pl.DataFrame(schema=self.orders_schema)
|
|
@@ -81,9 +81,9 @@ class FlatTrade(Noren):
|
|
|
81
81
|
"request_code": reqCode,
|
|
82
82
|
"api_secret": hashlib.sha256(secret_code.encode()).hexdigest(),
|
|
83
83
|
}
|
|
84
|
-
|
|
84
|
+
url = "https://authapi.flattrade.in/trade/apitoken"
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
token =
|
|
86
|
+
res = requests.post(url, json=payload)
|
|
87
|
+
token = res.json()["token"]
|
|
88
88
|
|
|
89
89
|
return token
|
|
@@ -8,11 +8,12 @@ import urllib.parse
|
|
|
8
8
|
from datetime import datetime as dt
|
|
9
9
|
from time import sleep
|
|
10
10
|
from typing import Any, Callable, Dict, List, Literal, TypedDict
|
|
11
|
-
|
|
12
|
-
from quantplay.model.generics import ExchangeType
|
|
11
|
+
|
|
13
12
|
import requests
|
|
14
13
|
import websocket
|
|
15
14
|
|
|
15
|
+
from quantplay.model.generics import ExchangeType, NorenTypes
|
|
16
|
+
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
18
19
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
1
|
import copy
|
|
3
2
|
import io
|
|
4
3
|
import json
|
|
@@ -11,6 +10,7 @@ import threading
|
|
|
11
10
|
import time
|
|
12
11
|
import traceback
|
|
13
12
|
import zipfile
|
|
13
|
+
from abc import ABC, abstractmethod
|
|
14
14
|
from datetime import datetime, timedelta
|
|
15
15
|
from queue import Queue
|
|
16
16
|
from threading import Lock
|
|
@@ -32,10 +32,10 @@ from quantplay.model.broker import (
|
|
|
32
32
|
UserBrokerProfileResponse,
|
|
33
33
|
)
|
|
34
34
|
from quantplay.model.generics import (
|
|
35
|
+
OrderTypeType,
|
|
35
36
|
ProductType,
|
|
36
37
|
QuantplayOrder,
|
|
37
38
|
TransactionType,
|
|
38
|
-
OrderTypeType,
|
|
39
39
|
)
|
|
40
40
|
from quantplay.model.instrument_data import InstrumentDataType
|
|
41
41
|
from quantplay.model.order_event import OrderUpdateEvent
|
|
@@ -812,8 +812,8 @@ class Broker(ABC):
|
|
|
812
812
|
product: ProductType,
|
|
813
813
|
transaction_type: TransactionType,
|
|
814
814
|
quantity: int,
|
|
815
|
-
strike_factor: int,
|
|
816
|
-
new_strike: int,
|
|
815
|
+
strike_factor: int | None,
|
|
816
|
+
new_strike: int | None,
|
|
817
817
|
):
|
|
818
818
|
split_regex = r"([A-Z]+)(.{5})([0-9]+)(CE|PE)"
|
|
819
819
|
|
|
@@ -825,7 +825,7 @@ class Broker(ABC):
|
|
|
825
825
|
config = self.underlying_config(underlying, expiry)
|
|
826
826
|
strike_gap = config["strike_gap"]
|
|
827
827
|
|
|
828
|
-
if strike_factor:
|
|
828
|
+
if strike_factor is not None:
|
|
829
829
|
new_strike = strike + (strike_gap * strike_factor)
|
|
830
830
|
|
|
831
831
|
new_trading_symbol = f"{underlying}{expiry}{new_strike}{instrument_type}"
|
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
import binascii
|
|
1
2
|
import copy
|
|
2
3
|
import hashlib
|
|
4
|
+
import json
|
|
3
5
|
from queue import Queue
|
|
4
6
|
from typing import Any, Dict
|
|
5
|
-
|
|
6
|
-
import json
|
|
7
|
+
|
|
7
8
|
import polars as pl
|
|
9
|
+
import pyotp
|
|
10
|
+
import requests
|
|
11
|
+
from retrying import retry # type: ignore
|
|
8
12
|
|
|
13
|
+
from quantplay.broker.generics.broker import Broker
|
|
14
|
+
from quantplay.exception.exceptions import (
|
|
15
|
+
InvalidArgumentException,
|
|
16
|
+
QuantplayOrderPlacementException,
|
|
17
|
+
RetryableException,
|
|
18
|
+
TokenException,
|
|
19
|
+
retry_exception,
|
|
20
|
+
)
|
|
9
21
|
from quantplay.model.broker import UserBrokerProfileResponse
|
|
10
22
|
from quantplay.model.generics import (
|
|
11
23
|
ExchangeType,
|
|
@@ -15,18 +27,7 @@ from quantplay.model.generics import (
|
|
|
15
27
|
)
|
|
16
28
|
from quantplay.model.order_event import OrderUpdateEvent
|
|
17
29
|
from quantplay.utils.constant import Constants, OrderType
|
|
18
|
-
from quantplay.broker.generics.broker import Broker
|
|
19
|
-
from quantplay.exception.exceptions import InvalidArgumentException
|
|
20
|
-
import pyotp
|
|
21
|
-
import binascii
|
|
22
30
|
from quantplay.utils.pickle_utils import InstrumentData
|
|
23
|
-
from quantplay.exception.exceptions import (
|
|
24
|
-
QuantplayOrderPlacementException,
|
|
25
|
-
TokenException,
|
|
26
|
-
retry_exception,
|
|
27
|
-
RetryableException,
|
|
28
|
-
)
|
|
29
|
-
from retrying import retry # type: ignore
|
|
30
31
|
from quantplay.wrapper.aws.s3 import S3Utils
|
|
31
32
|
|
|
32
33
|
|
|
@@ -74,7 +75,7 @@ class Motilal(Broker):
|
|
|
74
75
|
totp: str | None = None,
|
|
75
76
|
order_updates: Queue[OrderUpdateEvent] | None = None,
|
|
76
77
|
):
|
|
77
|
-
super(
|
|
78
|
+
super().__init__()
|
|
78
79
|
self.order_updates = order_updates
|
|
79
80
|
|
|
80
81
|
self.instrument_data_by_exchange = {}
|
|
@@ -339,7 +340,7 @@ class Motilal(Broker):
|
|
|
339
340
|
).json()
|
|
340
341
|
Constants.logger.info("[MODIFY_ORDER_RESPONSE] {}".format(response))
|
|
341
342
|
except Exception as e:
|
|
342
|
-
exception_message = f"[ORDER_MODIFICATION_FAILED] for {data[
|
|
343
|
+
exception_message = f"[ORDER_MODIFICATION_FAILED] for {data['uniqueorderid']} failed with exception {e}"
|
|
343
344
|
Constants.logger.error("{}".format(exception_message))
|
|
344
345
|
return order["order_id"]
|
|
345
346
|
|
|
@@ -23,8 +23,12 @@ from quantplay.model.broker import (
|
|
|
23
23
|
ModifyOrderRequest,
|
|
24
24
|
UserBrokerProfileResponse,
|
|
25
25
|
)
|
|
26
|
-
from quantplay.model.generics import
|
|
27
|
-
|
|
26
|
+
from quantplay.model.generics import (
|
|
27
|
+
NorenTypes,
|
|
28
|
+
OrderTypeType,
|
|
29
|
+
ProductType,
|
|
30
|
+
TransactionType,
|
|
31
|
+
)
|
|
28
32
|
from quantplay.model.order_event import OrderUpdateEvent
|
|
29
33
|
from quantplay.utils.constant import Constants, OrderType
|
|
30
34
|
from quantplay.utils.pickle_utils import InstrumentData
|
|
@@ -39,7 +43,7 @@ class Noren(Broker):
|
|
|
39
43
|
load_instrument: bool = True,
|
|
40
44
|
order_updates: Queue[OrderUpdateEvent] | None = None,
|
|
41
45
|
):
|
|
42
|
-
super(
|
|
46
|
+
super().__init__()
|
|
43
47
|
|
|
44
48
|
self.order_updates = order_updates
|
|
45
49
|
|
|
@@ -49,6 +49,8 @@ class Upstox(Broker):
|
|
|
49
49
|
redirect_url: str | None = None,
|
|
50
50
|
load_instrument: bool = True,
|
|
51
51
|
):
|
|
52
|
+
super().__init__()
|
|
53
|
+
|
|
52
54
|
try:
|
|
53
55
|
if access_token:
|
|
54
56
|
self.set_access_token(access_token)
|
|
@@ -83,8 +85,6 @@ class Upstox(Broker):
|
|
|
83
85
|
if load_instrument:
|
|
84
86
|
self.load_instrument()
|
|
85
87
|
|
|
86
|
-
super(Upstox, self).__init__()
|
|
87
|
-
|
|
88
88
|
def load_instrument(self, file_name: str | None = None) -> None:
|
|
89
89
|
super().load_instrument("upstox_instruments")
|
|
90
90
|
|
|
@@ -192,7 +192,7 @@ class Upstox(Broker):
|
|
|
192
192
|
)
|
|
193
193
|
|
|
194
194
|
Constants.logger.info(
|
|
195
|
-
f"Modifying order [{ order[
|
|
195
|
+
f"Modifying order [{ order['order_id']}] new price [{order.get('price')}]"
|
|
196
196
|
)
|
|
197
197
|
return order["order_id"]
|
|
198
198
|
|
|
@@ -12,9 +12,8 @@ import traceback
|
|
|
12
12
|
from typing import Any, Dict, List, Literal
|
|
13
13
|
|
|
14
14
|
import requests
|
|
15
|
-
import urllib3
|
|
16
15
|
import requests.adapters
|
|
17
|
-
|
|
16
|
+
import urllib3
|
|
18
17
|
from six.moves.urllib.parse import urljoin # type:ignore
|
|
19
18
|
|
|
20
19
|
from quantplay.broker.xts_utils import Exception as ex
|
|
@@ -47,6 +47,7 @@ class Zerodha(Broker):
|
|
|
47
47
|
totp: str | None = None,
|
|
48
48
|
load_instrument: bool = True,
|
|
49
49
|
):
|
|
50
|
+
super().__init__()
|
|
50
51
|
self.wrapper: KiteConnect
|
|
51
52
|
try:
|
|
52
53
|
if wrapper:
|
|
@@ -62,7 +63,6 @@ class Zerodha(Broker):
|
|
|
62
63
|
if load_instrument:
|
|
63
64
|
self.initialize_symbol_data()
|
|
64
65
|
self.broker_symbol_map = {}
|
|
65
|
-
super(Zerodha, self).__init__()
|
|
66
66
|
|
|
67
67
|
def set_wrapper(self, serialized_wrapper: str):
|
|
68
68
|
self.wrapper = pickle.loads(codecs.decode(serialized_wrapper.encode(), "base64"))
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
class InvalidArgumentException(Exception):
|
|
2
|
+
code = "400"
|
|
3
|
+
|
|
4
|
+
def __init__(self, message: str):
|
|
5
|
+
super().__init__(message)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DataNotFoundException(Exception):
|
|
9
|
+
code = "404"
|
|
10
|
+
|
|
11
|
+
def __init__(self, message: str):
|
|
12
|
+
super().__init__(message)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FeatureNotSupported(Exception):
|
|
16
|
+
code = "407"
|
|
17
|
+
|
|
18
|
+
def __init__(self, message: str):
|
|
19
|
+
super().__init__(message)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AccessDeniedException(Exception):
|
|
23
|
+
code = "403"
|
|
24
|
+
|
|
25
|
+
def __init__(self, message: str):
|
|
26
|
+
super().__init__(message)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class RetryableException(Exception):
|
|
30
|
+
code = "409"
|
|
31
|
+
|
|
32
|
+
def __init__(self, message: str):
|
|
33
|
+
super().__init__(message)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def retry_on_access_denied(exc: Exception):
|
|
37
|
+
return isinstance(exc, AccessDeniedException)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def retry_exception(exc: Exception):
|
|
41
|
+
return isinstance(exc, RetryableException)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class StaleDataFound(Exception):
|
|
45
|
+
code = "101"
|
|
46
|
+
|
|
47
|
+
def __init__(self, message: str):
|
|
48
|
+
super().__init__(message)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ServiceException(Exception):
|
|
52
|
+
code = "500"
|
|
53
|
+
|
|
54
|
+
def __init__(self, message: str):
|
|
55
|
+
super().__init__(message)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class StockNotListedOnExchange(Exception):
|
|
59
|
+
stocks = []
|
|
60
|
+
|
|
61
|
+
def __init__(self, message: str):
|
|
62
|
+
super().__init__(message)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class QuantplayOrderPlacementException(Exception):
|
|
66
|
+
def __init__(self, message: str):
|
|
67
|
+
super().__init__(message)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class StrategyInvocationException(Exception):
|
|
71
|
+
def __init__(self, message: str):
|
|
72
|
+
super().__init__(message)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class BrokerNotFoundException(Exception):
|
|
76
|
+
code = "404"
|
|
77
|
+
|
|
78
|
+
def __init__(self, message: str):
|
|
79
|
+
super().__init__(message)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class TokenException(Exception):
|
|
83
|
+
code = "404"
|
|
84
|
+
|
|
85
|
+
def __init__(self, message: str):
|
|
86
|
+
super().__init__(message)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class WrongLibrarySetup(Exception):
|
|
90
|
+
code = "501"
|
|
91
|
+
|
|
92
|
+
def __init__(self, message: str):
|
|
93
|
+
super().__init__(message)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class BrokerException(Exception):
|
|
97
|
+
code = "510"
|
|
98
|
+
|
|
99
|
+
def __init__(self, message: str):
|
|
100
|
+
super().__init__(message)
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from threading import Lock
|
|
3
|
+
|
|
1
4
|
import boto3
|
|
2
5
|
import pandas as pd
|
|
3
|
-
import os
|
|
4
6
|
from boto3.s3.transfer import TransferConfig
|
|
5
|
-
from threading import Lock
|
|
6
|
-
from quantplay.utils.constant import Constants
|
|
7
7
|
from retrying import retry # type: ignore
|
|
8
8
|
|
|
9
|
+
from quantplay.utils.constant import Constants
|
|
9
10
|
|
|
10
11
|
lock = Lock()
|
|
11
12
|
|
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: quantplay
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.45
|
|
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
|
|
|
@@ -11,6 +11,7 @@ quantplay.egg-info/top_level.txt
|
|
|
11
11
|
quantplay/broker/__init__.py
|
|
12
12
|
quantplay/broker/aliceblue.py
|
|
13
13
|
quantplay/broker/angelone.py
|
|
14
|
+
quantplay/broker/broker_factory.py
|
|
14
15
|
quantplay/broker/dhan.py
|
|
15
16
|
quantplay/broker/five_paisa.py
|
|
16
17
|
quantplay/broker/flattrade.py
|
|
@@ -31,7 +32,6 @@ quantplay/broker/ft_utils/flattrade_utils.py
|
|
|
31
32
|
quantplay/broker/ft_utils/ft_noren.py
|
|
32
33
|
quantplay/broker/generics/__init__.py
|
|
33
34
|
quantplay/broker/generics/broker.py
|
|
34
|
-
quantplay/broker/generics/broker_factory.py
|
|
35
35
|
quantplay/broker/uplink/__init__.py
|
|
36
36
|
quantplay/broker/uplink/uplink_utils.py
|
|
37
37
|
quantplay/broker/xts_utils/Connect.py
|
|
@@ -9,7 +9,7 @@ def is_requirement(s: str) -> bool:
|
|
|
9
9
|
and must not start from - or #.
|
|
10
10
|
"""
|
|
11
11
|
s = s.strip()
|
|
12
|
-
return not any([not s, re.match("^[-#]", s)])
|
|
12
|
+
return not any([not s, re.match("^[-#]", s)])
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
requirements = [
|
|
@@ -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.
|
|
24
|
+
version="2.0.45",
|
|
25
25
|
setup_requires=["pytest-runner"],
|
|
26
26
|
install_requires=requirements,
|
|
27
27
|
tests_require=[],
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
class InvalidArgumentException(Exception):
|
|
2
|
-
code = "400"
|
|
3
|
-
|
|
4
|
-
def __init__(self, message: str):
|
|
5
|
-
# Call the base class constructor with the parameters it needs
|
|
6
|
-
super(InvalidArgumentException, self).__init__(message)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class DataNotFoundException(Exception):
|
|
10
|
-
code = "404"
|
|
11
|
-
|
|
12
|
-
def __init__(self, message: str):
|
|
13
|
-
# Call the base class constructor with the parameters it needs
|
|
14
|
-
super(DataNotFoundException, self).__init__(message)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class FeatureNotSupported(Exception):
|
|
18
|
-
code = "407"
|
|
19
|
-
|
|
20
|
-
def __init__(self, message: str):
|
|
21
|
-
# Call the base class constructor with the parameters it needs
|
|
22
|
-
super(FeatureNotSupported, self).__init__(message)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class AccessDeniedException(Exception):
|
|
26
|
-
code = "403"
|
|
27
|
-
|
|
28
|
-
def __init__(self, message: str):
|
|
29
|
-
# Call the base class constructor with the parameters it needs
|
|
30
|
-
super(AccessDeniedException, self).__init__(message)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class RetryableException(Exception):
|
|
34
|
-
code = "409"
|
|
35
|
-
|
|
36
|
-
def __init__(self, message: str):
|
|
37
|
-
# Call the base class constructor with the parameters it needs
|
|
38
|
-
super(RetryableException, self).__init__(message)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def retry_on_access_denied(exc: Exception):
|
|
42
|
-
return isinstance(exc, AccessDeniedException)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def retry_exception(exc: Exception):
|
|
46
|
-
return isinstance(exc, RetryableException)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class StaleDataFound(Exception):
|
|
50
|
-
code = "101"
|
|
51
|
-
|
|
52
|
-
def __init__(self, message: str):
|
|
53
|
-
# Call the base class constructor with the parameters it needs
|
|
54
|
-
super(StaleDataFound, self).__init__(message)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
class ServiceException(Exception):
|
|
58
|
-
code = "500"
|
|
59
|
-
|
|
60
|
-
def __init__(self, message: str):
|
|
61
|
-
# Call the base class constructor with the parameters it needs
|
|
62
|
-
super(ServiceException, self).__init__(message)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class StockNotListedOnExchange(Exception):
|
|
66
|
-
stocks = []
|
|
67
|
-
|
|
68
|
-
def __init__(self, message: str):
|
|
69
|
-
# Call the base class constructor with the parameters it needs
|
|
70
|
-
super(StockNotListedOnExchange, self).__init__(message)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class QuantplayOrderPlacementException(Exception):
|
|
74
|
-
def __init__(self, message: str):
|
|
75
|
-
# Call the base class constructor with the parameters it needs
|
|
76
|
-
super(QuantplayOrderPlacementException, self).__init__(message)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class StrategyInvocationException(Exception):
|
|
80
|
-
def __init__(self, message: str):
|
|
81
|
-
# Call the base class constructor with the parameters it needs
|
|
82
|
-
super(StrategyInvocationException, self).__init__(message)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class BrokerNotFoundException(Exception):
|
|
86
|
-
code = "404"
|
|
87
|
-
|
|
88
|
-
def __init__(self, message: str):
|
|
89
|
-
# Call the base class constructor with the parameters it needs
|
|
90
|
-
super(BrokerNotFoundException, self).__init__(message)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
class TokenException(Exception):
|
|
94
|
-
code = "404"
|
|
95
|
-
|
|
96
|
-
def __init__(self, message: str):
|
|
97
|
-
# Call the base class constructor with the parameters it needs
|
|
98
|
-
super(TokenException, self).__init__(message)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class WrongLibrarySetup(Exception):
|
|
102
|
-
code = "501"
|
|
103
|
-
|
|
104
|
-
def __init__(self, message: str):
|
|
105
|
-
# Call the base class constructor with the parameters it needs
|
|
106
|
-
super(WrongLibrarySetup, self).__init__(message)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
class BrokerException(Exception):
|
|
110
|
-
code = "510"
|
|
111
|
-
|
|
112
|
-
def __init__(self, message: str):
|
|
113
|
-
# Call the base class constructor with the parameters it needs
|
|
114
|
-
super(BrokerException, self).__init__(message)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quantplay-2.0.42/quantplay/broker → quantplay-2.0.45/quantplay/broker/auto_login}/__init__.py
RENAMED
|
File without changes
|
|
@@ -5,6 +5,7 @@ import traceback
|
|
|
5
5
|
import pyotp
|
|
6
6
|
from retrying import retry # type: ignore
|
|
7
7
|
from selenium.common.exceptions import NoSuchElementException, WebDriverException
|
|
8
|
+
from selenium.webdriver import Chrome
|
|
8
9
|
|
|
9
10
|
from quantplay.exception.exceptions import (
|
|
10
11
|
BrokerException,
|
|
@@ -12,7 +13,6 @@ from quantplay.exception.exceptions import (
|
|
|
12
13
|
RetryableException,
|
|
13
14
|
)
|
|
14
15
|
from quantplay.utils.selenium_utils import Selenium
|
|
15
|
-
from selenium.webdriver import Chrome
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class AliceblueLogin:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quantplay-2.0.42/quantplay/broker/generics → quantplay-2.0.45/quantplay/broker/uplink}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quantplay-2.0.42/quantplay/broker/uplink → quantplay-2.0.45/quantplay/broker/xts_utils}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{quantplay-2.0.42/quantplay/broker/xts_utils → quantplay-2.0.45/quantplay/model}/__init__.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
|