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.

@@ -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
  Metadata-Version: 2.4
2
2
  Name: bw-essentials-core
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: Reusable utilities for S3, email, Data Loch, Microsoft Teams Notifications and more.
5
5
  Author: InvestorAI
6
6
  Author-email: support+tech@investorai.in
@@ -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=IcJNd2w7bfEjvEvrkKg9te_71l4rntvU_g4gOMbmrDE,653
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=sLS7tYW7AkCEXYt8oWdXhmzgzvHCH9nKKFl47y8-c9c,3070
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=QaZzcw912Uos5ZafEaxLXDmCyetTFiVX3at3cTAv6MA,6003
26
- bw_essentials_core-0.1.5.dist-info/METADATA,sha256=O4CWWEYI-OtPf6TaJdXXZXCU3suvgqBA0jjKLbLcNBI,7501
27
- bw_essentials_core-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
- bw_essentials_core-0.1.5.dist-info/top_level.txt,sha256=gDc5T_y5snwKGXDQUusEus-FEt0RFwG644Yn_58wQOQ,14
29
- bw_essentials_core-0.1.5.dist-info/RECORD,,
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,,