Update utils/ui_helper.py
Browse files- utils/ui_helper.py +159 -1
utils/ui_helper.py
CHANGED
@@ -5,7 +5,7 @@ import plotly.graph_objects as go
|
|
5 |
import pandas as pd
|
6 |
from utils.helper import *
|
7 |
|
8 |
-
|
9 |
def main_algo_trader():
|
10 |
# Front-end Design
|
11 |
st.set_page_config(layout="wide")
|
@@ -154,6 +154,164 @@ def main_algo_trader():
|
|
154 |
|
155 |
st.plotly_chart(fig, use_container_width=True)
|
156 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
# Download
|
158 |
st.download_button(
|
159 |
label="Download data as CSV",
|
|
|
5 |
import pandas as pd
|
6 |
from utils.helper import *
|
7 |
|
8 |
+
# english
|
9 |
def main_algo_trader():
|
10 |
# Front-end Design
|
11 |
st.set_page_config(layout="wide")
|
|
|
154 |
|
155 |
st.plotly_chart(fig, use_container_width=True)
|
156 |
|
157 |
+
# Download
|
158 |
+
st.download_button(
|
159 |
+
label="Download data as CSV",
|
160 |
+
data=csv,
|
161 |
+
file_name=f'history_{end_date}.csv',
|
162 |
+
mime='text/csv',
|
163 |
+
)
|
164 |
+
|
165 |
+
|
166 |
+
# chinese
|
167 |
+
def main_algo_trader_chinese():
|
168 |
+
# Front-end Design
|
169 |
+
st.set_page_config(layout="wide")
|
170 |
+
st.write("# 欢迎来到算法交易!一个快速模拟平台👋")
|
171 |
+
|
172 |
+
with st.sidebar:
|
173 |
+
with st.expander("Expand/Collapse"):
|
174 |
+
st.markdown(
|
175 |
+
r"""
|
176 |
+
以下应用程序是成长股策略的简单演示。为简单起见,我们假设我们的研究团队交给了一些股票。在这些股票池中,我们可以做到以下几点:
|
177 |
+
- 使用 `yfinance` 库实时下载股票数据(为了速度,请从时间框架 "1mo" 开始);
|
178 |
+
- 每个周期(时间框架是一个调整参数),我们通过持有前 n 只股票(n 可以是股票的前五分之一/四分之一)来平衡我们的投资组合(等权)。
|
179 |
+
"""
|
180 |
+
)
|
181 |
+
|
182 |
+
# Main inputs
|
183 |
+
tickers = st.text_input(
|
184 |
+
"使用英文键入输入股票代码(以逗号分隔):",
|
185 |
+
"MSFT, AAPL, NVDA, GOOG, AMZN, META, LLY, AVGO, TSLA, JPM, V, WMT, UNH, MA, PG, HD, JNJ, ORCL, MRK, COST, ABBV, BAC, CRM, AMD, NFLX, ACN, ADBE, DIS, TMO, WFC, MCD, CSCO, ABT, QCOM, INTC, INTU, IBM, AMAT, CMCSA, AXP, PFE, NOW, AMGN, MU",
|
186 |
+
)
|
187 |
+
start_date = st.sidebar.date_input("开始日期", pd.to_datetime("2001-01-01"))
|
188 |
+
end_date = st.sidebar.date_input("结束日期", pd.to_datetime(datetime.now().strftime("%Y-%m-%d")))
|
189 |
+
time_frame = st.sidebar.selectbox(
|
190 |
+
"选择时间框架:",
|
191 |
+
[
|
192 |
+
"1mo",
|
193 |
+
"3mo",
|
194 |
+
],
|
195 |
+
)
|
196 |
+
top_n = st.sidebar.number_input("选择前 n 支股票", min_value=1, value=3)
|
197 |
+
height_of_graph = st.sidebar.number_input("图的高度", min_value=500, value=750)
|
198 |
+
|
199 |
+
# Process inputs
|
200 |
+
tickers_list = [ticker.strip() for ticker in tickers.split(",")]
|
201 |
+
|
202 |
+
# Run analysis on button click
|
203 |
+
if st.button("运行分析"):
|
204 |
+
with st.spinner("下载数据并计算回报..."):
|
205 |
+
stock_data = download_stock_data(
|
206 |
+
tickers_list,
|
207 |
+
start_date.strftime("%Y-%m-%d"),
|
208 |
+
end_date.strftime("%Y-%m-%d"),
|
209 |
+
w=time_frame,
|
210 |
+
)
|
211 |
+
returns_data = create_portfolio_and_calculate_returns(stock_data, top_n)
|
212 |
+
benchmark_sharpe_ratio = (
|
213 |
+
returns_data["benchmark"].mean() / returns_data["benchmark"].std()
|
214 |
+
)
|
215 |
+
portfolio_sharpe_ratio = (
|
216 |
+
returns_data["portfolio_returns"].mean()
|
217 |
+
/ returns_data["portfolio_returns"].std()
|
218 |
+
)
|
219 |
+
|
220 |
+
# Data for plotting
|
221 |
+
df = returns_data[
|
222 |
+
["rolling_benchmark", "rolling_portfolio_returns", "portfolio_history"]
|
223 |
+
]
|
224 |
+
df.index = pd.to_datetime(df.index, unit="ms")
|
225 |
+
|
226 |
+
# Create download file
|
227 |
+
@st.cache_data
|
228 |
+
def convert_df(df):
|
229 |
+
# IMPORTANT: Cache the conversion to prevent computation on every rerun
|
230 |
+
return df.to_csv().encode('utf-8')
|
231 |
+
|
232 |
+
csv = convert_df(df)
|
233 |
+
|
234 |
+
# Create plot
|
235 |
+
fig = go.Figure()
|
236 |
+
fig.add_trace(
|
237 |
+
go.Scatter(
|
238 |
+
x=df.index,
|
239 |
+
y=df["rolling_benchmark"],
|
240 |
+
mode="lines",
|
241 |
+
name="Rolling Benchmark",
|
242 |
+
)
|
243 |
+
)
|
244 |
+
fig.add_trace(
|
245 |
+
go.Scatter(
|
246 |
+
x=df.index,
|
247 |
+
y=df["rolling_portfolio_returns"],
|
248 |
+
mode="lines",
|
249 |
+
name="Rolling Portfolio Returns",
|
250 |
+
)
|
251 |
+
)
|
252 |
+
|
253 |
+
for date, stocks in df["portfolio_history"].items():
|
254 |
+
fig.add_shape(
|
255 |
+
type="line",
|
256 |
+
x0=date,
|
257 |
+
y0=0,
|
258 |
+
x1=date,
|
259 |
+
y1=0,
|
260 |
+
line=dict(color="RoyalBlue", width=1),
|
261 |
+
)
|
262 |
+
fig.add_annotation(
|
263 |
+
x=date,
|
264 |
+
y=0.5,
|
265 |
+
text=str(stocks),
|
266 |
+
showarrow=False,
|
267 |
+
yshift=10,
|
268 |
+
textangle=-90,
|
269 |
+
font=dict(size=15), # You can adjust the size as needed
|
270 |
+
)
|
271 |
+
|
272 |
+
# Calculate means and standard deviations
|
273 |
+
benchmark_mean = returns_data["benchmark"].mean()
|
274 |
+
benchmark_std = returns_data["benchmark"].std()
|
275 |
+
portfolio_mean = returns_data["portfolio_returns"].mean()
|
276 |
+
portfolio_std = returns_data["portfolio_returns"].std()
|
277 |
+
|
278 |
+
# Update title text with additional information
|
279 |
+
if time_frame == '1mo':
|
280 |
+
some_n_based_on_time_frame = 12
|
281 |
+
in_a_year = 1000*(1+portfolio_mean)**(some_n_based_on_time_frame)
|
282 |
+
in_50_years = 1000*(1+portfolio_mean)**(some_n_based_on_time_frame*50)
|
283 |
+
else:
|
284 |
+
some_n_based_on_time_frame = 4
|
285 |
+
in_a_year = 1000*(1+portfolio_mean)**(some_n_based_on_time_frame)
|
286 |
+
in_50_years = 1000*(1+portfolio_mean)**(some_n_based_on_time_frame*50)
|
287 |
+
title_text = (
|
288 |
+
f"Performance:<br>"
|
289 |
+
f"Benchmark Sharpe Ratio = {benchmark_sharpe_ratio:.3f}, "
|
290 |
+
f"Portfolio Sharpe Ratio = {portfolio_sharpe_ratio:.3f}, "
|
291 |
+
f"based on time frame: {time_frame}<br>"
|
292 |
+
f"Benchmark => Mean: {benchmark_mean:.4f}, Std: {benchmark_std:.4f}; "
|
293 |
+
f"Portfolio => Mean: {portfolio_mean:.4f}, Std: {portfolio_std:.4f}<br>"
|
294 |
+
f"---<br>"
|
295 |
+
f"This may or may not be a small number, let's check: <br>"
|
296 |
+
f"$1,000*(1+{portfolio_mean:.4f})^({some_n_based_on_time_frame})={in_a_year}, <br>"
|
297 |
+
f"$1,000*(1+{portfolio_mean:.4f})^({some_n_based_on_time_frame}*50)={in_50_years}."
|
298 |
+
)
|
299 |
+
curr_max_num = max(
|
300 |
+
df.rolling_benchmark.max(), df.rolling_portfolio_returns.max()
|
301 |
+
)
|
302 |
+
fig.update_layout(
|
303 |
+
title=title_text,
|
304 |
+
xaxis_title="Date",
|
305 |
+
yaxis_title="Value",
|
306 |
+
yaxis=dict(range=[0, curr_max_num * 1.1]),
|
307 |
+
legend=dict(
|
308 |
+
orientation="h", x=0.5, y=-0.4, xanchor="center", yanchor="bottom"
|
309 |
+
),
|
310 |
+
height=height_of_graph,
|
311 |
+
)
|
312 |
+
|
313 |
+
st.plotly_chart(fig, use_container_width=True)
|
314 |
+
|
315 |
# Download
|
316 |
st.download_button(
|
317 |
label="Download data as CSV",
|