0xrushi commited on
Commit
fcd46c3
·
verified ·
1 Parent(s): 57fb7e5

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -0
app.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import yfinance as yf
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+ from datetime import datetime, timedelta
6
+
7
+ def fetch_stock_data(symbol, start_date, end_date):
8
+ return yf.download(symbol, start=start_date, end=end_date)
9
+
10
+ def backtest_mixed_investment(data, start_date, end_date, monthly_investment, stock_allocation, savings_rate):
11
+ investment_dates = []
12
+ stock_shares = 0
13
+ savings_balance = 0
14
+ total_invested = 0
15
+ stock_value = []
16
+ savings_value = []
17
+
18
+ stock_investment = monthly_investment * stock_allocation
19
+ savings_investment = monthly_investment * (1 - stock_allocation)
20
+ daily_rate = (1 + savings_rate) ** (1/365) - 1
21
+
22
+ current_date = pd.to_datetime(start_date)
23
+ prev_date = current_date
24
+ while current_date <= pd.to_datetime(end_date):
25
+ if current_date in data.index:
26
+ price = data.loc[current_date, 'Adj Close']
27
+ new_shares = stock_investment / price
28
+ stock_shares += new_shares
29
+
30
+ days_passed = (current_date - prev_date).days
31
+ savings_balance *= (1 + daily_rate) ** days_passed
32
+ savings_balance += savings_investment
33
+
34
+ total_invested += monthly_investment
35
+
36
+ investment_dates.append(current_date)
37
+ stock_value.append(stock_shares * price)
38
+ savings_value.append(savings_balance)
39
+
40
+ prev_date = current_date
41
+
42
+ current_date += pd.DateOffset(months=1)
43
+
44
+ stock_value_series = pd.Series(stock_value, index=investment_dates).reindex(data.index, method='ffill')
45
+ savings_value_series = pd.Series(savings_value, index=investment_dates).reindex(data.index, method='ffill')
46
+ portfolio_value = stock_value_series + savings_value_series
47
+
48
+ return portfolio_value, stock_value_series, savings_value_series, total_invested
49
+
50
+ def backtest_stock_only(data, start_date, end_date, monthly_investment):
51
+ investment_dates = []
52
+ total_shares = 0
53
+ total_invested = 0
54
+
55
+ current_date = pd.to_datetime(start_date)
56
+ while current_date <= pd.to_datetime(end_date):
57
+ if current_date in data.index:
58
+ price = data.loc[current_date, 'Adj Close']
59
+ shares = monthly_investment / price
60
+ total_shares += shares
61
+ total_invested += monthly_investment
62
+
63
+ investment_dates.append(current_date)
64
+
65
+ current_date += pd.DateOffset(months=1)
66
+
67
+ total_shares_series = pd.Series([total_shares] * len(investment_dates), index=investment_dates).reindex(data.index, method='ffill')
68
+ portfolio_value = data['Adj Close'] * total_shares_series
69
+
70
+ return portfolio_value, pd.Series([total_invested] * len(data.index), index=data.index), total_invested
71
+
72
+ def plot_results(portfolio_value, stock_value, savings_value, total_invested, symbol, start_date, end_date, stock_only=False):
73
+ fig, ax = plt.subplots(figsize=(12, 6))
74
+ ax.plot(portfolio_value.index, portfolio_value, label='Portfolio Value')
75
+ if not stock_only:
76
+ ax.plot(stock_value.index, stock_value, label='Stock Investment Value')
77
+ ax.plot(savings_value.index, savings_value, label='Savings Account Value')
78
+ ax.plot(portfolio_value.index, total_invested, label='Total Cash Invested', linestyle='--')
79
+
80
+ ax.set_title(f'Monthly Investment Analysis: {symbol} ({start_date} to {end_date})')
81
+ ax.set_xlabel('Date')
82
+ ax.set_ylabel('Value ($)')
83
+ ax.legend()
84
+ ax.grid(True)
85
+
86
+ total_return = (portfolio_value[-1] - total_invested[-1]) / total_invested[-1] * 100
87
+
88
+ ax.annotate(f'Total Return: {total_return:.2f}%', xy=(0.05, 0.95), xycoords='axes fraction', fontsize=10, ha='left', va='top')
89
+ ax.annotate(f'Final Portfolio Value: ${portfolio_value[-1]:.2f}', xy=(0.05, 0.90), xycoords='axes fraction', fontsize=10, ha='left', va='top')
90
+ if not stock_only:
91
+ ax.annotate(f'Final Stock Value: ${stock_value[-1]:.2f}', xy=(0.05, 0.85), xycoords='axes fraction', fontsize=10, ha='left', va='top')
92
+ ax.annotate(f'Final Savings Value: ${savings_value[-1]:.2f}', xy=(0.05, 0.80), xycoords='axes fraction', fontsize=10, ha='left', va='top')
93
+ ax.annotate(f'Total Invested: ${total_invested[-1]:.2f}', xy=(0.05, 0.75), xycoords='axes fraction', fontsize=10, ha='left', va='top')
94
+
95
+ return fig
96
+
97
+ def main():
98
+ st.title("InvestSim: Stock & Savings Portfolio Analyzer")
99
+ st.write("Simulate and analyze your investment strategy with stocks and high-yield savings accounts.")
100
+
101
+ # Sidebar inputs
102
+ st.sidebar.header('Input Parameters')
103
+ symbol = st.sidebar.text_input('Stock Symbol', 'AAPL')
104
+ start_date = st.sidebar.date_input('Start Date', datetime(2000, 1, 1))
105
+ end_date = st.sidebar.date_input('End Date', datetime.now())
106
+ monthly_investment = st.sidebar.number_input('Monthly Investment ($)', min_value=1, value=100)
107
+ investment_type = st.sidebar.radio("Investment Type", ("Stock Only", "Mixed (Stock + Savings)"))
108
+
109
+ if investment_type == "Mixed (Stock + Savings)":
110
+ stock_allocation = st.sidebar.slider('Stock Allocation (%)', 0, 100, 60) / 100
111
+ savings_rate = st.sidebar.number_input('HYSA Annual Interest Rate (%)', min_value=0.0, max_value=20.0, value=4.5) / 100
112
+ else:
113
+ stock_allocation = 1.0
114
+ savings_rate = 0.0
115
+
116
+ if st.sidebar.button('Run Analysis'):
117
+ # Fetch stock data
118
+ data = fetch_stock_data(symbol, start_date, end_date)
119
+
120
+ if data.empty:
121
+ st.error(f"No data available for {symbol}. Please check the stock symbol and date range.")
122
+ return
123
+
124
+ # Run backtest
125
+ if investment_type == "Mixed (Stock + Savings)":
126
+ portfolio_value, stock_value, savings_value, total_invested = backtest_mixed_investment(
127
+ data, start_date, end_date, monthly_investment, stock_allocation, savings_rate
128
+ )
129
+ else:
130
+ portfolio_value, total_invested_series, total_invested = backtest_stock_only(
131
+ data, start_date, end_date, monthly_investment
132
+ )
133
+ stock_value = portfolio_value
134
+ savings_value = pd.Series([0] * len(portfolio_value), index=portfolio_value.index)
135
+
136
+ # Plot results
137
+ fig = plot_results(portfolio_value, stock_value, savings_value, total_invested_series if investment_type == "Stock Only" else pd.Series([total_invested] * len(portfolio_value), index=portfolio_value.index), symbol, start_date, end_date, stock_only=(investment_type == "Stock Only"))
138
+ st.pyplot(fig)
139
+
140
+ # Display summary statistics
141
+ st.subheader('Investment Summary')
142
+ st.write(f"Total Return: {((portfolio_value[-1] - total_invested) / total_invested * 100):.2f}%")
143
+ st.write(f"Final Portfolio Value: ${portfolio_value[-1]:.2f}")
144
+ if investment_type == "Mixed (Stock + Savings)":
145
+ st.write(f"Final Stock Value: ${stock_value[-1]:.2f}")
146
+ st.write(f"Final Savings Value: ${savings_value[-1]:.2f}")
147
+ st.write(f"Total Invested: ${total_invested:.2f}")
148
+
149
+ if __name__ == '__main__':
150
+ main()