quantplay 2.0.84__tar.gz → 2.0.86__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.84 → quantplay-2.0.86}/PKG-INFO +1 -1
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/aliceblue.py +8 -11
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/angelone.py +8 -22
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/dhan.py +14 -10
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/five_paisa.py +8 -14
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/generics/broker.py +2 -1
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/kotak.py +8 -4
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/motilal.py +11 -13
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/noren.py +10 -25
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/upstox.py +4 -17
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/xts.py +8 -8
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/zerodha.py +9 -15
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/model/broker.py +6 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay.egg-info/PKG-INFO +1 -1
- {quantplay-2.0.84 → quantplay-2.0.86}/setup.py +1 -1
- {quantplay-2.0.84 → quantplay-2.0.86}/README.md +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/pyproject.toml +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/auto_login/aliceblue.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/broker_factory.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/ft_utils/ft_noren.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/uplink/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/xts_utils/Connect.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/broker/xts_utils/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/model/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/model/generics.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/model/instrument_data.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/model/order_event.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/py.typed +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/utils/caching.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/utils/constant.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/wrapper/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay/wrapper/aws/s3.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay.egg-info/SOURCES.txt +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/setup.cfg +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/tests/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/tests/conftest.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/tests/wrapper/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.84 → quantplay-2.0.86}/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,7 +600,7 @@ 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 {
|
|
@@ -607,18 +611,11 @@ class Aliceblue(Broker):
|
|
|
607
611
|
|
|
608
612
|
margins = [a for a in margins if a["segment"] == "ALL"][0]
|
|
609
613
|
|
|
610
|
-
|
|
614
|
+
return {
|
|
611
615
|
"margin_used": float(margins["debits"]),
|
|
612
616
|
"total_balance": float(margins["credits"]),
|
|
613
617
|
"margin_available": float(margins["net"]),
|
|
614
618
|
}
|
|
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
619
|
|
|
623
620
|
def invoke_aliceblue_api(self, fn: Any, *args: Any, **kwargs: Any) -> Any:
|
|
624
621
|
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,7 +525,7 @@ 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:
|
|
@@ -533,7 +537,7 @@ class AngelOne(Broker):
|
|
|
533
537
|
api_margins = api_margins["data"]
|
|
534
538
|
|
|
535
539
|
try:
|
|
536
|
-
margins = {
|
|
540
|
+
margins: MarginsResponse = {
|
|
537
541
|
"margin_used": float(api_margins["net"]),
|
|
538
542
|
"margin_available": float(api_margins["net"]),
|
|
539
543
|
"total_balance": float(api_margins["net"]),
|
|
@@ -547,24 +551,6 @@ class AngelOne(Broker):
|
|
|
547
551
|
except Exception as e:
|
|
548
552
|
raise RetryableException(f"Angelone: Failed to fetch margin {e}")
|
|
549
553
|
|
|
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
554
|
@retry(
|
|
569
555
|
wait_exponential_multiplier=3000,
|
|
570
556
|
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 (
|
|
@@ -153,7 +154,7 @@ class Dhan(Broker):
|
|
|
153
154
|
|
|
154
155
|
def get_product(self, product: ProductType) -> DhanTypes.ProductType:
|
|
155
156
|
if product == "NRML":
|
|
156
|
-
return dhanhq.
|
|
157
|
+
return dhanhq.INTRA
|
|
157
158
|
elif product == "CNC":
|
|
158
159
|
return dhanhq.CNC
|
|
159
160
|
elif product == "MIS":
|
|
@@ -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,19 @@ 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
|
+
}
|
|
435
439
|
|
|
436
440
|
def profile(self) -> UserBrokerProfileResponse:
|
|
437
441
|
return {"user_id": self.dhan.client_id}
|
|
@@ -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,12 @@ 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"],
|
|
542
547
|
}
|
|
543
548
|
|
|
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
549
|
def cancel_order(self, order_id: str, variety: str | None = None) -> None:
|
|
556
550
|
raise NotImplementedError("Cancel Order Not Implementd")
|
|
557
551
|
|
|
@@ -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,16 @@ 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"],
|
|
190
195
|
}
|
|
191
|
-
return margins
|
|
192
196
|
|
|
193
197
|
# **
|
|
194
198
|
# ** 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,23 @@ 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
|
+
}
|
|
396
400
|
|
|
397
401
|
def place_order(
|
|
398
402
|
self,
|
|
@@ -454,12 +458,6 @@ class Motilal(Broker):
|
|
|
454
458
|
exception_message = "Order placement failed with error [{}]".format(str(e))
|
|
455
459
|
print(exception_message)
|
|
456
460
|
|
|
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
461
|
@retry(
|
|
464
462
|
wait_exponential_multiplier=3000,
|
|
465
463
|
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,16 @@ 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
|
+
"total_balance": float(cash) + float(holdings_val),
|
|
743
|
+
}
|
|
743
744
|
|
|
744
745
|
return margins
|
|
745
746
|
|
|
@@ -747,20 +748,4 @@ class Noren(Broker):
|
|
|
747
748
|
logger.error(f"[NOREN_MARGIN_ERROR] {e}")
|
|
748
749
|
RetryableException("[NOREN] Failed to fetch account margin")
|
|
749
750
|
|
|
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
|
|
751
|
+
return {"margin_available": 0, "margin_used": 0, "total_balance": 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,11 @@ 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,
|
|
586
588
|
}
|
|
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
589
|
|
|
603
590
|
def stream_order_data(self):
|
|
604
591
|
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,17 @@ class XTS(Broker):
|
|
|
180
181
|
return {
|
|
181
182
|
"margin_used": 0,
|
|
182
183
|
"margin_available": 0,
|
|
184
|
+
"total_balance": 0,
|
|
183
185
|
}
|
|
184
186
|
api_response = api_response["result"]["BalanceList"][0]["limitObject"]
|
|
187
|
+
margin_used = api_response["RMSSubLimits"]["marginUtilized"]
|
|
188
|
+
margin_available = api_response["RMSSubLimits"]["netMarginAvailable"]
|
|
185
189
|
return {
|
|
186
|
-
"margin_used":
|
|
187
|
-
"margin_available":
|
|
190
|
+
"margin_used": margin_used,
|
|
191
|
+
"margin_available": margin_available,
|
|
192
|
+
"total_balance": margin_used + margin_available,
|
|
188
193
|
}
|
|
189
194
|
|
|
190
|
-
def account_summary(self):
|
|
191
|
-
margins = self.margins()
|
|
192
|
-
margins["pnl"] = float(self.positions()["pnl"].sum())
|
|
193
|
-
return margins
|
|
194
|
-
|
|
195
195
|
@retry(
|
|
196
196
|
wait_exponential_multiplier=3000,
|
|
197
197
|
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
|
)
|
|
@@ -521,15 +522,17 @@ class Zerodha(Broker):
|
|
|
521
522
|
stop_max_attempt_number=3,
|
|
522
523
|
retry_on_exception=retry_exception,
|
|
523
524
|
)
|
|
524
|
-
def margins(self) ->
|
|
525
|
+
def margins(self) -> MarginsResponse:
|
|
525
526
|
try:
|
|
526
527
|
margins = self.wrapper.margins()
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
"
|
|
528
|
+
margin_used = float(margins["equity"]["utilised"]["debits"])
|
|
529
|
+
margin_available = float(margins["equity"]["net"])
|
|
530
|
+
response: MarginsResponse = {
|
|
531
|
+
"margin_used": margin_used,
|
|
532
|
+
"margin_available": margin_available,
|
|
533
|
+
"total_balance": margin_used + margin_available,
|
|
531
534
|
}
|
|
532
|
-
return
|
|
535
|
+
return response
|
|
533
536
|
|
|
534
537
|
except TokenException as e:
|
|
535
538
|
raise QuantplayTokenException(str(e))
|
|
@@ -554,15 +557,6 @@ class Zerodha(Broker):
|
|
|
554
557
|
"gst": sum([a["charges"]["gst"]["total"] for a in charges]),
|
|
555
558
|
}
|
|
556
559
|
|
|
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
560
|
@retry(
|
|
567
561
|
wait_exponential_multiplier=3000,
|
|
568
562
|
wait_exponential_max=10000,
|
|
@@ -30,3 +30,9 @@ 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
|
|
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
|
|
File without changes
|
|
File without changes
|