bw-essentials-core 0.1.5__py3-none-any.whl → 0.1.7__py3-none-any.whl
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.
Potentially problematic release.
This version of bw-essentials-core might be problematic. Click here for more details.
- bw_essentials/constants/services.py +10 -0
- bw_essentials/services/portfolio_catalogue.py +56 -1
- bw_essentials/services/user_portfolio_reporting.py +18 -1
- {bw_essentials_core-0.1.5.dist-info → bw_essentials_core-0.1.7.dist-info}/METADATA +1 -1
- {bw_essentials_core-0.1.5.dist-info → bw_essentials_core-0.1.7.dist-info}/RECORD +7 -7
- {bw_essentials_core-0.1.5.dist-info → bw_essentials_core-0.1.7.dist-info}/WHEEL +0 -0
- {bw_essentials_core-0.1.5.dist-info → bw_essentials_core-0.1.7.dist-info}/top_level.txt +0 -0
|
@@ -20,3 +20,13 @@ class Services(Enum):
|
|
|
20
20
|
PROMETHEUS_USER_APP = "Prometheus_User_App"
|
|
21
21
|
PORTFOLIO_CATALOGUE = "Portfolio_Catalogue"
|
|
22
22
|
PORTFOLIO_CONTENT = "Portfolio_Content"
|
|
23
|
+
|
|
24
|
+
class PortfolioStatus(Enum):
|
|
25
|
+
"""
|
|
26
|
+
Enum representing Status of Basket.
|
|
27
|
+
"""
|
|
28
|
+
ACTIVE = "active"
|
|
29
|
+
INACTIVE = "inactive"
|
|
30
|
+
PAUSED = "paused"
|
|
31
|
+
|
|
32
|
+
ACTIVE_FOR_SUBSCRIBED_USER = (ACTIVE, PAUSED)
|
|
@@ -48,7 +48,7 @@ Example
|
|
|
48
48
|
import logging
|
|
49
49
|
from typing import Optional, Dict, Any
|
|
50
50
|
|
|
51
|
-
from bw_essentials.constants.services import Services
|
|
51
|
+
from bw_essentials.constants.services import Services, PortfolioStatus
|
|
52
52
|
from bw_essentials.services.api_client import ApiClient
|
|
53
53
|
|
|
54
54
|
logger = logging.getLogger(__name__)
|
|
@@ -78,6 +78,7 @@ class PortfolioCatalogue(ApiClient):
|
|
|
78
78
|
self.name = Services.PORTFOLIO_CATALOGUE.value
|
|
79
79
|
self.urls = {
|
|
80
80
|
"rebalance": "rebalance",
|
|
81
|
+
"get_rebalance": "rebalance"
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
def create_rebalance(self, json: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
@@ -102,3 +103,57 @@ class PortfolioCatalogue(ApiClient):
|
|
|
102
103
|
)
|
|
103
104
|
logger.info("%s", data)
|
|
104
105
|
return data
|
|
106
|
+
|
|
107
|
+
def rebalance(self, portfolio_id, status):
|
|
108
|
+
"""Fetch the latest rebalance record for a portfolio.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
portfolio_id : str
|
|
113
|
+
Portfolio identifier.
|
|
114
|
+
status : str
|
|
115
|
+
Portfolio status filter.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
dict
|
|
120
|
+
The first record from the service response's 'data' list.
|
|
121
|
+
"""
|
|
122
|
+
logger.info("In - rebalance portfolio_id=%s status=%s", portfolio_id, status)
|
|
123
|
+
data = self._get(
|
|
124
|
+
url=self.base_url,
|
|
125
|
+
endpoint=self.urls["get_rebalance"],
|
|
126
|
+
params={'portfolioId': portfolio_id, 'status': status}
|
|
127
|
+
)
|
|
128
|
+
logger.info("rebalance response: %s", data)
|
|
129
|
+
return data.get('data')[0]
|
|
130
|
+
|
|
131
|
+
def get_rebalance_due_date(self, portfolio_id, status):
|
|
132
|
+
"""Return the next rebalance date for an active portfolio, else None.
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
portfolio_id : str
|
|
137
|
+
Portfolio identifier.
|
|
138
|
+
status : str
|
|
139
|
+
Portfolio status.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
str | None
|
|
144
|
+
The next rebalance date string if available; otherwise None.
|
|
145
|
+
"""
|
|
146
|
+
logger.info(
|
|
147
|
+
"In - get_rebalance_due_date portfolio_id=%s status=%s",
|
|
148
|
+
portfolio_id,
|
|
149
|
+
status,
|
|
150
|
+
)
|
|
151
|
+
if status in PortfolioStatus.ACTIVE_FOR_SUBSCRIBED_USER.value:
|
|
152
|
+
rebalance_history = self.rebalance(portfolio_id, status)
|
|
153
|
+
next_rebalance_date = (
|
|
154
|
+
rebalance_history.get('nextRebalanceDate') if rebalance_history else None
|
|
155
|
+
)
|
|
156
|
+
logger.info("nextRebalanceDate=%s", next_rebalance_date)
|
|
157
|
+
return next_rebalance_date
|
|
158
|
+
logger.info("get_rebalance_due_date not applicable for status=%s", status)
|
|
159
|
+
return None
|
|
@@ -65,7 +65,8 @@ class UserReporting(ApiClient):
|
|
|
65
65
|
self.urls = {
|
|
66
66
|
"instructions": "reporting/instructions/",
|
|
67
67
|
"portfolio_performance": "reporting/user/%s/userportfolio/%s/performance/",
|
|
68
|
-
"portfolio_performance_breakdown": "reporting/user/%s/userportfolio/%s/performance/breakdown/"
|
|
68
|
+
"portfolio_performance_breakdown": "reporting/user/%s/userportfolio/%s/performance/breakdown/",
|
|
69
|
+
'portfolio_stock_performance': "reporting/user/%s/userportfolio/%s/stock/performance/"
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
def _get_integer_quantity(self, qty, side):
|
|
@@ -151,3 +152,19 @@ class UserReporting(ApiClient):
|
|
|
151
152
|
endpoint=endpoint)
|
|
152
153
|
logger.info(f"{data =}")
|
|
153
154
|
return data.get("data")
|
|
155
|
+
|
|
156
|
+
def get_portfolio_stock_performance(self, user_id, user_portfolio_id):
|
|
157
|
+
"""
|
|
158
|
+
Retrieves a detailed breakdown of portfolio pnl
|
|
159
|
+
|
|
160
|
+
:param user_id: ID of the user
|
|
161
|
+
:param user_portfolio_id: ID of the user portfolio
|
|
162
|
+
:return: Performance breakdown data from the response
|
|
163
|
+
"""
|
|
164
|
+
logger.info(f"In get_portfolio_stock_performance {user_id=}, {user_portfolio_id=}")
|
|
165
|
+
endpoint = self.urls.get('portfolio_stock_performance') % (
|
|
166
|
+
user_id, user_portfolio_id)
|
|
167
|
+
data = self._get(url=self.base_url,
|
|
168
|
+
endpoint=endpoint)
|
|
169
|
+
logger.info(f"{data=}")
|
|
170
|
+
return data.get("data")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
bw_essentials/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
bw_essentials/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
bw_essentials/constants/services.py,sha256=
|
|
3
|
+
bw_essentials/constants/services.py,sha256=jFP9QnzgYK-PUJT3oigpdaesYnnzLN-D5REe3Bdkwms,864
|
|
4
4
|
bw_essentials/data_loch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
bw_essentials/data_loch/data_loch.py,sha256=iJO0oPhZyQjoUZOaeBP1nsbuc5iR9ZNWoAXj2pGEpT8,11716
|
|
6
6
|
bw_essentials/email_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -17,13 +17,13 @@ bw_essentials/services/market_pricer.py,sha256=Qc9lxzAjhefAvjyEKsBPDu60bF6_61cnS
|
|
|
17
17
|
bw_essentials/services/master_data.py,sha256=2o_r2gdhIKBeTFgn5IIY-becgCEpYBymO4BKmixdV1g,11987
|
|
18
18
|
bw_essentials/services/model_portfolio_reporting.py,sha256=iOtm4gyfU8P7C0R1gp6gUJI4ZRxJD5K2GLOalI_gToM,3249
|
|
19
19
|
bw_essentials/services/notification.py,sha256=q4jIZzIWIHvn-XaIIbkEjjhkYUV8ZGQWUXaY4NNRFgI,5078
|
|
20
|
-
bw_essentials/services/portfolio_catalogue.py,sha256=
|
|
20
|
+
bw_essentials/services/portfolio_catalogue.py,sha256=y1sJENAsr8sSy_oeHqdZUGWfcV19FAHICMWYpJFRA4s,4944
|
|
21
21
|
bw_essentials/services/portfolio_content.py,sha256=rdFTTsUUIt-AgFfA1SAItqg2njakVOm4dUKU0FHZQ2E,2148
|
|
22
22
|
bw_essentials/services/trade_placement.py,sha256=PrzeU2XXC9HF1IQ1dMDM_ZHxmC491sOl-JbA6GWPwII,20772
|
|
23
23
|
bw_essentials/services/user_app.py,sha256=_Y2NgDq6kEoco7ZRJ3-MMYJ-K2HGStJoFoeGOH_HotQ,11107
|
|
24
24
|
bw_essentials/services/user_portfolio.py,sha256=_5M6yPfQt4MXedINBawEoPkb_o7IGzxPeHkvZkoQm8k,16191
|
|
25
|
-
bw_essentials/services/user_portfolio_reporting.py,sha256=
|
|
26
|
-
bw_essentials_core-0.1.
|
|
27
|
-
bw_essentials_core-0.1.
|
|
28
|
-
bw_essentials_core-0.1.
|
|
29
|
-
bw_essentials_core-0.1.
|
|
25
|
+
bw_essentials/services/user_portfolio_reporting.py,sha256=pwqfW95LTiGOGufcTphljFxPlOd-G4Q263UtoQURPxM,6772
|
|
26
|
+
bw_essentials_core-0.1.7.dist-info/METADATA,sha256=QKkFUyEBpJkb6rbJ8jPV6iA1v6R0MORD9830OPz6k9c,7501
|
|
27
|
+
bw_essentials_core-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
28
|
+
bw_essentials_core-0.1.7.dist-info/top_level.txt,sha256=gDc5T_y5snwKGXDQUusEus-FEt0RFwG644Yn_58wQOQ,14
|
|
29
|
+
bw_essentials_core-0.1.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|