quantplay 2.1.141__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.141 → quantplay-2.1.142}/PKG-INFO +1 -1
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/zerodha.py +28 -14
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay.egg-info/PKG-INFO +1 -1
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay.egg-info/SOURCES.txt +1 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/setup.py +1 -1
- quantplay-2.1.142/tests/test_zerodha_positions_add_ltp.py +73 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/README.md +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/pyproject.toml +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/aliceblue.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/aliceblue_utils/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/aliceblue_utils/aliceblue_oauth.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/aliceblue_v2.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/angelone.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/angelone_utils/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/angelone_utils/angeloneWS.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/breeze/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/breeze/breeze_utils.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/broker_factory.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/dhan.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/finvasia_utils/finvasia_oauth.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/five_paisa.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/ft_utils/ft_noren.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/generics/broker.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/icici_direct.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/jainam_xts.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/kotak.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/kotak_utils/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/kotak_utils/kotak_ws.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/kotak_utils/kotak_ws_lib.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/motilal.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/noren.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/uplink/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/upstox.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts_utils/Connect.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts_utils/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts_utils_v2/ConnectV2.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts_utils_v2/InteractiveSocketClientV2.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts_utils_v2/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/core/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/core/strategy.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/indicator/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/indicator/iv.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/model/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/model/broker.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/model/broker_response.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/model/generics.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/model/instrument_data.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/model/order_event.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/py.typed +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/strategy/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/strategy/iv_spike.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/strategy/obuy.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/utils/caching.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/utils/constant.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/utils/redaction.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/wrapper/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/wrapper/aws/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/wrapper/aws/s3.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay/wrapper/redis.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/setup.cfg +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/conftest.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_aliceblue_unified.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_deltax_positions.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_deltax_root_url.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_jainam_xts.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_kotak_order_feed_url.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_log_redaction.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_motilal_login.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_sub_client_all_types.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/test_xts_v2_modify_order.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/wrapper/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.1.141 → quantplay-2.1.142}/tests/wrapper/aws/s3_test.py +0 -0
|
@@ -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
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
{quantplay-2.1.141 → quantplay-2.1.142}/quantplay/broker/xts_utils/InteractiveSocketClient.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quantplay-2.1.141 → 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
|
|
File without changes
|