quantplay 2.1.140__tar.gz → 2.1.142__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.1.140 → quantplay-2.1.142}/PKG-INFO +1 -1
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/motilal.py +22 -47
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/upstox.py +1 -1
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/zerodha.py +28 -14
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay.egg-info/PKG-INFO +1 -1
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay.egg-info/SOURCES.txt +1 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/setup.py +1 -1
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_motilal_login.py +22 -0
- quantplay-2.1.142/tests/test_zerodha_positions_add_ltp.py +73 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/README.md +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/pyproject.toml +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/aliceblue.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/aliceblue_utils/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/aliceblue_utils/aliceblue_oauth.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/aliceblue_v2.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/angelone.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/angelone_utils/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/angelone_utils/angeloneWS.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/breeze/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/breeze/breeze_utils.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/broker_factory.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/dhan.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/finvasia_utils/finvasia_oauth.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/five_paisa.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/ft_utils/ft_noren.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/generics/broker.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/icici_direct.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/jainam_xts.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/kotak.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/kotak_utils/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/kotak_utils/kotak_ws.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/kotak_utils/kotak_ws_lib.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/noren.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/uplink/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils/Connect.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils_v2/ConnectV2.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils_v2/InteractiveSocketClientV2.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils_v2/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/core/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/core/strategy.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/indicator/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/indicator/iv.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/model/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/model/broker.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/model/broker_response.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/model/generics.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/model/instrument_data.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/model/order_event.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/py.typed +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/strategy/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/strategy/iv_spike.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/strategy/obuy.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/utils/caching.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/utils/constant.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/utils/redaction.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/wrapper/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/wrapper/aws/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/wrapper/aws/s3.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay/wrapper/redis.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/setup.cfg +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/conftest.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_aliceblue_unified.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_deltax_positions.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_deltax_root_url.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_jainam_xts.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_kotak_order_feed_url.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_log_redaction.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_sub_client_all_types.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/test_xts_v2_modify_order.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/wrapper/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.1.140 → quantplay-2.1.142}/tests/wrapper/aws/s3_test.py +0 -0
|
@@ -85,49 +85,26 @@ class Motilal(Broker):
|
|
|
85
85
|
|
|
86
86
|
self.instrument_data_by_exchange = {}
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"https://
|
|
94
|
-
)
|
|
95
|
-
self.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
self.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
self.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
self.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self.
|
|
108
|
-
"https://{}openapi.motilaloswal.com/rest/login/v1/getprofile".format(uat)
|
|
109
|
-
)
|
|
110
|
-
self.margin_summary_url = "https://{}openapi.motilaloswal.com/rest/report/v1/getreportmarginsummary".format(
|
|
111
|
-
uat
|
|
112
|
-
)
|
|
113
|
-
self.modify_order_url = (
|
|
114
|
-
"https://{}openapi.motilaloswal.com/rest/trans/v2/modifyorder".format(uat)
|
|
115
|
-
)
|
|
116
|
-
self.order_book_url = (
|
|
117
|
-
"https://{}openapi.motilaloswal.com/rest/book/v1/getorderbook".format(uat)
|
|
118
|
-
)
|
|
119
|
-
self.cancel_order_url = (
|
|
120
|
-
"https://{}openapi.motilaloswal.com/rest/trans/v1/cancelorder".format(uat)
|
|
121
|
-
)
|
|
122
|
-
self.positions_url = (
|
|
123
|
-
"https://{}openapi.motilaloswal.com/rest/book/v1/getposition".format(uat)
|
|
124
|
-
)
|
|
125
|
-
self.holdings_url = (
|
|
126
|
-
"https://{}openapi.motilaloswal.com/rest/report/v1/getdpholding".format(uat)
|
|
127
|
-
)
|
|
128
|
-
self.order_details_url = "https://{}openapi.motilaloswal.com/rest/book/v2/getorderdetailbyuniqueorderid".format(
|
|
129
|
-
uat
|
|
130
|
-
)
|
|
88
|
+
# Versions per Motilal's API docs: the v7 login token is rejected (MO8001) by
|
|
89
|
+
# the older v1 data endpoints.
|
|
90
|
+
base = (
|
|
91
|
+
"https://openapi.motilaloswaluat.com/rest"
|
|
92
|
+
if is_uat
|
|
93
|
+
else "https://openapi.motilaloswal.com/rest"
|
|
94
|
+
)
|
|
95
|
+
self.url = f"{base}/login/v7/authdirectapi"
|
|
96
|
+
self.otp_url = f"{base}/login/v5/resendotp"
|
|
97
|
+
self.verify_otp_url = f"{base}/login/v5/verifyotp"
|
|
98
|
+
self.get_profile_url = f"{base}/login/v5/getprofile"
|
|
99
|
+
self.ltp_url = f"{base}/report/v3/getltpdata"
|
|
100
|
+
self.margin_summary_url = f"{base}/report/v3/getreportmarginsummary"
|
|
101
|
+
self.holdings_url = f"{base}/report/v3/getdpholding"
|
|
102
|
+
self.positions_url = f"{base}/book/v4/getposition"
|
|
103
|
+
self.order_book_url = f"{base}/book/v5/getorderbook"
|
|
104
|
+
self.order_details_url = f"{base}/book/v5/getorderdetailbyuniqueorderid"
|
|
105
|
+
self.place_order_url = f"{base}/trans/v2/placeorder"
|
|
106
|
+
self.modify_order_url = f"{base}/trans/v5/modifyorder"
|
|
107
|
+
self.cancel_order_url = f"{base}/trans/v2/cancelorder"
|
|
131
108
|
|
|
132
109
|
try:
|
|
133
110
|
if headers:
|
|
@@ -521,9 +498,7 @@ class Motilal(Broker):
|
|
|
521
498
|
retry_on_exception=retry_exception,
|
|
522
499
|
)
|
|
523
500
|
def __post_request(self, url: str, data: Any):
|
|
524
|
-
|
|
525
|
-
data = {"Clientcode": self.headers["vendorinfo"]}
|
|
526
|
-
data = json.dumps(data)
|
|
501
|
+
data = json.dumps(data or {})
|
|
527
502
|
|
|
528
503
|
api_response = requests.post(
|
|
529
504
|
url,
|
|
@@ -588,7 +563,7 @@ class Motilal(Broker):
|
|
|
588
563
|
holdings_df = holdings_df.with_columns(
|
|
589
564
|
pl.struct(["exchange", "tradingsymbol"])
|
|
590
565
|
.map_elements(
|
|
591
|
-
lambda x:
|
|
566
|
+
lambda x: float(self.ltp(x["exchange"], x["tradingsymbol"])),
|
|
592
567
|
return_dtype=pl.Float64,
|
|
593
568
|
)
|
|
594
569
|
.alias("price")
|
|
@@ -360,7 +360,7 @@ class Upstox(Broker):
|
|
|
360
360
|
holdings_df = holdings_df.with_columns(
|
|
361
361
|
pl.struct(["exchange", "tradingsymbol"])
|
|
362
362
|
.map_elements(
|
|
363
|
-
lambda x:
|
|
363
|
+
lambda x: float(self.ltp(x["exchange"], x["tradingsymbol"])),
|
|
364
364
|
return_dtype=pl.Float64,
|
|
365
365
|
)
|
|
366
366
|
.alias("price")
|
|
@@ -461,26 +461,40 @@ class Zerodha(Broker):
|
|
|
461
461
|
positions_df = positions_df.with_columns(
|
|
462
462
|
(pl.col("exchange") + ":" + pl.col("tradingsymbol")).alias("exchange_symbol")
|
|
463
463
|
)
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
464
|
+
if add_ltp:
|
|
465
|
+
symbols = (
|
|
466
|
+
positions_df.select(pl.col("exchange_symbol").unique())
|
|
467
|
+
.to_series()
|
|
468
|
+
.to_list()
|
|
469
|
+
)
|
|
470
|
+
symbol_ltps = self.get_ltps(symbols)
|
|
471
|
+
ltp_map: dict[str, float] = {}
|
|
472
|
+
for exchange_symbol in symbol_ltps:
|
|
473
|
+
ltp_map[exchange_symbol] = float(
|
|
474
|
+
symbol_ltps[exchange_symbol]["last_price"]
|
|
475
|
+
)
|
|
471
476
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
477
|
+
positions_df = positions_df.with_columns(
|
|
478
|
+
pl.col("exchange_symbol")
|
|
479
|
+
.replace_strict(ltp_map, default=0.0)
|
|
480
|
+
.cast(pl.Float64)
|
|
481
|
+
.alias("ltp")
|
|
482
|
+
)
|
|
483
|
+
else:
|
|
484
|
+
# kite.ltp() needs a paid market-data subscription; callers that only
|
|
485
|
+
# display positions skip it and fill live prices themselves.
|
|
486
|
+
positions_df = positions_df.with_columns(
|
|
487
|
+
pl.lit(None).cast(pl.Float64).alias("ltp")
|
|
488
|
+
)
|
|
478
489
|
|
|
479
490
|
positions_df = positions_df.with_columns(
|
|
480
491
|
(pl.col("sell_value") - pl.col("buy_value")).alias("pnl")
|
|
481
492
|
)
|
|
482
493
|
positions_df = positions_df.with_columns(
|
|
483
|
-
|
|
494
|
+
pl.when(pl.col("quantity") == 0)
|
|
495
|
+
.then(pl.col("pnl"))
|
|
496
|
+
.otherwise(pl.col("quantity") * pl.col("ltp") + pl.col("pnl"))
|
|
497
|
+
.alias("pnl")
|
|
484
498
|
)
|
|
485
499
|
|
|
486
500
|
positions_df = positions_df.with_columns(
|
|
@@ -92,6 +92,7 @@ tests/test_log_redaction.py
|
|
|
92
92
|
tests/test_motilal_login.py
|
|
93
93
|
tests/test_sub_client_all_types.py
|
|
94
94
|
tests/test_xts_v2_modify_order.py
|
|
95
|
+
tests/test_zerodha_positions_add_ltp.py
|
|
95
96
|
tests/wrapper/__init__.py
|
|
96
97
|
tests/wrapper/aws/__init__.py
|
|
97
98
|
tests/wrapper/aws/s3_test.py
|
|
@@ -56,3 +56,25 @@ def test_accounts_do_not_share_header_state() -> None:
|
|
|
56
56
|
def test_login_without_secret_is_rejected() -> None:
|
|
57
57
|
with pytest.raises(RetryableException, match="Missing Arguments"):
|
|
58
58
|
_login(api_secret=None)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_data_endpoints_use_versions_that_accept_v7_tokens() -> None:
|
|
62
|
+
client, _ = _login()
|
|
63
|
+
assert client.get_profile_url.endswith("/login/v5/getprofile")
|
|
64
|
+
assert client.holdings_url.endswith("/report/v3/getdpholding")
|
|
65
|
+
assert client.positions_url.endswith("/book/v4/getposition")
|
|
66
|
+
assert client.order_book_url.endswith("/book/v5/getorderbook")
|
|
67
|
+
assert client.place_order_url.endswith("/trans/v2/placeorder")
|
|
68
|
+
assert client.modify_order_url.endswith("/trans/v5/modifyorder")
|
|
69
|
+
assert client.cancel_order_url.endswith("/trans/v2/cancelorder")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_reads_send_an_empty_body() -> None:
|
|
73
|
+
# v3+ rejects a client sending its own code: MO2031 "Client and Vendor Cannot
|
|
74
|
+
# Enter UserId".
|
|
75
|
+
client, _ = _login()
|
|
76
|
+
response = MagicMock()
|
|
77
|
+
response.json.return_value = {"status": "SUCCESS", "data": []}
|
|
78
|
+
with patch("quantplay.broker.motilal.requests.post", return_value=response) as post:
|
|
79
|
+
client.margins()
|
|
80
|
+
assert post.call_args.kwargs["data"] == "{}"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from unittest.mock import MagicMock
|
|
3
|
+
|
|
4
|
+
import polars as pl
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from quantplay.broker.zerodha import Zerodha
|
|
8
|
+
from quantplay.exception.exceptions import TokenException
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _position(symbol: str, quantity: int, buy: float, sell: float) -> dict[str, Any]:
|
|
12
|
+
return {
|
|
13
|
+
"tradingsymbol": symbol,
|
|
14
|
+
"exchange": "NFO",
|
|
15
|
+
"product": "NRML",
|
|
16
|
+
"quantity": quantity,
|
|
17
|
+
"average_price": 100.0,
|
|
18
|
+
"buy_quantity": 50,
|
|
19
|
+
"sell_quantity": 50 - quantity,
|
|
20
|
+
"buy_value": buy,
|
|
21
|
+
"sell_value": sell,
|
|
22
|
+
"buy_price": 100.0,
|
|
23
|
+
"sell_price": 100.0,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def broker() -> Zerodha:
|
|
29
|
+
zerodha = object.__new__(Zerodha)
|
|
30
|
+
zerodha.wrapper = MagicMock()
|
|
31
|
+
zerodha.invoke_kite_api = MagicMock( # type: ignore[method-assign]
|
|
32
|
+
return_value={
|
|
33
|
+
"net": [
|
|
34
|
+
_position("NIFTY26N0624000CE", 50, 5000.0, 0.0),
|
|
35
|
+
_position("NIFTY26N0624000PE", 0, 5000.0, 6000.0),
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
zerodha.symbol_attribute = MagicMock(return_value=123) # type: ignore[method-assign]
|
|
40
|
+
return zerodha
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_add_ltp_false_skips_market_data_call(broker: Zerodha) -> None:
|
|
44
|
+
# kite.ltp() fails without a market-data subscription; add_ltp=False must not call it
|
|
45
|
+
broker.get_ltps = MagicMock( # type: ignore[method-assign]
|
|
46
|
+
side_effect=TokenException("LTP Calls Require Market Data Subscription")
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
positions = broker.positions(add_ltp=False)
|
|
50
|
+
|
|
51
|
+
broker.get_ltps.assert_not_called()
|
|
52
|
+
rows = {r["tradingsymbol"]: r for r in positions.to_dicts()}
|
|
53
|
+
assert rows["NIFTY26N0624000CE"]["ltp"] is None
|
|
54
|
+
assert rows["NIFTY26N0624000CE"]["pnl"] is None
|
|
55
|
+
assert rows["NIFTY26N0624000PE"]["ltp"] is None
|
|
56
|
+
assert rows["NIFTY26N0624000PE"]["pnl"] == 1000.0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_add_ltp_true_unchanged(broker: Zerodha) -> None:
|
|
60
|
+
broker.get_ltps = MagicMock( # type: ignore[method-assign]
|
|
61
|
+
return_value={
|
|
62
|
+
"NFO:NIFTY26N0624000CE": {"last_price": 120.0},
|
|
63
|
+
"NFO:NIFTY26N0624000PE": {"last_price": 80.0},
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
positions = broker.positions(add_ltp=True)
|
|
68
|
+
|
|
69
|
+
rows = {r["tradingsymbol"]: r for r in positions.to_dicts()}
|
|
70
|
+
assert rows["NIFTY26N0624000CE"]["ltp"] == 120.0
|
|
71
|
+
assert rows["NIFTY26N0624000CE"]["pnl"] == 50 * 120.0 - 5000.0
|
|
72
|
+
assert rows["NIFTY26N0624000PE"]["pnl"] == 1000.0
|
|
73
|
+
assert positions.schema == pl.Schema(broker.positions_schema)
|
|
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
|
{quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils/InteractiveSocketClient.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quantplay-2.1.140 → quantplay-2.1.142}/quantplay/broker/xts_utils_v2/InteractiveSocketClientV2.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
|
|
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
|