vibhorag101
commited on
Commit
•
57f491f
1
Parent(s):
0530756
Added inception date toggle
Browse files
app.py
CHANGED
@@ -4,7 +4,6 @@ import plotly.graph_objects as go
|
|
4 |
from datetime import datetime, timedelta
|
5 |
import requests
|
6 |
|
7 |
-
|
8 |
js_func = """
|
9 |
function refresh() {
|
10 |
const url = new URL(window.location);
|
@@ -24,9 +23,10 @@ def get_nav_data(scheme_code):
|
|
24 |
df['date'] = pd.to_datetime(df['date'], format='%d-%m-%Y')
|
25 |
df['nav'] = df['nav'].astype(float)
|
26 |
df = df.sort_values('date')
|
27 |
-
|
|
|
28 |
|
29 |
-
def calculate_sip_returns(nav_data, sip_amount, start_date, end_date,SIP_Date):
|
30 |
start_date = pd.Timestamp(start_date)
|
31 |
end_date = pd.Timestamp(end_date)
|
32 |
|
@@ -60,21 +60,23 @@ def create_pie_chart(schemes):
|
|
60 |
fig.update_layout(title_text="Scheme Weightages")
|
61 |
return fig
|
62 |
|
63 |
-
def calculate_portfolio_returns(schemes, sip_amount, start_date, end_date, SIP_date,schemes_df):
|
64 |
scheme_returns = []
|
65 |
total_investment = 0
|
66 |
final_value = 0
|
|
|
67 |
|
68 |
for scheme_name, scheme_weight in schemes.items():
|
69 |
scheme_code = schemes_df[schemes_df['schemeName'] == scheme_name]['schemeCode'].values[0]
|
70 |
-
nav_data = get_nav_data(scheme_code)
|
71 |
-
|
|
|
72 |
scheme_returns.append((scheme_name, scheme_return))
|
73 |
final_value += scheme_final_value
|
74 |
total_investment += scheme_total_investment
|
75 |
|
76 |
portfolio_return = (final_value - total_investment) / total_investment * 100
|
77 |
-
return portfolio_return, final_value, total_investment, scheme_returns
|
78 |
|
79 |
def update_sip_calculator(*args):
|
80 |
period = args[0]
|
@@ -85,10 +87,12 @@ def update_sip_calculator(*args):
|
|
85 |
schemes_df = args[5]
|
86 |
schemes = {}
|
87 |
|
88 |
-
for i in range(6, len(args), 2):
|
89 |
if args[i] and args[i+1]:
|
90 |
schemes[args[i]] = float(args[i+1])
|
91 |
|
|
|
|
|
92 |
if not schemes:
|
93 |
return "Please add at least one scheme.", None, None, None
|
94 |
|
@@ -96,30 +100,48 @@ def update_sip_calculator(*args):
|
|
96 |
|
97 |
end_date = datetime.now().date()
|
98 |
|
99 |
-
if
|
|
|
|
|
100 |
if not custom_start_date or not custom_end_date:
|
101 |
return "Please provide both start and end dates for custom period.", None, None, None
|
102 |
start_date = datetime.strptime(custom_start_date, "%Y-%m-%d").date()
|
103 |
end_date = datetime.strptime(custom_end_date, "%Y-%m-%d").date()
|
104 |
-
|
105 |
elif period == "YTD":
|
106 |
-
start_date = datetime(end_date.year, 1, 1)
|
107 |
-
|
|
|
108 |
else:
|
109 |
-
|
110 |
-
if
|
111 |
-
|
|
|
|
|
|
|
112 |
start_date = end_date - timedelta(days=years*365)
|
113 |
else:
|
114 |
-
months = int(
|
115 |
start_date = end_date - timedelta(days=months*30)
|
116 |
|
117 |
try:
|
118 |
-
portfolio_return, final_value, total_investment, scheme_returns = calculate_portfolio_returns(schemes, sip_amount, start_date, end_date, SIP_Date,schemes_df)
|
119 |
except Exception as e:
|
120 |
return f"Error: {str(e)}", None, None, None
|
121 |
|
122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
result += f"Total investment: ₹{total_investment:.2f}\n"
|
124 |
result += f"Final value: ₹{final_value:.2f}\n\n"
|
125 |
result += "Individual scheme returns:\n"
|
@@ -182,17 +204,13 @@ def update_schemes(schemes_list, updated_data):
|
|
182 |
error_msg = f"Error updating schemes: {str(e)}"
|
183 |
return schemes_list, update_schemes_table(schemes_list), error_msg
|
184 |
|
185 |
-
def prepare_inputs(period, custom_start, custom_end,SIP_Date,sip_amount, schemes_list, schemes_df
|
186 |
-
inputs = [period, custom_start, custom_end,SIP_Date, sip_amount, schemes_df]
|
187 |
for name, weight in schemes_list:
|
188 |
inputs.extend([name, weight])
|
189 |
return inputs
|
190 |
|
191 |
def handle_row_selection(schemes_list, evt: gr.SelectData, table_data):
|
192 |
-
# print(f"Event data: {evt}")
|
193 |
-
# print(f"Event index: {evt.index}")
|
194 |
-
# print(f"Table data: {table_data}")
|
195 |
-
|
196 |
if evt.index is not None and len(evt.index) > 1:
|
197 |
column_index = evt.index[1]
|
198 |
if column_index == 2: # "Actions" column
|
@@ -204,11 +222,6 @@ def handle_row_selection(schemes_list, evt: gr.SelectData, table_data):
|
|
204 |
return table_data, updated_schemes_list
|
205 |
return table_data, schemes_list
|
206 |
|
207 |
-
def update_schemes_table(schemes_list):
|
208 |
-
df = pd.DataFrame(schemes_list, columns=["Scheme Name", "Weight (%)"])
|
209 |
-
df["Actions"] = "❌"
|
210 |
-
return df
|
211 |
-
|
212 |
def create_ui():
|
213 |
schemes_df = fetch_scheme_data()
|
214 |
|
@@ -220,6 +233,9 @@ def create_ui():
|
|
220 |
custom_start_date = gr.Textbox(label="Custom Start Date (YYYY-MM-DD)", visible=False)
|
221 |
custom_end_date = gr.Textbox(label="Custom End Date (YYYY-MM-DD)", visible=False)
|
222 |
SIP_Date = gr.Dropdown(label="Monthly SIP Date", choices=["start","middle","end"])
|
|
|
|
|
|
|
223 |
|
224 |
sip_amount = gr.Number(label="SIP Amount (₹)")
|
225 |
|
@@ -241,7 +257,7 @@ def create_ui():
|
|
241 |
|
242 |
update_button = gr.Button("Update Schemes")
|
243 |
error_message = gr.Textbox(label="Error", visible=False)
|
244 |
-
|
245 |
calculate_button = gr.Button("Calculate Returns")
|
246 |
|
247 |
result = gr.Textbox(label="Results")
|
@@ -286,9 +302,42 @@ def create_ui():
|
|
286 |
inputs=[schemes_list, schemes_table],
|
287 |
outputs=[schemes_table, schemes_list]
|
288 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
calculate_button.click(
|
290 |
-
lambda *args: update_sip_calculator(*
|
291 |
-
inputs=[period, custom_start_date, custom_end_date,SIP_Date,sip_amount, schemes_list, gr.State(schemes_df)],
|
292 |
outputs=[result, pie_chart, final_value, total_investment]
|
293 |
)
|
294 |
|
|
|
4 |
from datetime import datetime, timedelta
|
5 |
import requests
|
6 |
|
|
|
7 |
js_func = """
|
8 |
function refresh() {
|
9 |
const url = new URL(window.location);
|
|
|
23 |
df['date'] = pd.to_datetime(df['date'], format='%d-%m-%Y')
|
24 |
df['nav'] = df['nav'].astype(float)
|
25 |
df = df.sort_values('date')
|
26 |
+
inception_date = df['date'].min()
|
27 |
+
return df, inception_date
|
28 |
|
29 |
+
def calculate_sip_returns(nav_data, sip_amount, start_date, end_date, SIP_Date):
|
30 |
start_date = pd.Timestamp(start_date)
|
31 |
end_date = pd.Timestamp(end_date)
|
32 |
|
|
|
60 |
fig.update_layout(title_text="Scheme Weightages")
|
61 |
return fig
|
62 |
|
63 |
+
def calculate_portfolio_returns(schemes, sip_amount, start_date, end_date, SIP_date, schemes_df):
|
64 |
scheme_returns = []
|
65 |
total_investment = 0
|
66 |
final_value = 0
|
67 |
+
inception_dates = []
|
68 |
|
69 |
for scheme_name, scheme_weight in schemes.items():
|
70 |
scheme_code = schemes_df[schemes_df['schemeName'] == scheme_name]['schemeCode'].values[0]
|
71 |
+
nav_data, inception_date = get_nav_data(scheme_code)
|
72 |
+
inception_dates.append((scheme_name, inception_date))
|
73 |
+
scheme_return, scheme_final_value, scheme_total_investment = calculate_sip_returns(nav_data, sip_amount * scheme_weight / 100, start_date, end_date, SIP_date)
|
74 |
scheme_returns.append((scheme_name, scheme_return))
|
75 |
final_value += scheme_final_value
|
76 |
total_investment += scheme_total_investment
|
77 |
|
78 |
portfolio_return = (final_value - total_investment) / total_investment * 100
|
79 |
+
return portfolio_return, final_value, total_investment, scheme_returns, inception_dates
|
80 |
|
81 |
def update_sip_calculator(*args):
|
82 |
period = args[0]
|
|
|
87 |
schemes_df = args[5]
|
88 |
schemes = {}
|
89 |
|
90 |
+
for i in range(6, len(args) - 1, 2): # Adjust range to account for use_inception_date
|
91 |
if args[i] and args[i+1]:
|
92 |
schemes[args[i]] = float(args[i+1])
|
93 |
|
94 |
+
use_inception_date = args[-1] # Get use_inception_date from the last argument
|
95 |
+
|
96 |
if not schemes:
|
97 |
return "Please add at least one scheme.", None, None, None
|
98 |
|
|
|
100 |
|
101 |
end_date = datetime.now().date()
|
102 |
|
103 |
+
if use_inception_date:
|
104 |
+
start_date = datetime.strptime(custom_start_date, "%Y-%m-%d").date()
|
105 |
+
elif period == "Custom":
|
106 |
if not custom_start_date or not custom_end_date:
|
107 |
return "Please provide both start and end dates for custom period.", None, None, None
|
108 |
start_date = datetime.strptime(custom_start_date, "%Y-%m-%d").date()
|
109 |
end_date = datetime.strptime(custom_end_date, "%Y-%m-%d").date()
|
|
|
110 |
elif period == "YTD":
|
111 |
+
start_date = datetime(end_date.year, 1, 1).date()
|
112 |
+
elif not period:
|
113 |
+
return "Please select a period, provide custom dates, or use the inception date.", None, None, None
|
114 |
else:
|
115 |
+
period_parts = period.split()
|
116 |
+
if len(period_parts) < 2:
|
117 |
+
return "Invalid period selected.", None, None, None
|
118 |
+
|
119 |
+
if 'year' in period_parts[1]:
|
120 |
+
years = int(period_parts[0])
|
121 |
start_date = end_date - timedelta(days=years*365)
|
122 |
else:
|
123 |
+
months = int(period_parts[0])
|
124 |
start_date = end_date - timedelta(days=months*30)
|
125 |
|
126 |
try:
|
127 |
+
portfolio_return, final_value, total_investment, scheme_returns, inception_dates = calculate_portfolio_returns(schemes, sip_amount, start_date, end_date, SIP_Date, schemes_df)
|
128 |
except Exception as e:
|
129 |
return f"Error: {str(e)}", None, None, None
|
130 |
|
131 |
+
# Check if start_date is before any scheme's inception date
|
132 |
+
inception_warnings = []
|
133 |
+
earliest_inception_date = min(inception_date for _, inception_date in inception_dates)
|
134 |
+
for scheme_name, inception_date in inception_dates:
|
135 |
+
if start_date < inception_date.date():
|
136 |
+
inception_warnings.append(f"Warning: {scheme_name} inception date ({inception_date.date()}) is after the chosen start date ({start_date}).")
|
137 |
+
|
138 |
+
result = ""
|
139 |
+
if inception_warnings:
|
140 |
+
result += "The following warnings were found:\n"
|
141 |
+
result += "\n".join(inception_warnings) + "\n\n"
|
142 |
+
result += f"The earliest possible start date for all chosen schemes is: {earliest_inception_date.date()}\n\n"
|
143 |
+
|
144 |
+
result += f"Total portfolio SIP return: {portfolio_return:.2f}%\n"
|
145 |
result += f"Total investment: ₹{total_investment:.2f}\n"
|
146 |
result += f"Final value: ₹{final_value:.2f}\n\n"
|
147 |
result += "Individual scheme returns:\n"
|
|
|
204 |
error_msg = f"Error updating schemes: {str(e)}"
|
205 |
return schemes_list, update_schemes_table(schemes_list), error_msg
|
206 |
|
207 |
+
def prepare_inputs(period, custom_start, custom_end, SIP_Date, sip_amount, schemes_list, schemes_df):
|
208 |
+
inputs = [period, custom_start, custom_end, SIP_Date, sip_amount, schemes_df]
|
209 |
for name, weight in schemes_list:
|
210 |
inputs.extend([name, weight])
|
211 |
return inputs
|
212 |
|
213 |
def handle_row_selection(schemes_list, evt: gr.SelectData, table_data):
|
|
|
|
|
|
|
|
|
214 |
if evt.index is not None and len(evt.index) > 1:
|
215 |
column_index = evt.index[1]
|
216 |
if column_index == 2: # "Actions" column
|
|
|
222 |
return table_data, updated_schemes_list
|
223 |
return table_data, schemes_list
|
224 |
|
|
|
|
|
|
|
|
|
|
|
225 |
def create_ui():
|
226 |
schemes_df = fetch_scheme_data()
|
227 |
|
|
|
233 |
custom_start_date = gr.Textbox(label="Custom Start Date (YYYY-MM-DD)", visible=False)
|
234 |
custom_end_date = gr.Textbox(label="Custom End Date (YYYY-MM-DD)", visible=False)
|
235 |
SIP_Date = gr.Dropdown(label="Monthly SIP Date", choices=["start","middle","end"])
|
236 |
+
with gr.Column():
|
237 |
+
use_inception_date = gr.Checkbox(label="Use Earliest Inception Date", value=False)
|
238 |
+
inception_date_display = gr.Textbox(label="Earliest Inception Date", interactive=False)
|
239 |
|
240 |
sip_amount = gr.Number(label="SIP Amount (₹)")
|
241 |
|
|
|
257 |
|
258 |
update_button = gr.Button("Update Schemes")
|
259 |
error_message = gr.Textbox(label="Error", visible=False)
|
260 |
+
|
261 |
calculate_button = gr.Button("Calculate Returns")
|
262 |
|
263 |
result = gr.Textbox(label="Results")
|
|
|
302 |
inputs=[schemes_list, schemes_table],
|
303 |
outputs=[schemes_table, schemes_list]
|
304 |
)
|
305 |
+
|
306 |
+
def get_earliest_inception_date(schemes_list, schemes_df):
|
307 |
+
inception_dates = []
|
308 |
+
for scheme_name, _ in schemes_list:
|
309 |
+
scheme_code = schemes_df[schemes_df['schemeName'] == scheme_name]['schemeCode'].values[0]
|
310 |
+
_, inception_date = get_nav_data(scheme_code)
|
311 |
+
inception_dates.append(inception_date)
|
312 |
+
return max(inception_dates).strftime("%Y-%m-%d") if inception_dates else ""
|
313 |
+
|
314 |
+
def update_inception_date(use_inception_date, schemes_list, schemes_df):
|
315 |
+
if use_inception_date and schemes_list:
|
316 |
+
earliest_inception_date = get_earliest_inception_date(schemes_list, schemes_df)
|
317 |
+
return gr.update(value=earliest_inception_date, visible=True)
|
318 |
+
else:
|
319 |
+
return gr.update(value="", visible=False)
|
320 |
+
|
321 |
+
use_inception_date.change(
|
322 |
+
update_inception_date,
|
323 |
+
inputs=[use_inception_date, schemes_list, gr.State(schemes_df)],
|
324 |
+
outputs=inception_date_display
|
325 |
+
)
|
326 |
+
|
327 |
+
def prepare_inputs_with_inception(period, custom_start, custom_end, SIP_Date, sip_amount, schemes_list, schemes_df, use_inception_date, inception_date_display):
|
328 |
+
inputs = [period, custom_start, custom_end, SIP_Date, sip_amount, schemes_df]
|
329 |
+
for name, weight in schemes_list:
|
330 |
+
inputs.extend([name, weight])
|
331 |
+
|
332 |
+
inputs.append(use_inception_date) # Add use_inception_date to the inputs
|
333 |
+
if use_inception_date and inception_date_display:
|
334 |
+
inputs[1] = inception_date_display # Replace custom_start with inception_date_display
|
335 |
+
|
336 |
+
return inputs
|
337 |
+
|
338 |
calculate_button.click(
|
339 |
+
lambda *args: update_sip_calculator(*prepare_inputs_with_inception(*args)),
|
340 |
+
inputs=[period, custom_start_date, custom_end_date, SIP_Date, sip_amount, schemes_list, gr.State(schemes_df), use_inception_date, inception_date_display],
|
341 |
outputs=[result, pie_chart, final_value, total_investment]
|
342 |
)
|
343 |
|