Spaces:
Runtime error
Runtime error
File size: 9,424 Bytes
642c876 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
import streamlit as st
import plotly.express as px
from datetime import date, timedelta
from data_creator import create_market_cap_dict, gen_rebased_df, ids2names_dict, names2ids_dict, create_assets, gen_symbols, create_histories_df, create_unix_dates, create_returns_df, create_rebased_df, date_range
from plot_creator import get_pre_selected_idx, write_coins, write_coins_custom, write_bespoke_coins, create_comparison_df, load_images, gen_performance_ag_df, add_drawdown
from port_creator import gen_all_returns, markowitz_weights_dict, uniform_weights_dict, ids_with_histories, uniform, create_port_rtns, markowitz_weights, create_weights_df
from risk_metrics import max_drawdown
from st_aggrid import AgGrid, GridOptionsBuilder
from persist import persist, load_widget_state
load_widget_state()
st.markdown(
"""
<style>
.css-1xsoh1l {
font-size: 0px;
}
.css-1xsoh1l{
color: rgb(120 190 33);
}
.css-jhf39w {
color: rgba(120, 190, 33, 1);
}
.css-jv3mmh {
background-color: rgb(120, 190, 33);
}
</style>
""",
unsafe_allow_html = True
)
# load start and end dates for investment analysis
lookback_years = 5 # max date range for backtest will be: lookback_years - 1
start_date = date.today() - timedelta(365)
end_date = date.today()
if 'start_date' not in st.session_state:
st.session_state.start_date = start_date
st.session_state.end_date = end_date
if 'max_coins' not in st.session_state:
st.session_state.max_coins = 10
if 'start_id' not in st.session_state:
st.session_state.start_id = 1
# Pull down histories from coincap, and create dataframes for historic prices,
# returns and rebased cumulative price; histories_df, returns_df, and
# rebased_df, respectively.
assets_json = create_assets(total_coins=50)
symbols, names, coin_ids = gen_symbols(assets_json)
ids2symbols = ids2names_dict(coin_ids, symbols)
ids2names_dict=ids2names_dict(coin_ids, names)
names2ids_dict = names2ids_dict(names, coin_ids)
market_cap_dict = create_market_cap_dict(assets_json)
start_unix, end_unix = create_unix_dates(today=date.today(), lookback_years=lookback_years)
histories_df = create_histories_df(coin_ids, start_unix, end_unix)
# Create list of coin ids with full hisoties over the backtest period
ids_with_histories = ids_with_histories(histories_df,
st.session_state.start_date, st.session_state.end_date)
names_with_histories = list(map(ids2names_dict.get, ids_with_histories))
def change_date_range():
st.session_state.start_date = st.session_state.myslider[0]
st.session_state.end_date = st.session_state.myslider[1]
# calculate weghts for the uniform and markowitz pfs
uniform_weights_dict = uniform_weights_dict(ids_with_histories[:st.session_state.max_coins])
#markowitz_weights_dict = markowitz_weights_dict(histories_df,
# st.session_state.start_date ,ids_with_histories[:max_coins], analysis_days=365)
strategy_dict = {'Uniform': uniform_weights_dict}#, 'Markowitz':markowitz_weights_dict}
if "strategy_dict" not in st.session_state:
st.session_state.strategy_dict=strategy_dict
if 'selected_assets' not in st.session_state:
st.session_state.selected_assets = ["Uniform"]
with st.sidebar:
st.subheader("Portfolio weights viewer")
portfolio_type = st.selectbox(
'Select portfolio strategy',
['Create your own'] + (list(st.session_state.strategy_dict.keys())),
index = st.session_state.start_id
)
if st.checkbox("Explain this"):
st.subheader("What's this all about then, eh?")
st.write('''
The app allows you to construct your own portfolios of crypto currencies and view their
historic performance alongside the performance of individual crypto
currencies over an investment period of your choosing.
To view the assets and weights comprising a particular portfolio select the
portfolio of interest in the 'Select portfolio strategy' dropdown (a uniform
portfolio for the top ten largest coins has been automatically created for you
to start with).
To create your own portfolio:
1. Select 'Create your own' in the 'select portfolio strategy' dropdown;
2. Select the maximum number of coins in your portfolio;
3. Select the relative weights for each of these assets;
4. Choose a name for your portfolio and click add portfolio;
5. Click update viewer;
You can sort and filter the performance metrics table on each of the columns.
To add an asset to the performance chart, select the corresponding select box.
''')
# Add select slider to allow
date_list = date_range(end_date,lookback_years-1)
start_port_date, end_port_date = st.select_slider(
'Select backtest date range',
key="myslider",
options=date_list,
#value=(date.today() - timedelta(365), date.today()),
value = (st.session_state.start_date, st.session_state.end_date),
on_change=change_date_range
)
# Move the definition of strategy_dict to about the potfolio_type selectbox
# This will require that you define max_coins in session state,a dn the
# have the max_coins number_input update the max coins session state.
# = 10 and let it be
# calculate returns for the portfolios and add to it the rebased df for assets
# with hisories. This is the new returns_df
rebased_df = gen_rebased_df(histories_df, ids_with_histories,
st.session_state.start_date, st.session_state.end_date)
all_returns_df = gen_all_returns(rebased_df, ids_with_histories,st.session_state.strategy_dict)
def write_something():
st.write("")
def rerun_aggrid():
st.session_state.selected_indexes = selected_indexes
st.session_state.performance_ag_df = gen_performance_ag_df(all_returns_df, market_cap_dict,
st.session_state.strategy_dict)
st.header('ran')
if portfolio_type == 'Create your own':
with st.sidebar:
st.session_state.max_coins = st.number_input(
"Maximum number of coins in portfolio",
min_value=1,
max_value=20,
value=10,
help='''
Coins will be added to your "investment set" in order of largest market cap.
The "investment set" is the group of assets from which your portfolio is
constructed. Depending on the portfolio strategy you choose, not all of the
assets in your investment set will be included in your portfolio.
'''
)
st.markdown("Bespoke portfolio weights (relative):" , unsafe_allow_html=False)
bespoke_weights = write_coins_custom(names_with_histories[:st.session_state.max_coins])
#bespoke_weights = write_bespoke_coins(names_with_histories[:st.session_state.max_coins])
bespoke_cols = st.columns(2)
bespoke_cols[0].write(" ")
bespoke_cols[0].write(" ")
add_bespoke = bespoke_cols[0].button("Add portfolio", key='bespoke_button')
bespoke_name = bespoke_cols[1].text_input("Choose portfolio name")
if add_bespoke:
if bespoke_name=="" or bespoke_name in all_returns_df.columns:
st.warning("Please give your portfolio a unique name")
else:
beskpoke_weights_dict={}
for i, wt in enumerate(bespoke_weights):
beskpoke_weights_dict[coin_ids[i]] = wt
st.session_state.strategy_dict[bespoke_name] = beskpoke_weights_dict
st.session_state.start_id = len(st.session_state.strategy_dict)
#st.session_state.selected_assets.append(bespoke_name)
st.success("Porfolio added, update viewer to see results")
#st.button('Update viewer', on_click = change_date_range)
st.button('Update viewer', on_click = rerun_aggrid)
#st.button('Update viewer', on_click = st.experimental_rerun())
#st.write(st.session_state.strategy_dict)
else:
non_zero_coins = [key for key in st.session_state.strategy_dict[portfolio_type].keys() if st.session_state.strategy_dict[portfolio_type][key]>0]
with st.sidebar:
st.markdown(portfolio_type + " portfolio weights (%):" , unsafe_allow_html=False)
write_coins(non_zero_coins, st.session_state.strategy_dict[portfolio_type], ids2names_dict)
st.session_state.performance_ag_df = gen_performance_ag_df(all_returns_df, market_cap_dict,
st.session_state.strategy_dict)
if 'selected_assets' not in st.session_state:
st.session_state.selected_assets = ["Uniform"]
selected_indexes = []
for asset in st.session_state.selected_assets:
try:
selected_indexes.append(list(st.session_state.performance_ag_df['Asset']).index(asset))
except:
pass
if 'selected_indexes' not in st.session_state:
st.session_state.selected_indexes = selected_indexes
gb = GridOptionsBuilder.from_dataframe(st.session_state.performance_ag_df)
gb.configure_selection('multiple', use_checkbox=True,
pre_selected_rows = st.session_state.selected_indexes)
gridOptions = gb.build()
st.subheader("Performance metrics")
grid_response = AgGrid(st.session_state.performance_ag_df, gridOptions=gridOptions,
data_return_mode = 'FILTERED', allow_unsafe_jscode=True, height = 200,
update_mode='MODEL_CHANGED', key = persist("aggrid")) # MANUAL SELECTION_CHANGED MODEL_CHANGED, VALUE_CHANGED
selected_assets = []
for row in grid_response['selected_rows']:
selected_assets.append(row['Asset'])
st.session_state.selected_assets = selected_assets
#selected_indexes = []
#for asset in st.session_state.selected_assets:
# selected_indexes.append(list(performance_ag_df['Asset']).index(asset))
chart_df = create_comparison_df(all_returns_df, st.session_state.selected_assets)
fig = px.line(chart_df, x=chart_df.index, y='Value (USD)', color='Asset')
st.subheader("Performance chart")
st.write(fig)
|