quantplay 2.0.85__tar.gz → 2.0.90__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.85 → quantplay-2.0.90}/PKG-INFO +1 -1
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/aliceblue.py +10 -11
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/angelone.py +21 -26
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/dhan.py +14 -9
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/finvasia_utils/fa_noren.py +3 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/five_paisa.py +9 -14
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/ft_utils/ft_noren.py +5 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/generics/broker.py +2 -1
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/kotak.py +9 -4
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/motilal.py +12 -13
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/noren.py +11 -25
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/upstox.py +5 -17
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/xts.py +10 -8
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/zerodha.py +19 -15
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/model/broker.py +7 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay.egg-info/PKG-INFO +1 -1
- {quantplay-2.0.85 → quantplay-2.0.90}/setup.py +1 -1
- {quantplay-2.0.85 → quantplay-2.0.90}/README.md +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/pyproject.toml +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/auto_login/aliceblue.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/broker_factory.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/uplink/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/xts_utils/Connect.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/broker/xts_utils/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/model/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/model/generics.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/model/instrument_data.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/model/order_event.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/py.typed +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/utils/caching.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/utils/constant.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/wrapper/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay/wrapper/aws/s3.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay.egg-info/SOURCES.txt +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/setup.cfg +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/tests/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/tests/conftest.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/tests/wrapper/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.85 → quantplay-2.0.90}/tests/wrapper/aws/s3_test.py +0 -0
|
@@ -3,7 +3,7 @@ import copy
|
|
|
3
3
|
import pickle
|
|
4
4
|
import traceback
|
|
5
5
|
from queue import Queue
|
|
6
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Literal
|
|
7
7
|
|
|
8
8
|
import polars as pl
|
|
9
9
|
from pya3 import (
|
|
@@ -28,7 +28,11 @@ from quantplay.exception.exceptions import (
|
|
|
28
28
|
TokenException,
|
|
29
29
|
retry_exception,
|
|
30
30
|
)
|
|
31
|
-
from quantplay.model.broker import
|
|
31
|
+
from quantplay.model.broker import (
|
|
32
|
+
MarginsResponse,
|
|
33
|
+
ModifyOrderRequest,
|
|
34
|
+
UserBrokerProfileResponse,
|
|
35
|
+
)
|
|
32
36
|
from quantplay.model.generics import (
|
|
33
37
|
ExchangeType,
|
|
34
38
|
OrderTypeType,
|
|
@@ -596,29 +600,24 @@ class Aliceblue(Broker):
|
|
|
596
600
|
|
|
597
601
|
return orders_df[list(self.orders_schema.keys())].cast(self.orders_schema)
|
|
598
602
|
|
|
599
|
-
def margins(self) ->
|
|
603
|
+
def margins(self) -> MarginsResponse:
|
|
600
604
|
margins = self.invoke_aliceblue_api(self.alice.get_balance)
|
|
601
605
|
if margins is None:
|
|
602
606
|
return {
|
|
603
607
|
"margin_used": 0.0,
|
|
604
608
|
"total_balance": 0.0,
|
|
605
609
|
"margin_available": 0.0,
|
|
610
|
+
"cash": 0,
|
|
606
611
|
}
|
|
607
612
|
|
|
608
613
|
margins = [a for a in margins if a["segment"] == "ALL"][0]
|
|
609
614
|
|
|
610
|
-
|
|
615
|
+
return {
|
|
611
616
|
"margin_used": float(margins["debits"]),
|
|
612
617
|
"total_balance": float(margins["credits"]),
|
|
613
618
|
"margin_available": float(margins["net"]),
|
|
619
|
+
"cash": 0,
|
|
614
620
|
}
|
|
615
|
-
return response
|
|
616
|
-
|
|
617
|
-
def account_summary(self):
|
|
618
|
-
margins = self.margins()
|
|
619
|
-
margins["pnl"] = float(self.positions()["pnl"].sum())
|
|
620
|
-
|
|
621
|
-
return margins
|
|
622
621
|
|
|
623
622
|
def invoke_aliceblue_api(self, fn: Any, *args: Any, **kwargs: Any) -> Any:
|
|
624
623
|
try:
|
|
@@ -3,7 +3,7 @@ import copy
|
|
|
3
3
|
import json
|
|
4
4
|
import traceback
|
|
5
5
|
from queue import Queue
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
import logzero # type: ignore
|
|
9
9
|
import polars as pl
|
|
@@ -23,7 +23,11 @@ from quantplay.exception.exceptions import (
|
|
|
23
23
|
TokenException,
|
|
24
24
|
retry_exception,
|
|
25
25
|
)
|
|
26
|
-
from quantplay.model.broker import
|
|
26
|
+
from quantplay.model.broker import (
|
|
27
|
+
MarginsResponse,
|
|
28
|
+
ModifyOrderRequest,
|
|
29
|
+
UserBrokerProfileResponse,
|
|
30
|
+
)
|
|
27
31
|
from quantplay.model.generics import (
|
|
28
32
|
ExchangeType,
|
|
29
33
|
OrderTypeType,
|
|
@@ -521,22 +525,31 @@ class AngelOne(Broker):
|
|
|
521
525
|
|
|
522
526
|
return response
|
|
523
527
|
|
|
524
|
-
def margins(self) ->
|
|
528
|
+
def margins(self) -> MarginsResponse:
|
|
525
529
|
api_margins = self.invoke_angelone_api(self.wrapper.rmsLimit)
|
|
526
530
|
|
|
527
531
|
if "data" in api_margins and api_margins["data"] is None:
|
|
528
532
|
if "errorcode" in api_margins and api_margins["errorcode"] == "AB1004":
|
|
529
533
|
raise TokenException("Angelone server not not responding")
|
|
530
534
|
|
|
531
|
-
return {
|
|
535
|
+
return {
|
|
536
|
+
"margin_used": 0.0,
|
|
537
|
+
"margin_available": 0.0,
|
|
538
|
+
"total_balance": 0.0,
|
|
539
|
+
"cash": 0,
|
|
540
|
+
}
|
|
532
541
|
|
|
533
542
|
api_margins = api_margins["data"]
|
|
534
543
|
|
|
535
544
|
try:
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
545
|
+
margin_used = float(api_margins["utiliseddebits"])
|
|
546
|
+
margin_available = float(api_margins["net"])
|
|
547
|
+
|
|
548
|
+
margins: MarginsResponse = {
|
|
549
|
+
"margin_used": margin_used,
|
|
550
|
+
"margin_available": margin_available,
|
|
551
|
+
"cash": float(api_margins["availablecash"]),
|
|
552
|
+
"total_balance": margin_used + margin_available,
|
|
540
553
|
}
|
|
541
554
|
|
|
542
555
|
return margins
|
|
@@ -547,24 +560,6 @@ class AngelOne(Broker):
|
|
|
547
560
|
except Exception as e:
|
|
548
561
|
raise RetryableException(f"Angelone: Failed to fetch margin {e}")
|
|
549
562
|
|
|
550
|
-
def account_summary(self):
|
|
551
|
-
pnl = 0
|
|
552
|
-
|
|
553
|
-
margins = self.margins()
|
|
554
|
-
positions = self.positions()
|
|
555
|
-
|
|
556
|
-
if len(positions) > 0:
|
|
557
|
-
pnl = positions["pnl"].sum()
|
|
558
|
-
|
|
559
|
-
response = {
|
|
560
|
-
"margin_used": margins["margin_used"],
|
|
561
|
-
"total_balance": margins["total_balance"],
|
|
562
|
-
"margin_available": margins["margin_available"],
|
|
563
|
-
"pnl": pnl,
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
return response
|
|
567
|
-
|
|
568
563
|
@retry(
|
|
569
564
|
wait_exponential_multiplier=3000,
|
|
570
565
|
wait_exponential_max=10000,
|
|
@@ -15,6 +15,7 @@ from quantplay.exception.exceptions import (
|
|
|
15
15
|
)
|
|
16
16
|
from quantplay.model.broker import (
|
|
17
17
|
ExchangeType,
|
|
18
|
+
MarginsResponse,
|
|
18
19
|
UserBrokerProfileResponse,
|
|
19
20
|
)
|
|
20
21
|
from quantplay.model.generics import (
|
|
@@ -340,7 +341,7 @@ class Dhan(Broker):
|
|
|
340
341
|
.alias("product"),
|
|
341
342
|
pl.when(pl.col("exchange") == "NSE_FNO")
|
|
342
343
|
.then(pl.lit("NFO"))
|
|
343
|
-
.when(pl.col("exchange") == "
|
|
344
|
+
.when(pl.col("exchange") == "BSE_FNO")
|
|
344
345
|
.then(pl.lit("BFO"))
|
|
345
346
|
.when(pl.col("exchange") == "NSE_EQ")
|
|
346
347
|
.then(pl.lit("NSE"))
|
|
@@ -422,16 +423,20 @@ class Dhan(Broker):
|
|
|
422
423
|
traceback.print_exc()
|
|
423
424
|
raise RetryableException("Failed to Receive Data from broker. Retrying Again")
|
|
424
425
|
|
|
425
|
-
def margins(self) ->
|
|
426
|
+
def margins(self) -> MarginsResponse:
|
|
426
427
|
response = self.invoke_dhan_api(self.dhan.get_fund_limits)
|
|
428
|
+
margin_used = 0
|
|
429
|
+
margin_available = 0
|
|
427
430
|
if response:
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
431
|
+
margin_used = float(response["data"]["utilizedAmount"])
|
|
432
|
+
margin_available = float(response["data"]["availabelBalance"])
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
"margin_available": margin_available,
|
|
436
|
+
"margin_used": margin_used,
|
|
437
|
+
"total_balance": margin_used + margin_available,
|
|
438
|
+
"cash": 0,
|
|
439
|
+
}
|
|
435
440
|
|
|
436
441
|
def profile(self) -> UserBrokerProfileResponse:
|
|
437
442
|
return {"user_id": self.dhan.client_id}
|
|
@@ -13,6 +13,7 @@ import requests
|
|
|
13
13
|
import websocket
|
|
14
14
|
|
|
15
15
|
from quantplay.model.generics import ExchangeType, NorenTypes
|
|
16
|
+
from quantplay.exception import TokenException
|
|
16
17
|
|
|
17
18
|
logger = logging.getLogger(__name__)
|
|
18
19
|
|
|
@@ -294,6 +295,8 @@ class FA_NorenApi:
|
|
|
294
295
|
|
|
295
296
|
self.__username = userid
|
|
296
297
|
self.__accountid = userid
|
|
298
|
+
if "stat" in resDict and resDict["stat"].lower() == "not_ok":
|
|
299
|
+
raise TokenException(resDict["emsg"])
|
|
297
300
|
self.__susertoken = resDict["susertoken"]
|
|
298
301
|
|
|
299
302
|
return resDict
|
|
@@ -16,7 +16,11 @@ from quantplay.exception.exceptions import (
|
|
|
16
16
|
TokenException,
|
|
17
17
|
retry_exception,
|
|
18
18
|
)
|
|
19
|
-
from quantplay.model.broker import
|
|
19
|
+
from quantplay.model.broker import (
|
|
20
|
+
MarginsResponse,
|
|
21
|
+
ModifyOrderRequest,
|
|
22
|
+
UserBrokerProfileResponse,
|
|
23
|
+
)
|
|
20
24
|
from quantplay.model.generics import (
|
|
21
25
|
ExchangeType,
|
|
22
26
|
OrderTypeType,
|
|
@@ -528,7 +532,7 @@ class FivePaisa(Broker):
|
|
|
528
532
|
stop_max_attempt_number=3,
|
|
529
533
|
retry_on_exception=retry_exception,
|
|
530
534
|
)
|
|
531
|
-
def margins(self) ->
|
|
535
|
+
def margins(self) -> MarginsResponse:
|
|
532
536
|
margins = self.client.margin()
|
|
533
537
|
|
|
534
538
|
if margins is None:
|
|
@@ -536,22 +540,13 @@ class FivePaisa(Broker):
|
|
|
536
540
|
|
|
537
541
|
margins = margins[0]
|
|
538
542
|
|
|
539
|
-
|
|
543
|
+
return {
|
|
540
544
|
"margin_used": margins["MarginUtilized"],
|
|
541
545
|
"margin_available": margins["NetAvailableMargin"],
|
|
546
|
+
"total_balance": margins["NetAvailableMargin"] + margins["MarginUtilized"],
|
|
547
|
+
"cash": 0,
|
|
542
548
|
}
|
|
543
549
|
|
|
544
|
-
return margins
|
|
545
|
-
|
|
546
|
-
def account_summary(self):
|
|
547
|
-
margins = self.margins()
|
|
548
|
-
response = {
|
|
549
|
-
"margin_used": margins["margin_used"],
|
|
550
|
-
"margin_available": margins["margin_available"],
|
|
551
|
-
"pnl": float(self.positions()["pnl"].sum()),
|
|
552
|
-
}
|
|
553
|
-
return response
|
|
554
|
-
|
|
555
550
|
def cancel_order(self, order_id: str, variety: str | None = None) -> None:
|
|
556
551
|
raise NotImplementedError("Cancel Order Not Implementd")
|
|
557
552
|
|
|
@@ -12,6 +12,7 @@ from typing import Any, Callable, Dict, List, Literal, TypedDict
|
|
|
12
12
|
import requests
|
|
13
13
|
import websocket
|
|
14
14
|
|
|
15
|
+
from quantplay.exception.exceptions import TokenException
|
|
15
16
|
from quantplay.model.generics import ExchangeType, NorenTypes
|
|
16
17
|
|
|
17
18
|
logger = logging.getLogger(__name__)
|
|
@@ -291,6 +292,10 @@ class FT_NorenApi:
|
|
|
291
292
|
|
|
292
293
|
self.__username = userid
|
|
293
294
|
self.__accountid = userid
|
|
295
|
+
|
|
296
|
+
if "stat" in resDict and resDict["stat"].lower() == "not_ok":
|
|
297
|
+
raise TokenException(resDict["emsg"])
|
|
298
|
+
|
|
294
299
|
self.__susertoken = resDict["susertoken"]
|
|
295
300
|
|
|
296
301
|
return resDict
|
|
@@ -28,6 +28,7 @@ from quantplay.exception.exceptions import (
|
|
|
28
28
|
)
|
|
29
29
|
from quantplay.model.broker import (
|
|
30
30
|
ExchangeType,
|
|
31
|
+
MarginsResponse,
|
|
31
32
|
ModifyOrderRequest,
|
|
32
33
|
UserBrokerProfileResponse,
|
|
33
34
|
)
|
|
@@ -1045,7 +1046,7 @@ class Broker(ABC):
|
|
|
1045
1046
|
...
|
|
1046
1047
|
|
|
1047
1048
|
@abstractmethod
|
|
1048
|
-
def margins(self) ->
|
|
1049
|
+
def margins(self) -> MarginsResponse:
|
|
1049
1050
|
"""Returns User Margin Summary"""
|
|
1050
1051
|
...
|
|
1051
1052
|
|
|
@@ -8,7 +8,11 @@ import polars as pl
|
|
|
8
8
|
import requests
|
|
9
9
|
|
|
10
10
|
from quantplay.broker.generics.broker import Broker
|
|
11
|
-
from quantplay.model.broker import
|
|
11
|
+
from quantplay.model.broker import (
|
|
12
|
+
MarginsResponse,
|
|
13
|
+
ModifyOrderRequest,
|
|
14
|
+
UserBrokerProfileResponse,
|
|
15
|
+
)
|
|
12
16
|
from quantplay.model.generics import (
|
|
13
17
|
ExchangeType,
|
|
14
18
|
OrderTypeType,
|
|
@@ -179,16 +183,17 @@ class Kotak(Broker):
|
|
|
179
183
|
def profile(self) -> UserBrokerProfileResponse:
|
|
180
184
|
return {"user_id": self.user_id or ""}
|
|
181
185
|
|
|
182
|
-
def margins(self) ->
|
|
186
|
+
def margins(self) -> MarginsResponse:
|
|
183
187
|
limits_resp = self.request(
|
|
184
188
|
"limits", body={"seg": "ALL", "exch": "ALL", "prod": "ALL"}
|
|
185
189
|
)
|
|
186
190
|
|
|
187
|
-
|
|
191
|
+
return {
|
|
188
192
|
"margin_used": limits_resp["MarginUsed"],
|
|
189
193
|
"margin_available": limits_resp["Net"],
|
|
194
|
+
"total_balance": limits_resp["MarginUsed"] + limits_resp["Net"],
|
|
195
|
+
"cash": 0,
|
|
190
196
|
}
|
|
191
|
-
return margins
|
|
192
197
|
|
|
193
198
|
# **
|
|
194
199
|
# ** POST/PUT Api's
|
|
@@ -18,7 +18,7 @@ from quantplay.exception.exceptions import (
|
|
|
18
18
|
TokenException,
|
|
19
19
|
retry_exception,
|
|
20
20
|
)
|
|
21
|
-
from quantplay.model.broker import UserBrokerProfileResponse
|
|
21
|
+
from quantplay.model.broker import MarginsResponse, UserBrokerProfileResponse
|
|
22
22
|
from quantplay.model.generics import (
|
|
23
23
|
ExchangeType,
|
|
24
24
|
OrderTypeType,
|
|
@@ -380,19 +380,24 @@ class Motilal(Broker):
|
|
|
380
380
|
)
|
|
381
381
|
Constants.logger.error(exception_message)
|
|
382
382
|
|
|
383
|
-
def margins(self) ->
|
|
383
|
+
def margins(self) -> MarginsResponse:
|
|
384
384
|
response = self.__post_request(self.margin_summary_url, {})
|
|
385
385
|
margin_summary = response["data"]
|
|
386
|
-
|
|
387
|
-
|
|
386
|
+
margin_used = 0
|
|
387
|
+
margin_available = 0
|
|
388
388
|
for margin_particular in margin_summary:
|
|
389
389
|
if margin_particular["srno"] in [103]:
|
|
390
|
-
|
|
390
|
+
margin_available += margin_particular["amount"]
|
|
391
391
|
|
|
392
392
|
if margin_particular["srno"] in [301, 321, 340, 360]:
|
|
393
|
-
|
|
393
|
+
margin_used += margin_particular["amount"]
|
|
394
394
|
|
|
395
|
-
return
|
|
395
|
+
return {
|
|
396
|
+
"margin_available": margin_available,
|
|
397
|
+
"margin_used": margin_used,
|
|
398
|
+
"total_balance": margin_used + margin_available,
|
|
399
|
+
"cash": 0,
|
|
400
|
+
}
|
|
396
401
|
|
|
397
402
|
def place_order(
|
|
398
403
|
self,
|
|
@@ -454,12 +459,6 @@ class Motilal(Broker):
|
|
|
454
459
|
exception_message = "Order placement failed with error [{}]".format(str(e))
|
|
455
460
|
print(exception_message)
|
|
456
461
|
|
|
457
|
-
def account_summary(self):
|
|
458
|
-
response = self.margins()
|
|
459
|
-
response["pnl"] = float(self.positions()["pnl"].sum()) # type: ignore
|
|
460
|
-
|
|
461
|
-
return response
|
|
462
|
-
|
|
463
462
|
@retry(
|
|
464
463
|
wait_exponential_multiplier=3000,
|
|
465
464
|
wait_exponential_max=10000,
|
|
@@ -20,6 +20,7 @@ from quantplay.exception.exceptions import (
|
|
|
20
20
|
)
|
|
21
21
|
from quantplay.model.broker import (
|
|
22
22
|
ExchangeType,
|
|
23
|
+
MarginsResponse,
|
|
23
24
|
ModifyOrderRequest,
|
|
24
25
|
UserBrokerProfileResponse,
|
|
25
26
|
)
|
|
@@ -700,7 +701,7 @@ class Noren(Broker):
|
|
|
700
701
|
stop_max_attempt_number=3,
|
|
701
702
|
retry_on_exception=retry_exception,
|
|
702
703
|
)
|
|
703
|
-
def margins(self) ->
|
|
704
|
+
def margins(self) -> MarginsResponse:
|
|
704
705
|
api_margins = self.invoke_noren_api(self.api.get_limits)
|
|
705
706
|
|
|
706
707
|
if api_margins is None:
|
|
@@ -730,16 +731,17 @@ class Noren(Broker):
|
|
|
730
731
|
- float(api_margins["margin_used"])
|
|
731
732
|
)
|
|
732
733
|
|
|
733
|
-
margins: Dict[str, float] = {}
|
|
734
|
-
margins["margin_used"] = api_margins["margin_used"]
|
|
735
|
-
margins["margin_available"] = margin_available
|
|
736
|
-
|
|
737
734
|
try:
|
|
738
|
-
|
|
735
|
+
cash = float(api_margins["cash"])
|
|
739
736
|
except Exception:
|
|
740
|
-
|
|
737
|
+
cash = 0
|
|
741
738
|
|
|
742
|
-
margins
|
|
739
|
+
margins: MarginsResponse = {
|
|
740
|
+
"margin_used": api_margins["margin_used"],
|
|
741
|
+
"margin_available": margin_available,
|
|
742
|
+
"cash": cash,
|
|
743
|
+
"total_balance": float(cash) + float(holdings_val),
|
|
744
|
+
}
|
|
743
745
|
|
|
744
746
|
return margins
|
|
745
747
|
|
|
@@ -747,20 +749,4 @@ class Noren(Broker):
|
|
|
747
749
|
logger.error(f"[NOREN_MARGIN_ERROR] {e}")
|
|
748
750
|
RetryableException("[NOREN] Failed to fetch account margin")
|
|
749
751
|
|
|
750
|
-
return {}
|
|
751
|
-
|
|
752
|
-
def account_summary(self):
|
|
753
|
-
pnl = 0
|
|
754
|
-
margins = self.margins()
|
|
755
|
-
positions = self.positions()
|
|
756
|
-
|
|
757
|
-
if len(positions) > 0:
|
|
758
|
-
pnl = positions["pnl"].sum()
|
|
759
|
-
|
|
760
|
-
response = {
|
|
761
|
-
"margin_used": margins["margin_used"],
|
|
762
|
-
"total_balance": margins["total_balance"],
|
|
763
|
-
"margin_available": margins["margin_available"],
|
|
764
|
-
"pnl": pnl,
|
|
765
|
-
}
|
|
766
|
-
return response
|
|
752
|
+
return {"margin_available": 0, "margin_used": 0, "total_balance": 0, "cash": 0}
|
|
@@ -22,6 +22,7 @@ from quantplay.exception.exceptions import (
|
|
|
22
22
|
)
|
|
23
23
|
from quantplay.model.broker import (
|
|
24
24
|
ExchangeType,
|
|
25
|
+
MarginsResponse,
|
|
25
26
|
ModifyOrderRequest,
|
|
26
27
|
UserBrokerProfileResponse,
|
|
27
28
|
)
|
|
@@ -556,7 +557,7 @@ class Upstox(Broker):
|
|
|
556
557
|
stop_max_attempt_number=3,
|
|
557
558
|
retry_on_exception=retry_exception,
|
|
558
559
|
)
|
|
559
|
-
def margins(self) ->
|
|
560
|
+
def margins(self) -> MarginsResponse:
|
|
560
561
|
api_instance = upstox_client.UserApi(self.api_client)
|
|
561
562
|
|
|
562
563
|
segment = "SEC" # str | (optional)
|
|
@@ -580,25 +581,12 @@ class Upstox(Broker):
|
|
|
580
581
|
"Exception when calling UserApi->get_user_fund_margin: %s\n" % e
|
|
581
582
|
)
|
|
582
583
|
|
|
583
|
-
|
|
584
|
+
return {
|
|
584
585
|
"margin_used": margin_used,
|
|
585
586
|
"margin_available": margin_available,
|
|
587
|
+
"total_balance": margin_used + margin_available,
|
|
588
|
+
"cash": 0,
|
|
586
589
|
}
|
|
587
|
-
return margins
|
|
588
|
-
|
|
589
|
-
@retry(
|
|
590
|
-
wait_exponential_multiplier=3000,
|
|
591
|
-
wait_exponential_max=10000,
|
|
592
|
-
stop_max_attempt_number=3,
|
|
593
|
-
)
|
|
594
|
-
def account_summary(self):
|
|
595
|
-
margins = self.margins()
|
|
596
|
-
response = {
|
|
597
|
-
"margin_used": margins["margin_used"],
|
|
598
|
-
"margin_available": margins["margin_available"],
|
|
599
|
-
"pnl": float(self.positions()["pnl"].sum()),
|
|
600
|
-
}
|
|
601
|
-
return response
|
|
602
590
|
|
|
603
591
|
def stream_order_data(self):
|
|
604
592
|
th = threading.Thread(target=self.between_callback, daemon=True)
|
|
@@ -22,6 +22,7 @@ from quantplay.exception.exceptions import (
|
|
|
22
22
|
)
|
|
23
23
|
from quantplay.model.broker import (
|
|
24
24
|
ExchangeType,
|
|
25
|
+
MarginsResponse,
|
|
25
26
|
ModifyOrderRequest,
|
|
26
27
|
UserBrokerProfileResponse,
|
|
27
28
|
)
|
|
@@ -172,7 +173,7 @@ class XTS(Broker):
|
|
|
172
173
|
stop_max_attempt_number=3,
|
|
173
174
|
retry_on_exception=retry_exception,
|
|
174
175
|
)
|
|
175
|
-
def margins(self) ->
|
|
176
|
+
def margins(self) -> MarginsResponse:
|
|
176
177
|
api_response = self.wrapper.get_balance(clientID=self.ClientID)
|
|
177
178
|
self.handle_exception(api_response)
|
|
178
179
|
|
|
@@ -180,18 +181,19 @@ class XTS(Broker):
|
|
|
180
181
|
return {
|
|
181
182
|
"margin_used": 0,
|
|
182
183
|
"margin_available": 0,
|
|
184
|
+
"total_balance": 0,
|
|
185
|
+
"cash": 0,
|
|
183
186
|
}
|
|
184
187
|
api_response = api_response["result"]["BalanceList"][0]["limitObject"]
|
|
188
|
+
margin_used = api_response["RMSSubLimits"]["marginUtilized"]
|
|
189
|
+
margin_available = api_response["RMSSubLimits"]["netMarginAvailable"]
|
|
185
190
|
return {
|
|
186
|
-
"margin_used":
|
|
187
|
-
"margin_available":
|
|
191
|
+
"margin_used": margin_used,
|
|
192
|
+
"margin_available": margin_available,
|
|
193
|
+
"total_balance": margin_used + margin_available,
|
|
194
|
+
"cash": 0,
|
|
188
195
|
}
|
|
189
196
|
|
|
190
|
-
def account_summary(self):
|
|
191
|
-
margins = self.margins()
|
|
192
|
-
margins["pnl"] = float(self.positions()["pnl"].sum())
|
|
193
|
-
return margins
|
|
194
|
-
|
|
195
197
|
@retry(
|
|
196
198
|
wait_exponential_multiplier=3000,
|
|
197
199
|
wait_exponential_max=10000,
|
|
@@ -20,6 +20,7 @@ from quantplay.exception.exceptions import (
|
|
|
20
20
|
from quantplay.exception.exceptions import TokenException as QuantplayTokenException
|
|
21
21
|
from quantplay.model.broker import (
|
|
22
22
|
ExchangeType,
|
|
23
|
+
MarginsResponse,
|
|
23
24
|
ModifyOrderRequest,
|
|
24
25
|
UserBrokerProfileResponse,
|
|
25
26
|
)
|
|
@@ -380,7 +381,16 @@ class Zerodha(Broker):
|
|
|
380
381
|
[self.get_token(x) for x in holdings_df["instrument_token"].to_list()],
|
|
381
382
|
)
|
|
382
383
|
)
|
|
384
|
+
if "collateral_quantity" in holdings_df.columns:
|
|
385
|
+
holdings_df = holdings_df.with_columns(
|
|
386
|
+
pl.col("collateral_quantity").alias("pledged_quantity")
|
|
387
|
+
)
|
|
388
|
+
else:
|
|
389
|
+
holdings_df = holdings_df.with_columns(pl.lit(0).alias("pledged_quantity"))
|
|
383
390
|
|
|
391
|
+
holdings_df = holdings_df.with_columns(
|
|
392
|
+
(pl.col("pledged_quantity") + pl.col("quantity")).alias("quantity")
|
|
393
|
+
)
|
|
384
394
|
holdings_df = holdings_df.with_columns(
|
|
385
395
|
(pl.col("quantity") * pl.col("price")).alias("value"),
|
|
386
396
|
pl.lit(0).alias("pledged_quantity"),
|
|
@@ -521,15 +531,18 @@ class Zerodha(Broker):
|
|
|
521
531
|
stop_max_attempt_number=3,
|
|
522
532
|
retry_on_exception=retry_exception,
|
|
523
533
|
)
|
|
524
|
-
def margins(self) ->
|
|
534
|
+
def margins(self) -> MarginsResponse:
|
|
525
535
|
try:
|
|
526
536
|
margins = self.wrapper.margins()
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
"
|
|
537
|
+
margin_used = float(margins["equity"]["utilised"]["debits"])
|
|
538
|
+
margin_available = float(margins["equity"]["net"])
|
|
539
|
+
response: MarginsResponse = {
|
|
540
|
+
"margin_used": margin_used,
|
|
541
|
+
"margin_available": margin_available,
|
|
542
|
+
"total_balance": margin_used + margin_available,
|
|
543
|
+
"cash": float(margins["equity"]["available"]["cash"]),
|
|
531
544
|
}
|
|
532
|
-
return
|
|
545
|
+
return response
|
|
533
546
|
|
|
534
547
|
except TokenException as e:
|
|
535
548
|
raise QuantplayTokenException(str(e))
|
|
@@ -554,15 +567,6 @@ class Zerodha(Broker):
|
|
|
554
567
|
"gst": sum([a["charges"]["gst"]["total"] for a in charges]),
|
|
555
568
|
}
|
|
556
569
|
|
|
557
|
-
def account_summary(self):
|
|
558
|
-
margins = self.margins()
|
|
559
|
-
response = {
|
|
560
|
-
"margin_used": margins["margin_used"],
|
|
561
|
-
"margin_available": margins["margin_available"],
|
|
562
|
-
"pnl": float(self.positions()["pnl"].sum()),
|
|
563
|
-
}
|
|
564
|
-
return response
|
|
565
|
-
|
|
566
570
|
@retry(
|
|
567
571
|
wait_exponential_multiplier=3000,
|
|
568
572
|
wait_exponential_max=10000,
|
|
@@ -30,3 +30,10 @@ class UserBrokerProfileResponse(TypedDict):
|
|
|
30
30
|
segments: NotRequired[ExchangeType]
|
|
31
31
|
exchanges: NotRequired[ExchangeType]
|
|
32
32
|
email: NotRequired[str]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class MarginsResponse(TypedDict):
|
|
36
|
+
total_balance: float
|
|
37
|
+
margin_available: float
|
|
38
|
+
margin_used: float
|
|
39
|
+
cash: float
|
|
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
|
|
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
|