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( """ """, 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)