Spaces:
Configuration error
Configuration error
ldsakjl
Browse files- README.md +1 -1
- apps/.DS_Store +0 -0
- apps/Clustering.py +183 -3
- apps/Comandos_utiles.py +107 -3
- apps/Comentarios.py +623 -3
- apps/Google_Trends.py +490 -3
- apps/Home.py +331 -3
- apps/Mom_industrias.py +702 -3
- apps/Panel_de_control.py +95 -3
- apps/Scoring.py +303 -3
- apps/Tasas.py +950 -3
- apps/analisis_inmob.py +347 -3
- apps/mailer_quant.py +63 -3
- apps/simulacion_vc.py +1414 -3
- apps/streamlit_larra.py +131 -3
README.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
oid sha256:211cb91d6d7d65b8e74afe1e4257af5ee70faf2d6c4cda8bb589d812e0fbe1a7
|
| 3 |
-
size 248
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
oid sha256:211cb91d6d7d65b8e74afe1e4257af5ee70faf2d6c4cda8bb589d812e0fbe1a7
|
| 3 |
+
size 248
|
apps/.DS_Store
CHANGED
|
Binary files a/apps/.DS_Store and b/apps/.DS_Store differ
|
|
|
apps/Clustering.py
CHANGED
|
@@ -1,3 +1,183 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from io import BytesIO
|
| 2 |
+
import streamlit as st
|
| 3 |
+
import pandas as pd
|
| 4 |
+
from scipy.cluster.hierarchy import linkage
|
| 5 |
+
from datetime import date
|
| 6 |
+
from dateutil.relativedelta import relativedelta
|
| 7 |
+
import plotly.figure_factory as ff
|
| 8 |
+
from fastdtw import fastdtw
|
| 9 |
+
from scipy.spatial.distance import euclidean
|
| 10 |
+
import numpy as np
|
| 11 |
+
from modules import tables
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
@st.cache(suppress_st_warning=True)
|
| 15 |
+
def data_request(country_to_request, start, currency='USD', end=date.today()):
|
| 16 |
+
data = tables.EquityMaster(country=country_to_request, field='IQ_CLOSEPRICE_ADJ', currency=currency).query(rename=['asset'],
|
| 17 |
+
start=start, end=str(end))
|
| 18 |
+
adtv = tables.EquityMaster(country=country_to_request, field='IQ_VALUE_TRADED', currency=currency).query(rename=['asset'],
|
| 19 |
+
start=start, end=str(end)).median()
|
| 20 |
+
marketcap = tables.EquityMaster(country=country_to_request, field='IQ_MARKETCAP', currency=currency).query(rename=['asset'],
|
| 21 |
+
start=start, end=str(end)).median()
|
| 22 |
+
return data, adtv, marketcap
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
@st.cache(suppress_st_warning=True)
|
| 26 |
+
def data_filter(data, adtv, marketcap, adtv_threshold, mktcap_threshold, p):
|
| 27 |
+
adtv_filter = (adtv >= adtv_threshold)
|
| 28 |
+
adtv = adtv.loc[adtv_filter]
|
| 29 |
+
marketcap_filter = (marketcap >= mktcap_threshold)
|
| 30 |
+
marketcap = marketcap.loc[marketcap_filter]
|
| 31 |
+
data = data.loc[:, data.columns.isin(adtv.index)]
|
| 32 |
+
data = data.loc[:, data.columns.isin(marketcap.index)]
|
| 33 |
+
|
| 34 |
+
file_to_read = 'Data/Company_Base_Definitivo.xlsx'
|
| 35 |
+
company_base = pd.read_excel(file_to_read, sheet_name='Compilado')
|
| 36 |
+
id_to_ticker = {str(row['ID_Quant']): str(row['Ticker Bloomberg']).split()[0] for i, row in company_base.iterrows()}
|
| 37 |
+
data = data.loc[:, data.columns.isin(id_to_ticker.keys())]
|
| 38 |
+
data.columns = [id_to_ticker[col] for col in data.columns]
|
| 39 |
+
|
| 40 |
+
if isinstance(p, str):
|
| 41 |
+
returns_final = data.resample(p).last().pct_change().fillna(0)
|
| 42 |
+
else:
|
| 43 |
+
returns_final = data.iloc[::p].pct_change().fillna(0)
|
| 44 |
+
return returns_final
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def dist(correlation):
|
| 48 |
+
return ((1-correlation)/2.)**.5
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def to_excel(df_to_write):
|
| 52 |
+
output = BytesIO()
|
| 53 |
+
writer = pd.ExcelWriter(output, engine='xlsxwriter')
|
| 54 |
+
df_to_write.to_excel(writer, index=False, sheet_name='Sheet1')
|
| 55 |
+
workbook = writer.book
|
| 56 |
+
worksheet = writer.sheets['Sheet1']
|
| 57 |
+
format1 = workbook.add_format({'num_format': '0.00'})
|
| 58 |
+
worksheet.set_column('A:A', None, format1)
|
| 59 |
+
writer.save()
|
| 60 |
+
processed_data = output.getvalue()
|
| 61 |
+
return processed_data
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
@st.cache(suppress_st_warning=True)
|
| 65 |
+
def get_dtw_distance(x, y):
|
| 66 |
+
distance_dtw = fastdtw(x, y, dist=euclidean)[0]
|
| 67 |
+
return distance_dtw
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def clustering_basado_en_correlacion():
|
| 71 |
+
|
| 72 |
+
form = st.form("Correlation Clustering")
|
| 73 |
+
posible_countries = ('Todos', 'Argentina', 'Brazil', 'Chile', 'Colombia', 'Mexico', 'Peru')
|
| 74 |
+
countries = form.multiselect('¿Qué países desea visualizar?', posible_countries)
|
| 75 |
+
if 'Todos' in countries:
|
| 76 |
+
countries = ('Argentina', 'Brazil', 'Chile', 'Colombia', 'Mexico', 'Peru')
|
| 77 |
+
|
| 78 |
+
adtv_p = form.number_input('Ingrese el mínimo Average Daily Traded Value que desea considerar', value=1., format="%.2f")
|
| 79 |
+
mktcap_thresh = form.number_input('Ingrese el mínimo Market Cap que desea considerar', value=200., format="%.2f")
|
| 80 |
+
start_date = form.selectbox('Ingrese la fecha de inicio que desea considerar', ('3 Meses', '6 Meses', '1 Año'))
|
| 81 |
+
period = form.number_input('Defina la frecuencia en la que desea las observaciones (en días)', value=1)
|
| 82 |
+
accept = form.form_submit_button('Aceptar')
|
| 83 |
+
|
| 84 |
+
if accept:
|
| 85 |
+
start_date = str(date.today() - relativedelta(months=int(start_date[0])))
|
| 86 |
+
for country in countries:
|
| 87 |
+
data_, adtv_, marketcap_ = data_request(country, start_date)
|
| 88 |
+
# Filtramos para que se cumplan los filtros del usuario en los datos
|
| 89 |
+
returns = data_filter(data_, adtv_, marketcap_, adtv_p, mktcap_thresh, period)
|
| 90 |
+
|
| 91 |
+
# Normalizamos
|
| 92 |
+
base = (returns.subtract(returns.mean(0), axis=1)).div(returns.std(axis=0), axis=1)
|
| 93 |
+
base = base.sort_index(axis=1)
|
| 94 |
+
|
| 95 |
+
# Procedemos a calcular correlación y covarianza
|
| 96 |
+
corr, covs = base.corr(), base.cov()
|
| 97 |
+
file = to_excel(corr)
|
| 98 |
+
|
| 99 |
+
# Definimos la matriz de distancia
|
| 100 |
+
dist_matrix = dist(corr)
|
| 101 |
+
|
| 102 |
+
hierarchy = linkage(dist_matrix)
|
| 103 |
+
ct = 0.54 * max(hierarchy[:, 2])
|
| 104 |
+
fig = ff.create_dendrogram(dist_matrix, orientation='left', labels=list(base.columns),
|
| 105 |
+
color_threshold=ct, linkagefun=linkage)
|
| 106 |
+
|
| 107 |
+
fig.update_layout(title='{} desde {} hasta {}'.format(country,
|
| 108 |
+
returns.index[0].date(),
|
| 109 |
+
returns.index[-1].date()))
|
| 110 |
+
if country == 'Brazil':
|
| 111 |
+
fig.update_layout(height=2000)
|
| 112 |
+
else:
|
| 113 |
+
fig.update_layout(height=900)
|
| 114 |
+
|
| 115 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 116 |
+
|
| 117 |
+
st.download_button(label='Descargar Matriz de Correlación para {}'.format(country), data=file,
|
| 118 |
+
file_name='{}_correlacion.xlsx'.format(country))
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def clustering_con_dtw():
|
| 122 |
+
form = st.form("Dynamic Time Warping Clustering")
|
| 123 |
+
posible_countries = ('Todos', 'Brazil', 'Argentina', 'Chile', 'Colombia', 'Mexico', 'Peru')
|
| 124 |
+
countries = form.multiselect('¿Qué países desea visualizar?', posible_countries)
|
| 125 |
+
if 'Todos' in countries:
|
| 126 |
+
countries = ('Brazil', 'Argentina', 'Chile', 'Colombia', 'Mexico', 'Peru')
|
| 127 |
+
|
| 128 |
+
adtv_p = form.number_input('Ingrese el mínimo Average Daily Traded Value que desea considerar', value=1.,
|
| 129 |
+
format="%.2f")
|
| 130 |
+
mktcap_thresh = form.number_input('Ingrese el Mínimo Market Cap que desea considerar', value=200., format="%.2f")
|
| 131 |
+
start_date = form.selectbox('Ingrese la fecha de inicio que desea considerar', ('3 Meses', '6 Meses', '1 Año'))
|
| 132 |
+
period = form.number_input('Defina la frecuencia en la que desea las observaciones (en días)', value=1)
|
| 133 |
+
accept = form.form_submit_button('Aceptar')
|
| 134 |
+
|
| 135 |
+
if accept:
|
| 136 |
+
start_date = str(date.today() - relativedelta(months=int(start_date[0])))
|
| 137 |
+
|
| 138 |
+
for country in countries:
|
| 139 |
+
data_, adtv_, marketcap_ = data_request(country, start_date)
|
| 140 |
+
# Filtramos para que se cumplan los filtros del usuario en los datos
|
| 141 |
+
returns = data_filter(data_, adtv_, marketcap_, adtv_p, mktcap_thresh, period)
|
| 142 |
+
# Normalizamos returns
|
| 143 |
+
base = (returns.subtract(returns.mean(0), axis=1)).div(returns.std(axis=0), axis=1)
|
| 144 |
+
base = base.sort_index(axis=1)
|
| 145 |
+
# Procedemos a calcular correlación y covarianza
|
| 146 |
+
N = len(base[:base.index[0]].T)
|
| 147 |
+
# Creamos la Matriz de Distancias para DTW
|
| 148 |
+
Dist = np.zeros((N, N))
|
| 149 |
+
place = st.empty()
|
| 150 |
+
for i in range(N):
|
| 151 |
+
place.write("Cargando: " + str(round(i*100/N)) + " %")
|
| 152 |
+
for j in range(i - 1, N):
|
| 153 |
+
company_1 = base.columns[i]
|
| 154 |
+
company_2 = base.columns[j]
|
| 155 |
+
Dist[i, j] = get_dtw_distance(base[company_1], base[company_2])
|
| 156 |
+
# La matriz es simétrica
|
| 157 |
+
Dist[j, i] = Dist[i, j]
|
| 158 |
+
# Creamos un DataFrame con la matriz de distancias
|
| 159 |
+
df = pd.DataFrame(Dist)
|
| 160 |
+
df.index = base.columns
|
| 161 |
+
df.columns = base.columns
|
| 162 |
+
|
| 163 |
+
# Pasamos el df a excel para descarga del usuario
|
| 164 |
+
file = to_excel(df)
|
| 165 |
+
|
| 166 |
+
hierarchy = linkage(Dist)
|
| 167 |
+
ct = 0.54 * max(hierarchy[:, 2])
|
| 168 |
+
|
| 169 |
+
fig = ff.create_dendrogram(Dist, orientation='left', labels=list(base.columns),
|
| 170 |
+
color_threshold=ct, linkagefun=linkage)
|
| 171 |
+
fig.update_layout(
|
| 172 |
+
title='{} desde {} hasta {}'.format(country, returns.index[0].date(), returns.index[-1].date()))
|
| 173 |
+
|
| 174 |
+
if country == 'Brazil':
|
| 175 |
+
fig.update_layout(height=2000)
|
| 176 |
+
else:
|
| 177 |
+
fig.update_layout(height=900)
|
| 178 |
+
|
| 179 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 180 |
+
|
| 181 |
+
st.download_button(label='Descargar Matriz de distancias con DTW para {}'.format(country), data=file,
|
| 182 |
+
file_name='{}_correlacion.xlsx'.format(country))
|
| 183 |
+
|
apps/Comandos_utiles.py
CHANGED
|
@@ -1,3 +1,107 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
Created on Tue Aug 31 15:01:56 2021
|
| 5 |
+
|
| 6 |
+
@author: benjaminull
|
| 7 |
+
"""
|
| 8 |
+
import streamlit as st
|
| 9 |
+
import pandas as pd
|
| 10 |
+
import numpy as np
|
| 11 |
+
import io
|
| 12 |
+
import pybase64 as base64
|
| 13 |
+
from plotly import graph_objs as go
|
| 14 |
+
from datetime import datetime
|
| 15 |
+
import plotly.express as px
|
| 16 |
+
|
| 17 |
+
def get_table_excel_link(df, selected_stocks):
|
| 18 |
+
towrite = io.BytesIO()
|
| 19 |
+
downloaded_file = df.to_excel(towrite, encoding='utf-8', index=False,
|
| 20 |
+
header=True)
|
| 21 |
+
towrite.seek(0) # reset pointer
|
| 22 |
+
file_name = 'Data'+ selected_stocks+'.xlsx'
|
| 23 |
+
style = 'style="color:black;text-decoration: none; font-size:18px;"'
|
| 24 |
+
name_mark = "Descargar " + selected_stocks + ".xlsx"
|
| 25 |
+
b64 = base64.b64encode(towrite.read()).decode() # some strings
|
| 26 |
+
linko= f'<center><a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" '+style+'download="'+file_name+'"><button>'+name_mark+'</button></a></center>'
|
| 27 |
+
return linko
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
@st.cache(show_spinner=True)
|
| 31 |
+
def charged_data():
|
| 32 |
+
regiones = {}
|
| 33 |
+
regiones['Latam'] = ['Argentina', 'Brazil', 'Chile', 'Colombia',
|
| 34 |
+
'Mexico', 'Peru']
|
| 35 |
+
regiones['Europa'] = ['Italy', 'Spain', 'Germany', 'United Kingdom',
|
| 36 |
+
'France']
|
| 37 |
+
regiones['Asia Emergente'] = ['South Korea', 'Taiwan', 'Hong Kong',
|
| 38 |
+
'India', 'Thailand', 'Indonesia']
|
| 39 |
+
regiones['USA'] = ['United States']
|
| 40 |
+
data_dict=np.load('dict_movilidad.npy', allow_pickle='TRUE').item()
|
| 41 |
+
return data_dict, regiones
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def comandos_utiles():
|
| 47 |
+
st.code("""CMD o Terminal\n> pip install streamlit """, language='python')
|
| 48 |
+
st.code("""CMD o Terminal\n> cd "ruta vista" \n> streamlit run app.py """,language='python')
|
| 49 |
+
code='''import streamlit as st \ndef comandos_utiles(): \n col1, col2 = st.columns(2) \n ...'''
|
| 50 |
+
st.code(code, language='python')
|
| 51 |
+
st.subheader("Elementos interactivos")
|
| 52 |
+
col1, col2 = st.columns(2)
|
| 53 |
+
col2.header(" ")
|
| 54 |
+
code2=('''var = col1.selectbox("Selectbox", ["Opcion 1", "Opcion 2", "Opcion 3"]) \nst.write(var)''')
|
| 55 |
+
col2.code(code2)
|
| 56 |
+
var = col1.selectbox("Selectbox", ["Opcion 1", "Opcion 2", "Opcion 3"])
|
| 57 |
+
col1.write(var)
|
| 58 |
+
var2 = col1.multiselect("Multiselect", ["Opcion 1", "Opcion 2", "Opcion 3"])
|
| 59 |
+
col1.write(var2)
|
| 60 |
+
code3=('''var = col1.multiselect("Selectbox", ["Opcion 1", "Opcion 2", "Opcion 3"]) \nst.write(var2)''')
|
| 61 |
+
col2.header(" ")
|
| 62 |
+
col2.code(code3)
|
| 63 |
+
var3 = col1.number_input("Number input")
|
| 64 |
+
col1.write(var3)
|
| 65 |
+
code4=('''var3 = col1.number_input("Number input") \nst.write(var3)''')
|
| 66 |
+
col2.header(" ")
|
| 67 |
+
col2.code(code4)
|
| 68 |
+
st.subheader("Tablas")
|
| 69 |
+
col1, col2 = st.columns(2)
|
| 70 |
+
df=pd.DataFrame([["1","2","3"],["2","5","6"],["7","8","9"]])
|
| 71 |
+
col1.write(df)
|
| 72 |
+
col2.header(" ")
|
| 73 |
+
col2.code("col1.write(df)")
|
| 74 |
+
col1.table(df)
|
| 75 |
+
col2.header(" ")
|
| 76 |
+
col2.header(" ")
|
| 77 |
+
col2.code("col1.table(df)")
|
| 78 |
+
col2.header(" ")
|
| 79 |
+
code_exc="""import io \nimport pybase64 as base6 \ndef get_table_excel_link(df, name):
|
| 80 |
+
towrite = io.BytesIO()
|
| 81 |
+
downloaded_file = df.to_excel(towrite, encoding='utf-8', index=False,
|
| 82 |
+
header=True)
|
| 83 |
+
towrite.seek(0) # reset pointer
|
| 84 |
+
file_name = 'Data'+ name +'.xlsx'
|
| 85 |
+
style = 'style="color:black;text-decoration: none; font-size:18px;"'
|
| 86 |
+
name_mark = "Descargar " + name + ".xlsx"
|
| 87 |
+
b64 = base64.b64encode(towrite.read()).decode() # some strings
|
| 88 |
+
linko= f'<center><a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" '+style+'download="'+file_name+'"><button>'+name_mark+'</button></a></center>'
|
| 89 |
+
return linko \ncol1.markdown(get_table_excel_link(df, "tabla 1"),unsafe_allow_html=True)
|
| 90 |
+
"""
|
| 91 |
+
col1.subheader("Descargar data frame")
|
| 92 |
+
col2.header(" ")
|
| 93 |
+
col1.header(" ")
|
| 94 |
+
col1.header(" ")
|
| 95 |
+
col2.code(code_exc)
|
| 96 |
+
col1.markdown(get_table_excel_link(df, "tabla 1"),unsafe_allow_html=True)
|
| 97 |
+
st.subheader("Graficos")
|
| 98 |
+
col1, col2 = st.columns((2,1))
|
| 99 |
+
col2.code("col1, col2 = st.columns((2,1)) \nfrom plotly import graph_objs as go \nimport plotly.express as px ")
|
| 100 |
+
df = px.data.tips()
|
| 101 |
+
fig = px.scatter(df, x="total_bill", y="tip", trendline="ols")
|
| 102 |
+
st.plotly_chart(fig)
|
| 103 |
+
st.code("""df = px.data.tips() \nfig = px.scatter(df, x="total_bill", y="tip", trendline="ols")\ncol1.plotly_chart(fig)""")
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
|
apps/Comentarios.py
CHANGED
|
@@ -1,3 +1,623 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import plotly.express as px
|
| 4 |
+
import datetime
|
| 5 |
+
from Scheduler.mailer_quant import Mailer
|
| 6 |
+
from sqlalchemy import create_engine
|
| 7 |
+
import psycopg2
|
| 8 |
+
import graphviz as graphviz
|
| 9 |
+
import plotly.graph_objects as go
|
| 10 |
+
from logs_portal import log
|
| 11 |
+
import io
|
| 12 |
+
import boto3
|
| 13 |
+
from Data.credentials import credentials_s3 as creds3
|
| 14 |
+
from Data.credentials import credentials_postgresql as credpost
|
| 15 |
+
from st_aggrid import GridOptionsBuilder, AgGrid, GridUpdateMode, DataReturnMode, JsCode
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def save_s3(key, secret_key, bucket, df, path):
|
| 19 |
+
with io.BytesIO() as output:
|
| 20 |
+
with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
|
| 21 |
+
df.to_excel(writer, index=False)
|
| 22 |
+
data = output.getvalue()
|
| 23 |
+
s3 = boto3.resource('s3', aws_access_key_id=key,
|
| 24 |
+
aws_secret_access_key=secret_key)
|
| 25 |
+
s3.Bucket(bucket).put_object(Key=path, Body=data)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def read_excel_s3(key, secret_key, bucket, path):
|
| 29 |
+
s3_client = boto3.client('s3', aws_access_key_id=key,
|
| 30 |
+
aws_secret_access_key=secret_key)
|
| 31 |
+
response = s3_client.get_object(Bucket=bucket, Key=path)
|
| 32 |
+
data = response["Body"].read()
|
| 33 |
+
df = pd.read_excel(io.BytesIO(data), engine='openpyxl')
|
| 34 |
+
return df
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def display_table(df: pd.DataFrame):
|
| 38 |
+
# Configure AgGrid options
|
| 39 |
+
gb = GridOptionsBuilder.from_dataframe(df)
|
| 40 |
+
gb.configure_selection(selection_mode="single", use_checkbox=True,)
|
| 41 |
+
return AgGrid(
|
| 42 |
+
df, gridOptions=gb.build(),
|
| 43 |
+
update_mode=GridUpdateMode.SELECTION_CHANGED,
|
| 44 |
+
enable_enterprise_modules=True)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def style_table():
|
| 48 |
+
style_table = """
|
| 49 |
+
<style>
|
| 50 |
+
tbody tr:hover {
|
| 51 |
+
color:#BB1114;}
|
| 52 |
+
thead {
|
| 53 |
+
background-color:#BB1114 ;
|
| 54 |
+
color: #E8E8E8;
|
| 55 |
+
}
|
| 56 |
+
tbody tr:nth-child(odd) {
|
| 57 |
+
background-color: #fff;
|
| 58 |
+
}
|
| 59 |
+
# tbody tr:nth-child(even) {
|
| 60 |
+
# background-color: #eee;
|
| 61 |
+
# }
|
| 62 |
+
tbody tr:nth-child(odd)
|
| 63 |
+
stTable {
|
| 64 |
+
border-collapse: collapse;
|
| 65 |
+
margin: 25px 0;
|
| 66 |
+
font-size: 0.9em;
|
| 67 |
+
min-width: 400px;
|
| 68 |
+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
| 69 |
+
}
|
| 70 |
+
</style>
|
| 71 |
+
"""
|
| 72 |
+
st.markdown(style_table, unsafe_allow_html=True)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def mostrar_tabla(info_fil, placeholder, select):
|
| 76 |
+
info_fil2 = info_fil.copy()
|
| 77 |
+
info_fil2 = info_fil2[select]
|
| 78 |
+
placeholder.table(info_fil2)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
@st.experimental_memo
|
| 82 |
+
def leer_notas():
|
| 83 |
+
url = credpost["POSTGRESQL"]
|
| 84 |
+
engine = create_engine(url, echo=False)
|
| 85 |
+
data = pd.read_sql_query("SELECT * FROM notas_analistas", con=engine)
|
| 86 |
+
data.columns = ["Analista", "Comentario", "Date", "Empresa", "ID_Quant",
|
| 87 |
+
"LV1", "Nota",
|
| 88 |
+
"Pais", "Ticker Bloomberg", "Tipo de Comentario"]
|
| 89 |
+
data.index = pd.to_datetime(data['Date']).dt.strftime('%d/%m/%Y')
|
| 90 |
+
data.index.name = "Fecha"
|
| 91 |
+
data = data.sort_index(ascending=False)
|
| 92 |
+
return data
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
@log
|
| 96 |
+
def ver_nota():
|
| 97 |
+
select = ["Analista", "Tipo de Comentario", "Empresa", "Pais", "Nota",
|
| 98 |
+
"Comentario"]
|
| 99 |
+
key = creds3["S3_KEY_ID"]
|
| 100 |
+
secret_key = creds3["S3_SECRET_KEY"]
|
| 101 |
+
bucket = creds3["S3_BUCKET"]
|
| 102 |
+
path ="Analistas Empresa.xlsx"
|
| 103 |
+
style_table()
|
| 104 |
+
col1, col2, col3, col4 = st.columns(4)
|
| 105 |
+
data = leer_notas()
|
| 106 |
+
select = ["Analista", "Pais", "LV1", "Empresa", "Nota",
|
| 107 |
+
"Comentario"]
|
| 108 |
+
data3 = read_excel_s3(key, secret_key, bucket, path)
|
| 109 |
+
data4 = data3.copy()
|
| 110 |
+
autores = sorted(list(set(data4["Analista"].dropna())))
|
| 111 |
+
Autor = col1.selectbox("Analista", ["-"] + autores)
|
| 112 |
+
if Autor != "-":
|
| 113 |
+
data4 = data4[data4["Analista"] == Autor]
|
| 114 |
+
data = data[data["Analista"] == Autor]
|
| 115 |
+
pais = sorted(list(set(data4["Pais"].dropna())))
|
| 116 |
+
Pais = col2.selectbox("Pais", ["-"] + pais)
|
| 117 |
+
if Pais != "-":
|
| 118 |
+
data4 = data4[data4["Pais"] == Pais]
|
| 119 |
+
data = data[data["Pais"] == Pais]
|
| 120 |
+
industria = sorted(list(set(data4["LV1"].dropna())))
|
| 121 |
+
Industria = col3.selectbox("Industria", ["-"] + industria)
|
| 122 |
+
if Industria != "-":
|
| 123 |
+
data4 = data4[data4["LV1"] == Industria]
|
| 124 |
+
data = data[data["LV1"] == Industria]
|
| 125 |
+
empresa = sorted(list(set(data4["Empresa"].dropna())))
|
| 126 |
+
Empresa = col4.selectbox("Empresa", ["-"] + empresa)
|
| 127 |
+
if Empresa != "-":
|
| 128 |
+
data4 = data4[data4["Empresa"] == Empresa]
|
| 129 |
+
data = data[data["Empresa"] == Empresa]
|
| 130 |
+
info_fil = data
|
| 131 |
+
Ordenar_por = col1.selectbox("Ordenar por", ["Date", "Analista", "Pais",
|
| 132 |
+
"LV1", "Empresa"])
|
| 133 |
+
mayor = col2.selectbox("Asc o desc", ["Descendiente",
|
| 134 |
+
"Ascendiente"])
|
| 135 |
+
fec_i = col3.date_input('Fecha de inicio', datetime.date(2021, 7, 1))
|
| 136 |
+
fec_f = col4.date_input('Fecha final')
|
| 137 |
+
placeholder = st.empty()
|
| 138 |
+
if mayor != "-" and Ordenar_por != "-":
|
| 139 |
+
var = Ordenar_por
|
| 140 |
+
if mayor == "Ascendiente":
|
| 141 |
+
info_fil = info_fil.sort_values(var, ascending=True)
|
| 142 |
+
else:
|
| 143 |
+
info_fil = info_fil.sort_values(var, ascending=False)
|
| 144 |
+
info_fil = info_fil[info_fil["Date"].dt.date >= fec_i]
|
| 145 |
+
info_fil = info_fil[info_fil["Date"].dt.date <= fec_f]
|
| 146 |
+
mostrar_tabla(info_fil, placeholder, select)
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
@st.experimental_memo
|
| 150 |
+
def read_mapeo_analistas():
|
| 151 |
+
key = creds3["S3_KEY_ID"]
|
| 152 |
+
secret_key = creds3["S3_SECRET_KEY"]
|
| 153 |
+
bucket = creds3["S3_BUCKET"]
|
| 154 |
+
path = "Analistas Empresa.xlsx"
|
| 155 |
+
return read_excel_s3(key, secret_key, bucket, path)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
@st.experimental_memo
|
| 159 |
+
def read_company_db():
|
| 160 |
+
company_db = pd.pandas.read_excel("Data/Company_Base_Definitivo.xlsx",
|
| 161 |
+
sheet_name="Compilado",
|
| 162 |
+
engine="openpyxl")
|
| 163 |
+
return company_db
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def aggrid_notas(data):
|
| 167 |
+
gb = GridOptionsBuilder.from_dataframe(data)
|
| 168 |
+
# make columns editable
|
| 169 |
+
gb.configure_columns(["Nota",
|
| 170 |
+
"Comentario"], editable=True)
|
| 171 |
+
gb.configure_column('Nota',
|
| 172 |
+
cellEditor='agRichSelectCellEditor',
|
| 173 |
+
cellEditorParams={'values': [1, 2, 3, 4, 5]}
|
| 174 |
+
)
|
| 175 |
+
js = JsCode("""
|
| 176 |
+
function(e) {
|
| 177 |
+
let api = e.api;
|
| 178 |
+
let rowIndex = e.rowIndex;
|
| 179 |
+
let col = e.column.colId;
|
| 180 |
+
let rowNode = api.getDisplayedRowAtIndex(rowIndex);
|
| 181 |
+
api.flashCells({
|
| 182 |
+
rowNodes: [rowNode],
|
| 183 |
+
columns: [col],
|
| 184 |
+
flashDelay: 10000000000
|
| 185 |
+
});
|
| 186 |
+
};
|
| 187 |
+
""")
|
| 188 |
+
gb.configure_grid_options(onCellValueChanged=js)
|
| 189 |
+
go = gb.build()
|
| 190 |
+
return AgGrid(data, gridOptions=go, key='grid1',
|
| 191 |
+
allow_unsafe_jscode=True,
|
| 192 |
+
reload_data=False,
|
| 193 |
+
fit_columns_on_grid_load=False,
|
| 194 |
+
enable_enterprise_modules=True)
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def ingresar_nota():
|
| 198 |
+
try:
|
| 199 |
+
notas_df = leer_notas()
|
| 200 |
+
companydb_df = read_company_db()
|
| 201 |
+
companies_assigned_df = read_mapeo_analistas()
|
| 202 |
+
notas_df["Comentario"] = notas_df["Comentario"].fillna(" ")
|
| 203 |
+
analista = st.session_state["name"]
|
| 204 |
+
empresa_analista = sorted(
|
| 205 |
+
list(set(companies_assigned_df[companies_assigned_df["Analista"]
|
| 206 |
+
== analista]["Empresa"])))
|
| 207 |
+
companies_fil = companies_assigned_df[
|
| 208 |
+
companies_assigned_df["Analista"] == analista]
|
| 209 |
+
data_fil_a = notas_df[notas_df["Analista"] == analista].drop_duplicates(
|
| 210 |
+
"Empresa")
|
| 211 |
+
data_fil = data_fil_a[["Empresa", "Nota", "Comentario"]]
|
| 212 |
+
data_fil = companies_fil.merge(data_fil,
|
| 213 |
+
on="Empresa",
|
| 214 |
+
how='left').reset_index()
|
| 215 |
+
data_fil["Nota"] = data_fil["Nota"].fillna(0)
|
| 216 |
+
data_fil["Comentario"] = data_fil["Comentario"].fillna(" ")
|
| 217 |
+
data_fil = data_fil[["Empresa",
|
| 218 |
+
"Pais",
|
| 219 |
+
"LV1",
|
| 220 |
+
"Nota",
|
| 221 |
+
"Comentario"]].sort_values("LV1")
|
| 222 |
+
notas = aggrid_notas(data_fil)
|
| 223 |
+
notas_f = notas["data"]
|
| 224 |
+
update_notas = []
|
| 225 |
+
for emp in notas_f.Empresa:
|
| 226 |
+
new_df = notas_f[notas_f.Empresa == emp]
|
| 227 |
+
old_df = data_fil[data_fil.Empresa == emp]
|
| 228 |
+
new_nota = new_df.iloc[0].Nota
|
| 229 |
+
new_comentario = new_df.iloc[0].Comentario
|
| 230 |
+
old_nota = old_df.iloc[0].Nota
|
| 231 |
+
old_comentario = old_df.iloc[0].Comentario
|
| 232 |
+
if old_nota != new_nota or old_comentario != new_comentario:
|
| 233 |
+
update_notas.append(notas_f[notas_f.Empresa == emp])
|
| 234 |
+
update_final = pd.concat(update_notas)
|
| 235 |
+
st.write(update_final)
|
| 236 |
+
submitted_2 = st.button("Update Notas")
|
| 237 |
+
if submitted_2:
|
| 238 |
+
today = datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S')
|
| 239 |
+
for emp in update_final.Empresa:
|
| 240 |
+
df_emp = update_final[update_final.Empresa==emp]
|
| 241 |
+
empresa_df = companydb_df[companydb_df['Short_Name']==emp].iloc[0]
|
| 242 |
+
pais = empresa_df['Portfolio_Country']
|
| 243 |
+
industria = empresa_df["LV1"]
|
| 244 |
+
id_quant = empresa_df["ID_Quant"]
|
| 245 |
+
tbloom = empresa_df['Ticker Bloomberg']
|
| 246 |
+
comentario = df_emp.iloc[0]["Comentario"]
|
| 247 |
+
nota = df_emp.iloc[0]["Nota"]
|
| 248 |
+
var = """(analista, comentario, date_nota, empresa, id_quant, lv1,
|
| 249 |
+
nota, pais, ticker_bloomberg)"""
|
| 250 |
+
if "'" in emp:
|
| 251 |
+
emp = emp.replace("'", "")
|
| 252 |
+
varlist = [analista, comentario, today, emp, id_quant,
|
| 253 |
+
industria, nota, pais, tbloom]
|
| 254 |
+
# try:
|
| 255 |
+
url = credpost["POSTGRESQL"]
|
| 256 |
+
conn = psycopg2.connect(url, sslmode='require')
|
| 257 |
+
cur = conn.cursor()
|
| 258 |
+
cur.execute("INSERT INTO notas_test {Var} VALUES %r; ".
|
| 259 |
+
format(Var=var) % (tuple(varlist),))
|
| 260 |
+
conn.commit()
|
| 261 |
+
cur.close()
|
| 262 |
+
conn.close()
|
| 263 |
+
st.info("Nota ingresada exitosamente")
|
| 264 |
+
if emp != "-":
|
| 265 |
+
asunto = "Actualizacion nota " + emp + " - " + analista
|
| 266 |
+
mensaje = analista + " ha actualizado la nota de la empresa " + emp + " a " + str(nota)
|
| 267 |
+
else:
|
| 268 |
+
asunto = "Actualizacion nota " + industria + " - " + analista
|
| 269 |
+
mensaje = analista + " ha actualizado la nota de la industria " + industria + " a " + str(nota)
|
| 270 |
+
destinatario = st.session_state['mail']
|
| 271 |
+
mail = Mailer(asunto, mensaje, "", "bullm@larrainvial.com")
|
| 272 |
+
mail.send_message([#destinatario,
|
| 273 |
+
"bullm@larrainvial.com,",
|
| 274 |
+
"benjamin.ull.m@gmail.com"])
|
| 275 |
+
# except:
|
| 276 |
+
# st.error("Problemas al ingresar la nota")
|
| 277 |
+
# asunto = "Actualizacion nota " + emp + " - " + analista
|
| 278 |
+
# mensaje = analista + " ha tenido problemas con la nota de" + emp + " a " + str(nota)
|
| 279 |
+
# mail = Mailer(asunto, mensaje, "", "bullm@larrainvial.com")
|
| 280 |
+
# mail.send_message(["bullm@larrainvial.com,",
|
| 281 |
+
# "benjamin.ull.m@gmail.com"])
|
| 282 |
+
st.experimental_memo.clear()
|
| 283 |
+
except Exception as exc:
|
| 284 |
+
st.write(exc)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
def ingresar_nota_ex():
|
| 289 |
+
|
| 290 |
+
Analistas = {
|
| 291 |
+
"fsutter": "Florencia Sutter",
|
| 292 |
+
"alehmann": "Alejandro Lehmann",
|
| 293 |
+
"bcosoi": "Benjamín Cosoi",
|
| 294 |
+
"chinojosa": "Carlos Hinojosa",
|
| 295 |
+
"gcatalan": "Gustavo Catalan",
|
| 296 |
+
"bull": "Benjamin Ul",
|
| 297 |
+
"ftaverne": "Francisca Taverne"
|
| 298 |
+
}
|
| 299 |
+
notas_df = leer_notas()
|
| 300 |
+
companydb_df = read_company_db()
|
| 301 |
+
companies_assigned_df = read_mapeo_analistas()
|
| 302 |
+
notas_df["Comentario"] = notas_df["Comentario"].fillna(" ")
|
| 303 |
+
if st.session_state.key in list(Analistas.keys()):
|
| 304 |
+
analista = Analistas[st.session_state.key]
|
| 305 |
+
data_analista = companies_assigned_df[companies_assigned_df["Analista"] == analista]
|
| 306 |
+
industrias_analista = sorted(list(
|
| 307 |
+
set(companies_assigned_df[companies_assigned_df["Analista"]
|
| 308 |
+
== analista]["LV1"])))
|
| 309 |
+
empresa_analista = sorted(list(
|
| 310 |
+
set(companies_assigned_df[companies_assigned_df["Analista"]
|
| 311 |
+
== analista]["Empresa"])))
|
| 312 |
+
else:
|
| 313 |
+
analista = st.session_state.key
|
| 314 |
+
data_analista = companies_assigned_df[
|
| 315 |
+
companies_assigned_df["Analista"] == analista]
|
| 316 |
+
industrias_analista = sorted(
|
| 317 |
+
list(set(companies_assigned_df[companies_assigned_df["Analista"]
|
| 318 |
+
== analista]["LV1"])))
|
| 319 |
+
empresa_analista = sorted(
|
| 320 |
+
list(set(companies_assigned_df[companies_assigned_df["Analista"]
|
| 321 |
+
== analista]["Empresa"])))
|
| 322 |
+
Countries = sorted(list(set(data_analista["Pais"])))
|
| 323 |
+
LV1s = sorted(list(set(data_analista["LV1"])))
|
| 324 |
+
industrias = []
|
| 325 |
+
for c in Countries:
|
| 326 |
+
for l in LV1s:
|
| 327 |
+
industrias.append(c + " - " + l)
|
| 328 |
+
col1, col2 = st.columns(2)
|
| 329 |
+
placeholder = col2.empty()
|
| 330 |
+
companies_fil = companies_assigned_df[
|
| 331 |
+
companies_assigned_df["Analista"] == analista]
|
| 332 |
+
data_fil_a = notas_df[notas_df["Analista"] == analista].drop_duplicates(
|
| 333 |
+
"Empresa")
|
| 334 |
+
data_fil = data_fil_a[["Empresa", "Nota"]]
|
| 335 |
+
data_fil = companies_fil.merge(data_fil,
|
| 336 |
+
on="Empresa",
|
| 337 |
+
how='left').fillna(0)
|
| 338 |
+
with col1:
|
| 339 |
+
notas_df2 = notas_df
|
| 340 |
+
porc_total = (notas_df.drop_duplicates("Empresa")["Nota"]>0).sum()/len(notas_df)
|
| 341 |
+
porc_emp_notas = (data_fil["Nota"] > 0).sum()/len(data_fil)*100
|
| 342 |
+
delta_per = round(porc_total - porc_emp_notas, 2)
|
| 343 |
+
st.metric("% de empresas con nota", round(porc_emp_notas,2), delta_per)
|
| 344 |
+
notas_table = display_table(data_fil[["Empresa",
|
| 345 |
+
"Pais",
|
| 346 |
+
"LV1",
|
| 347 |
+
"Nota"]].sort_values("LV1"))
|
| 348 |
+
|
| 349 |
+
if len(notas_table["selected_rows"]) > 0:
|
| 350 |
+
emp_name = notas_table["selected_rows"][0]["Empresa"]
|
| 351 |
+
st.subheader("Comentario")
|
| 352 |
+
data_emp_df = data_fil_a[data_fil_a["Empresa"] == emp_name]
|
| 353 |
+
if len(data_emp_df) > 0:
|
| 354 |
+
st.write(data_emp_df.iloc[0]["Comentario"])
|
| 355 |
+
id_quant = data_emp_df.iloc[0]["ID_Quant"]
|
| 356 |
+
country = data_emp_df.iloc[0]["Pais"]
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
with placeholder.form("my_form2", True):
|
| 360 |
+
# col1, col2, col3, col4 = st.columns((3, 8, 2, 1.5))
|
| 361 |
+
Empresas = ["-"]+sorted(list(empresa_analista) + industrias)
|
| 362 |
+
st.markdown(
|
| 363 |
+
'<p style="font-size:12px; padding-left:0px; margin-bottom:0px;">Analista</p>',
|
| 364 |
+
unsafe_allow_html=True)
|
| 365 |
+
st.markdown('<h3 style="padding-left:0px;; margin-bottom:0px;"">'+analista+"</h3>",
|
| 366 |
+
unsafe_allow_html=True)
|
| 367 |
+
if len(notas_table["selected_rows"]) <1:
|
| 368 |
+
empresa = st.selectbox('Empresa', Empresas)
|
| 369 |
+
else:
|
| 370 |
+
empresa = notas_table["selected_rows"][0]["Empresa"]
|
| 371 |
+
st.subheader(empresa)
|
| 372 |
+
tipo_comentario = "Nota"
|
| 373 |
+
nota = st.selectbox("Nota", [0, 1, 2, 3, 4, 5])
|
| 374 |
+
comentario = st.text_area('Comentario')
|
| 375 |
+
submitted_2 = st.form_submit_button("Publicar ")
|
| 376 |
+
var = """(analista, comentario, date_nota, empresa, id_quant, lv1,
|
| 377 |
+
nota, pais, ticker_bloomberg)"""
|
| 378 |
+
today = datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S')
|
| 379 |
+
if submitted_2:
|
| 380 |
+
st.experimental_memo.clear()
|
| 381 |
+
empresa_df = companydb_df[companydb_df['Short_Name']==empresa].iloc[0]
|
| 382 |
+
pais = empresa_df['Portfolio_Country']
|
| 383 |
+
industria = empresa_df["LV1"]
|
| 384 |
+
id_quant = empresa_df["ID_Quant"]
|
| 385 |
+
tbloom = empresa_df['Ticker Bloomberg']
|
| 386 |
+
if "'" in empresa:
|
| 387 |
+
empresa = empresa.replace("'", "")
|
| 388 |
+
varlist = [analista, comentario, today, empresa, id_quant,
|
| 389 |
+
industria, nota, pais, tbloom]
|
| 390 |
+
try:
|
| 391 |
+
url = credpost["POSTGRESQL"]
|
| 392 |
+
conn = psycopg2.connect(url, sslmode='require')
|
| 393 |
+
cur = conn.cursor()
|
| 394 |
+
cur.execute("INSERT INTO notas_analistas {Var} VALUES %r; ".
|
| 395 |
+
format(Var=var) % (tuple(varlist),))
|
| 396 |
+
conn.commit()
|
| 397 |
+
cur.close()
|
| 398 |
+
conn.close()
|
| 399 |
+
st.info("Nota ingresada exitosamente")
|
| 400 |
+
if empresa != "-":
|
| 401 |
+
asunto = "Actualizacion nota " + empresa + " - " + analista
|
| 402 |
+
mensaje = analista + " ha actualizado la nota de la empresa " + empresa + " a " + str(nota)
|
| 403 |
+
else:
|
| 404 |
+
asunto = "Actualizacion nota " + industria + " - " + analista
|
| 405 |
+
mensaje = analista + " ha actualizado la nota de la industria " + industria + " a " + str(nota)
|
| 406 |
+
destinatario = st.session_state['mail']
|
| 407 |
+
mail = Mailer(asunto, mensaje, "", "bullm@larrainvial.com")
|
| 408 |
+
mail.send_message([destinatario,
|
| 409 |
+
"bullm@larrainvial.com,",
|
| 410 |
+
"benjamin.ull.m@gmail.com"])
|
| 411 |
+
except:
|
| 412 |
+
st.error("Problemas al ingresar la nota")
|
| 413 |
+
asunto = "Actualizacion nota " + empresa + " - " + analista
|
| 414 |
+
mensaje = analista + " ha tenido problemas con la nota de" + empresa + " a " + str(nota)
|
| 415 |
+
mail = Mailer(asunto, mensaje, "", "bullm@larrainvial.com")
|
| 416 |
+
mail.send_message(["bullm@larrainvial.com,",
|
| 417 |
+
"benjamin.ull.m@gmail.com"])
|
| 418 |
+
notas_df = leer_notas()
|
| 419 |
+
|
| 420 |
+
# st.write(data_fil.columns)
|
| 421 |
+
# st.table(data_fil[["Analista","Empresa", "LV1","Nota", "Comentario"]])
|
| 422 |
+
|
| 423 |
+
@log
|
| 424 |
+
def estadisticas():
|
| 425 |
+
data = leer_notas()
|
| 426 |
+
st.subheader("Distribución de notas")
|
| 427 |
+
data = data[data["Nota"] != 0]
|
| 428 |
+
col1, col2 = st.columns((1.681, 1))
|
| 429 |
+
place = col1.empty()
|
| 430 |
+
val = col2.selectbox("Seleccione un analista", list(set(data["Analista"].dropna())))
|
| 431 |
+
data_fil = data[data["Analista"] == val]
|
| 432 |
+
data_fil["count"] = 1
|
| 433 |
+
data_fil2 = data_fil.groupby(by=["Nota"],
|
| 434 |
+
as_index=False).agg({"count": "sum"})
|
| 435 |
+
data_fil3 = data.sort_values("Date", ascending=False)
|
| 436 |
+
data_fil3 = data_fil3[data_fil3["ID_Quant"] == 0]
|
| 437 |
+
data_fil4 = data_fil3.groupby(by=["LV1", "Pais", "Empresa", "Date"],
|
| 438 |
+
as_index=False).agg({"Nota": "mean"})
|
| 439 |
+
data_fil3 = data_fil3.groupby(by=["LV1"],
|
| 440 |
+
as_index=False).agg({"Nota": "mean"})
|
| 441 |
+
l = []
|
| 442 |
+
for i in range(len(data_fil2)):
|
| 443 |
+
l.append(str(round(data_fil2.iloc[i]["Nota"])))
|
| 444 |
+
data_fil2["Nota "] = l
|
| 445 |
+
fig = px.bar(data_fil2, x="Nota ", y="count",
|
| 446 |
+
color_discrete_sequence=['indianred'])
|
| 447 |
+
fig.update_layout(bargap=0.2)
|
| 448 |
+
place.plotly_chart(fig, use_container_width=True)
|
| 449 |
+
col2.header("Media = " + str(round(sum(data_fil2["Nota"]*data_fil2["count"])/sum(data_fil2["count"]),1)))
|
| 450 |
+
data["Datetime"] = pd.to_datetime(data["Date"], format='%Y-%m-%d %H:%M:%S',
|
| 451 |
+
errors='ignore')
|
| 452 |
+
data_fil4["Datetime"] = pd.to_datetime(data_fil4["Date"],
|
| 453 |
+
format='%Y-%m-%d %H:%M:%S',
|
| 454 |
+
errors='ignore')
|
| 455 |
+
st.subheader("Evolución por empresa")
|
| 456 |
+
col1, col2 = st.columns((2, 1))
|
| 457 |
+
placeholder = col1.empty()
|
| 458 |
+
pais = col2.selectbox("Seleccione un pais",
|
| 459 |
+
["-"] + sorted(list(set(data["Pais"].dropna()))))
|
| 460 |
+
if pais != "-":
|
| 461 |
+
data2 = data[data["Pais"] == pais]
|
| 462 |
+
else:
|
| 463 |
+
data2 = data
|
| 464 |
+
industria = col2.selectbox("Seleccione una industria",
|
| 465 |
+
["-"] + sorted(list(set(data2["LV1"].dropna()))))
|
| 466 |
+
if industria != "-":
|
| 467 |
+
data2 = data2[data2["LV1"] == industria]
|
| 468 |
+
else:
|
| 469 |
+
data2=data2
|
| 470 |
+
empr = col2.selectbox("Seleccione una empresa",
|
| 471 |
+
["-"] + sorted(list(set(data2["Empresa"].dropna()))))
|
| 472 |
+
if empr != "-":
|
| 473 |
+
notas_empr = data[data["Empresa"] == empr]
|
| 474 |
+
elif empr == "-" and pais == "-" and industria != "-":
|
| 475 |
+
notas_empr = data_fil4[data_fil4["LV1"]==industria]
|
| 476 |
+
elif empr == "-" and pais != "-" and industria == "-":
|
| 477 |
+
notas_empr = data_fil4[data_fil4["Pais"]==pais]
|
| 478 |
+
else:
|
| 479 |
+
notas_empr = data2
|
| 480 |
+
date_range = pd.date_range(notas_empr['Datetime'].min() - datetime.timedelta(days=4),
|
| 481 |
+
datetime.datetime.today() + datetime.timedelta(days=1))
|
| 482 |
+
hist_notas = pd.DataFrame(index=date_range)
|
| 483 |
+
if empr == "-" and pais == "-" and industria == "-":
|
| 484 |
+
placeholder.empty()
|
| 485 |
+
else:
|
| 486 |
+
for empresa in list(set(notas_empr["Empresa"])):
|
| 487 |
+
l = []
|
| 488 |
+
a = 0
|
| 489 |
+
for i in list(date_range):
|
| 490 |
+
data3 = notas_empr[notas_empr["Empresa"] == empresa]
|
| 491 |
+
data3 = data3[data3["Datetime"].dt.date == i]
|
| 492 |
+
if len(data3) == 0:
|
| 493 |
+
l.append(a)
|
| 494 |
+
else:
|
| 495 |
+
a = data3.iloc[0]["Nota"]
|
| 496 |
+
l.append(a)
|
| 497 |
+
hist_notas[empresa] = l
|
| 498 |
+
hist_notas["Date"] = list(hist_notas.index)
|
| 499 |
+
fig2 = px.line(hist_notas, x="Date", y=hist_notas.columns)
|
| 500 |
+
fig2.update_traces(textposition="bottom right")
|
| 501 |
+
placeholder.plotly_chart(fig2, use_container_width=True)
|
| 502 |
+
col2.header(" ")
|
| 503 |
+
col2.header(" ")
|
| 504 |
+
col1, col2 = st.columns((2, 1))
|
| 505 |
+
col1.subheader("Promedio por industria")
|
| 506 |
+
add_pais = col2.selectbox("Añadir Pais", ["-"] + list(set(data_fil4["Pais"])))
|
| 507 |
+
if add_pais != "-":
|
| 508 |
+
data_fil4 = data_fil4[data_fil4["Pais"] == add_pais]
|
| 509 |
+
data_fil4 = data_fil4.sort_values(by = "Datetime", ascending = False)
|
| 510 |
+
data_fil4 = data_fil4.drop_duplicates("LV1")
|
| 511 |
+
fig3 = go.Figure(data=[
|
| 512 |
+
go.Bar(name='General', x=data_fil3["LV1"], y=data_fil3["Nota"]),
|
| 513 |
+
go.Bar(name=add_pais, x=data_fil4["LV1"], y=data_fil4["Nota"])
|
| 514 |
+
])
|
| 515 |
+
fig3.update_yaxes(range=[min(min(data_fil3['Nota']),
|
| 516 |
+
min(data_fil4['Nota']))/1.1,
|
| 517 |
+
max(max(data_fil3['Nota']),
|
| 518 |
+
max(data_fil4['Nota']))*1.1])
|
| 519 |
+
else:
|
| 520 |
+
fig3 = go.Figure(data=[
|
| 521 |
+
go.Bar(name='General', x=data_fil3["LV1"], y=data_fil3["Nota"])
|
| 522 |
+
])
|
| 523 |
+
fig3.update_yaxes(range=[min(data_fil3['Nota'])/1.1,
|
| 524 |
+
max(data_fil3['Nota'])*1.1])
|
| 525 |
+
data_fil3 = data_fil3.sort_values("Nota")
|
| 526 |
+
fig3.update_layout(barmode='group',
|
| 527 |
+
xaxis={'categoryorder': 'total descending'})
|
| 528 |
+
|
| 529 |
+
st.plotly_chart(fig3, use_container_width=True)
|
| 530 |
+
|
| 531 |
+
|
| 532 |
+
def asignar_analista():
|
| 533 |
+
key = creds3["S3_KEY_ID"]
|
| 534 |
+
secret_key = creds3["S3_SECRET_KEY"]
|
| 535 |
+
bucket = creds3["S3_BUCKET"]
|
| 536 |
+
path ="Analistas Empresa.xlsx"
|
| 537 |
+
analista_emp = read_excel_s3(key, secret_key, bucket, path)
|
| 538 |
+
# analista_emp = pd.read_excel("Data/Analistas Empresa.xlsx", engine='openpyxl')
|
| 539 |
+
Analistas = {
|
| 540 |
+
"fsutter": "Florencia Sutter",
|
| 541 |
+
"alehmann": "Alejandro Lehmann",
|
| 542 |
+
"bcosoi": "Benjamín Cosoi",
|
| 543 |
+
"chinojosa": "Carlos Hinojosa",
|
| 544 |
+
"gcatalan": "Gustavo Catalan",
|
| 545 |
+
"bull": "Benjamin Ull",
|
| 546 |
+
"ftaverne": "Francisca Taverne"
|
| 547 |
+
}
|
| 548 |
+
analista_emp2 = analista_emp[["ID_Quant", "Analista", "Empresa", "LV1",
|
| 549 |
+
"Pais"]]
|
| 550 |
+
credenciales = pd.read_csv("Data/Credenciales_h.csv",
|
| 551 |
+
names=['Usuario', 'Password', 'Area',
|
| 552 |
+
'Cargo','Mail','Nombre'])
|
| 553 |
+
analistas = credenciales[credenciales["Cargo"] == "Investment Analyst"]
|
| 554 |
+
col1, col2, col3 = st.columns(3)
|
| 555 |
+
analista = col1.selectbox("Analista",
|
| 556 |
+
sorted(list(set(Analistas.values()))))
|
| 557 |
+
industria = col2.selectbox("Industria",
|
| 558 |
+
sorted(list(set(analista_emp["LV1"]))))
|
| 559 |
+
col3.title(" ")
|
| 560 |
+
val = col3.checkbox("Seleccionar todos", value=True)
|
| 561 |
+
dicc ={}
|
| 562 |
+
with st.form("form"):
|
| 563 |
+
col1, col2 = st.columns(2)
|
| 564 |
+
col1.write("Asignar a: ")
|
| 565 |
+
col2.write("Industria: ")
|
| 566 |
+
col1.subheader(analista)
|
| 567 |
+
col2.subheader(industria)
|
| 568 |
+
col1.header(" ")
|
| 569 |
+
col2.header(" ")
|
| 570 |
+
col1, col2 = st.columns(2)
|
| 571 |
+
empresas = analista_emp[analista_emp["LV1"]==industria]["Empresa"]
|
| 572 |
+
i = 0
|
| 573 |
+
for empresa in empresas:
|
| 574 |
+
if i%2 == 0:
|
| 575 |
+
dicc[empresa] = col1.checkbox(empresa, value=val)
|
| 576 |
+
i += 1
|
| 577 |
+
else:
|
| 578 |
+
dicc[empresa] = col2.checkbox(empresa, value=val)
|
| 579 |
+
i += 1
|
| 580 |
+
submit = st.form_submit_button("Asignar")
|
| 581 |
+
if submit:
|
| 582 |
+
for empresa in dicc.keys():
|
| 583 |
+
if dicc[empresa]:
|
| 584 |
+
cambio = analista_emp2[analista_emp2["Empresa"] == empresa]
|
| 585 |
+
analista_emp2.loc[analista_emp2.Empresa == empresa, 'Analista'] = analista
|
| 586 |
+
save_s3(key, secret_key, bucket, analista_emp2, path)
|
| 587 |
+
style_table()
|
| 588 |
+
data_f = analista_emp2[["Analista", "Pais", "LV1", "Empresa"]]
|
| 589 |
+
data_f = data_f[data_f["Analista"] == analista]
|
| 590 |
+
graph = graphviz.Digraph()
|
| 591 |
+
for industry in list(set(data_f["LV1"])):
|
| 592 |
+
graph.edge(analista, industry)
|
| 593 |
+
d_ind = data_f[data_f["LV1"]==industry]
|
| 594 |
+
st.subheader("Mapeo Analista - Industrias")
|
| 595 |
+
st.graphviz_chart(graph)
|
| 596 |
+
d_ind = analista_emp2[["Analista", "Pais", "LV1", "Empresa"]]
|
| 597 |
+
d_ind = d_ind[d_ind["LV1"] == industria]
|
| 598 |
+
st.subheader("Analistas asignados a la industria " + industria)
|
| 599 |
+
st.table(d_ind)
|
| 600 |
+
|
| 601 |
+
|
| 602 |
+
def save_password():
|
| 603 |
+
key = creds3["S3_KEY_ID"]
|
| 604 |
+
secret_key = creds3["S3_SECRET_KEY"]
|
| 605 |
+
bucket = creds3["S3_BUCKET"]
|
| 606 |
+
path ='Claves.xlsx'
|
| 607 |
+
claves = read_excel_s3(key, secret_key, bucket, path)
|
| 608 |
+
col1, col2 = st.columns((1, 1.5))
|
| 609 |
+
with col1.form('Nueva clave'):
|
| 610 |
+
new_user = st.text_input("Ingresar usuario")
|
| 611 |
+
password = st.text_input("Ingresar clave")
|
| 612 |
+
plataforma = st.text_input("Plataforma")
|
| 613 |
+
submitted = st.form_submit_button('Ingresar')
|
| 614 |
+
if submitted:
|
| 615 |
+
claves = claves.append({"Clave": password,
|
| 616 |
+
"Usuario": new_user,
|
| 617 |
+
"Plataforma": plataforma
|
| 618 |
+
}, ignore_index=True)
|
| 619 |
+
save_s3(key, secret_key, bucket, claves, path)
|
| 620 |
+
style_table()
|
| 621 |
+
claves.index = claves['Plataforma']
|
| 622 |
+
col2.table(claves[['Usuario','Clave']])
|
| 623 |
+
|
apps/Google_Trends.py
CHANGED
|
@@ -1,3 +1,490 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from modules import tables
|
| 2 |
+
from google_tools import trends as gtrends
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import numpy as np
|
| 5 |
+
from datetime import timedelta, date
|
| 6 |
+
from statsmodels.tsa.seasonal import seasonal_decompose
|
| 7 |
+
import plotly.graph_objects as go
|
| 8 |
+
from plotly.subplots import make_subplots
|
| 9 |
+
import streamlit as st
|
| 10 |
+
import io
|
| 11 |
+
import boto3
|
| 12 |
+
import openpyxl
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
key ='AKIARYMZ4J2YQDB66VX4'
|
| 16 |
+
secret_key = 'Jr5kvwPBF6XfUBnBOEjGaOirqOAIqo771mXIoRUy'
|
| 17 |
+
bucket='portallvam'
|
| 18 |
+
path ='Momentum.xlsx'
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def save_s3(key, secret_key, bucket, df, path):
|
| 22 |
+
with io.BytesIO() as output:
|
| 23 |
+
with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
|
| 24 |
+
for industry in df.keys():
|
| 25 |
+
df[industry].to_excel(writer, sheet_name=industry)
|
| 26 |
+
data = output.getvalue()
|
| 27 |
+
s3 = boto3.resource('s3', aws_access_key_id=key, aws_secret_access_key=secret_key)
|
| 28 |
+
s3.Bucket(bucket).put_object(Key=path, Body=data)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def read_excel_s3(key, secret_key, bucket, path):
|
| 32 |
+
s3_client = boto3.client('s3', aws_access_key_id=key, aws_secret_access_key=secret_key)
|
| 33 |
+
response = s3_client.get_object(Bucket=bucket, Key=path)
|
| 34 |
+
data = response["Body"].read()
|
| 35 |
+
df = pd.read_excel(io.BytesIO(data), sheet_name=None, index_col='Unnamed: 0.1')
|
| 36 |
+
return df
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def generar_excel(ruta_guardado, Pestanas, Data):
|
| 40 |
+
wb = openpyxl.Workbook()
|
| 41 |
+
writer = pd.ExcelWriter(ruta_guardado)
|
| 42 |
+
for pestana in Pestanas:
|
| 43 |
+
wb.create_sheet(pestana)
|
| 44 |
+
std = wb.get_sheet_by_name('Sheet')
|
| 45 |
+
wb.remove_sheet(std)
|
| 46 |
+
wb.save(ruta_guardado)
|
| 47 |
+
for i, pestana in enumerate(Pestanas):
|
| 48 |
+
if pestana=='Real Estate Management & Development-CL':
|
| 49 |
+
pestana = 'Real Estate-CL'
|
| 50 |
+
Data['Real Estate Management & Development-CL'].to_excel(writer, sheet_name=pestana)
|
| 51 |
+
elif pestana=='Real Estate Management & Development-BR':
|
| 52 |
+
pestana = 'Real Estate-BR'
|
| 53 |
+
Data['Real Estate Management & Development-BR'].to_excel(writer, sheet_name=pestana)
|
| 54 |
+
else:
|
| 55 |
+
Data[pestana].to_excel(writer, sheet_name=Pestanas[i])
|
| 56 |
+
writer.save()
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def colores_corporativos(colors=None):
|
| 60 |
+
|
| 61 |
+
color_dict = {'red': (204, 0, 51),
|
| 62 |
+
'light_blue': (110, 162, 201),
|
| 63 |
+
'light_gray': (135, 146, 158),
|
| 64 |
+
'grey': (105, 105, 105),
|
| 65 |
+
'yellow': (195, 195, 9),
|
| 66 |
+
'dark_purple': (119, 28, 95),
|
| 67 |
+
'blue': (42, 83, 113),
|
| 68 |
+
'purple': (159, 37, 127),
|
| 69 |
+
'light_yellow': (252, 252, 196),
|
| 70 |
+
'light_green': (122, 178, 153),
|
| 71 |
+
'gray': (66, 74, 82)}
|
| 72 |
+
|
| 73 |
+
for key in color_dict:
|
| 74 |
+
color_dict[key] = tuple(v/255 for v in color_dict[key])
|
| 75 |
+
|
| 76 |
+
if colors is None:
|
| 77 |
+
return color_dict
|
| 78 |
+
else:
|
| 79 |
+
aux = {col: color_dict[col] for col in colors}
|
| 80 |
+
return aux
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
corp_colors = list(colores_corporativos().values())
|
| 84 |
+
colors2 = []
|
| 85 |
+
for i in range(len(corp_colors)):
|
| 86 |
+
colors2.append("rgb" + str(corp_colors[i]))
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
company_db = pd.read_excel('Data/Company_Base_Definitivo.xlsx', sheet_name='Compilado')
|
| 90 |
+
id_to_ticker = {str(row['ID_Quant']): str(row['Ticker Bloomberg']).split()[0] for i, row in company_db.iterrows()}
|
| 91 |
+
|
| 92 |
+
countries_dict = {'BR': 'Brazil', 'CL': 'Chile', 'US': 'Brazil',
|
| 93 |
+
'US-Disease': 'Brazil'}
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
@st.cache(suppress_st_warning=True)
|
| 97 |
+
def data_request(countries, start, currency='USD'):
|
| 98 |
+
close_price = {'Brazil': [],
|
| 99 |
+
'Chile': []}
|
| 100 |
+
market_cap = {'Brazil': [],
|
| 101 |
+
'Chile': []}
|
| 102 |
+
for c in countries:
|
| 103 |
+
close_price[c] = tables.EquityMaster(field='IQ_CLOSEPRICE_ADJ', currency=currency, country=c).query(
|
| 104 |
+
rename=['asset'], start=start, expand=True)
|
| 105 |
+
market_cap[c] = tables.EquityMaster(field='IQ_MARKETCAP', currency=currency, country=c).query(
|
| 106 |
+
start=start, rename=['asset'], expand=True)
|
| 107 |
+
|
| 108 |
+
close_price[c] = close_price[c].loc[:, close_price[c].columns.isin(id_to_ticker.keys())]
|
| 109 |
+
close_price[c].columns = [id_to_ticker[col] for col in close_price[c].columns]
|
| 110 |
+
|
| 111 |
+
market_cap[c] = market_cap[c].loc[:, market_cap[c].columns.isin(id_to_ticker.keys())]
|
| 112 |
+
market_cap[c].columns = [id_to_ticker[col] for col in market_cap[c].columns]
|
| 113 |
+
return [close_price, market_cap]
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
@st.cache(suppress_st_warning=True)
|
| 117 |
+
def trends_request(keywords, today):
|
| 118 |
+
trends_frames_dict = {}
|
| 119 |
+
for sector, values in keywords.items():
|
| 120 |
+
if not (sector in ['Restaurantes']):
|
| 121 |
+
trends_frames_dict[sector] = {}
|
| 122 |
+
print('Buscando para ' + sector)
|
| 123 |
+
for country_name in values.columns:
|
| 124 |
+
words = values[country_name].dropna()
|
| 125 |
+
if '-' in country_name:
|
| 126 |
+
fixed_country_name = country_name.split('-')[0].strip()
|
| 127 |
+
else:
|
| 128 |
+
fixed_country_name = country_name
|
| 129 |
+
words_index = pd.DataFrame()
|
| 130 |
+
for word in words:
|
| 131 |
+
new_data = gtrends.keyword_trend(word, fixed_country_name, end_date=today)
|
| 132 |
+
if new_data is not None:
|
| 133 |
+
words_index = pd.concat([words_index,
|
| 134 |
+
new_data],
|
| 135 |
+
axis=1)
|
| 136 |
+
else:
|
| 137 |
+
print('No se encuentra data para ' + word)
|
| 138 |
+
trends_frames_dict[sector][country_name] = words_index
|
| 139 |
+
trends_frames_dict[sector][country_name].index.name = None
|
| 140 |
+
return trends_frames_dict
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def trends_frames_excel(dicc):
|
| 144 |
+
sheets_cl = []
|
| 145 |
+
sheets_br = []
|
| 146 |
+
for key_1 in dicc.keys():
|
| 147 |
+
for key_2 in dicc[key_1].keys():
|
| 148 |
+
if key_2=='CL':
|
| 149 |
+
sheets_cl .append(key_1 + '-' + key_2)
|
| 150 |
+
else:
|
| 151 |
+
sheets_br.append(key_1 + '-' + key_2)
|
| 152 |
+
trends_frames_dict_cl = {}
|
| 153 |
+
trends_frames_dict_br = {}
|
| 154 |
+
for key_1 in dicc.keys():
|
| 155 |
+
for key_2 in dicc[key_1].keys():
|
| 156 |
+
if key_2=='CL':
|
| 157 |
+
trends_frames_dict_cl[key_1 + '-'+ key_2] = dicc[key_1][key_2]
|
| 158 |
+
elif key_2=='BR':
|
| 159 |
+
trends_frames_dict_br[key_1 + '-' + key_2] = dicc[key_1][key_2]
|
| 160 |
+
elif key_2=='US' or key_2=='US-Disease':
|
| 161 |
+
trends_frames_dict_br[key_1 + '-' + key_2] = dicc[key_1][key_2]
|
| 162 |
+
|
| 163 |
+
generar_excel('Data/GT_CL.xlsx', sheets_cl, trends_frames_dict_cl)
|
| 164 |
+
df_cl = pd.read_excel('Data/GT_CL.xlsx', sheet_name=None)
|
| 165 |
+
st.write(df_cl)
|
| 166 |
+
save_s3(key=key, secret_key=secret_key, bucket=bucket, df=df_cl, path='GT_CL.xlsx')
|
| 167 |
+
|
| 168 |
+
generar_excel('Data/GT_BR.xlsx', sheets_br, trends_frames_dict_br)
|
| 169 |
+
df_br = pd.read_excel('Data/GT_BR.xlsx', sheet_name=None)
|
| 170 |
+
save_s3(key=key, secret_key=secret_key, bucket=bucket, df=df_br, path='GT_BR.xlsx')
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def read_trends_frames(country):
|
| 174 |
+
if country=='CL':
|
| 175 |
+
return read_excel_s3(key=key, secret_key=secret_key, bucket=bucket, path='GT_CL.xlsx')
|
| 176 |
+
elif country=='BR':
|
| 177 |
+
return read_excel_s3(key=key, secret_key=secret_key, bucket=bucket, path='GT_BR.xlsx')
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def report():
|
| 181 |
+
form = st.form('Report')
|
| 182 |
+
start_date = str(date.today() - timedelta(5 * 365))
|
| 183 |
+
select_countries = form.multiselect('¿Qué país(es) desea visualizar?', ['Todos', 'Chile', 'Brazil'])
|
| 184 |
+
if 'Todos' in select_countries:
|
| 185 |
+
select_countries = ['Chile', 'Brazil']
|
| 186 |
+
update_data = form.form_submit_button("Actualizar Datos")
|
| 187 |
+
accept = form.form_submit_button('Visualizar')
|
| 188 |
+
col1, col2 = st.columns(2)
|
| 189 |
+
|
| 190 |
+
if update_data:
|
| 191 |
+
xls = pd.ExcelFile('Data/keywords_definitivas_mongo.xlsx')
|
| 192 |
+
industry_filter = ['Pesca', 'Agricola', 'Financials-RP']
|
| 193 |
+
keywords_dict = {sheet: xls.parse(sheet) for sheet in xls.sheet_names
|
| 194 |
+
if sheet not in industry_filter}
|
| 195 |
+
xls.close()
|
| 196 |
+
del xls
|
| 197 |
+
|
| 198 |
+
# Arreglamos una llave porque una hoja de excel alcanza el máximo de caracteres posible para un nombre.
|
| 199 |
+
new_key = "Real Estate Management & Development"
|
| 200 |
+
old_key = "Real Estate Management & Develo"
|
| 201 |
+
keywords_dict[new_key] = keywords_dict.pop(old_key)
|
| 202 |
+
|
| 203 |
+
trends_dict = trends_request(keywords_dict, date.today())
|
| 204 |
+
trends_frames_excel(trends_dict)
|
| 205 |
+
ud = pd.read_excel('Data/update_data.xlsx')
|
| 206 |
+
ud = ud[ud['View'] != 'Google Trends']
|
| 207 |
+
today = date.today().strftime('%d-%m-%Y')
|
| 208 |
+
ud = ud.append({"View": 'Google Trends',
|
| 209 |
+
"Last_Update": today}, ignore_index=True)
|
| 210 |
+
ud.to_excel('Data/update_data.xlsx', index=False)
|
| 211 |
+
|
| 212 |
+
if accept:
|
| 213 |
+
close_price_dict, market_cap_dict = data_request(select_countries, start_date)
|
| 214 |
+
|
| 215 |
+
ew_index = {}
|
| 216 |
+
mw_index = {}
|
| 217 |
+
country_index = {}
|
| 218 |
+
|
| 219 |
+
if select_countries == ['Brazil']:
|
| 220 |
+
dates = {'Brazil': sorted(list(set(market_cap_dict['Brazil'].index)
|
| 221 |
+
.union(set(close_price_dict['Brazil'].index))))}
|
| 222 |
+
elif select_countries == ['Chile']:
|
| 223 |
+
dates = {'Chile': sorted(list(set(market_cap_dict['Chile'].index)
|
| 224 |
+
.union(set(close_price_dict['Chile'].index))))}
|
| 225 |
+
else:
|
| 226 |
+
dates = {'Brazil': sorted(list(set(market_cap_dict['Brazil'].index)
|
| 227 |
+
.union(set(close_price_dict['Brazil'].index)))),
|
| 228 |
+
'Chile': sorted(list(set(market_cap_dict['Chile'].index)
|
| 229 |
+
.union(set(close_price_dict['Chile'].index))))}
|
| 230 |
+
|
| 231 |
+
for country in select_countries:
|
| 232 |
+
mkt = market_cap_dict[country]
|
| 233 |
+
cp = close_price_dict[country]
|
| 234 |
+
w = mkt.div(mkt.sum(1).values, axis=0)
|
| 235 |
+
rets = cp.pct_change()
|
| 236 |
+
country_index[country] = pd.DataFrame({'MW': (w * rets).sum(1),
|
| 237 |
+
'EW': rets.mean(1)}).fillna(0)
|
| 238 |
+
industries_1 = np.unique(company_db[['LV1']].values)
|
| 239 |
+
industries_2 = np.unique(company_db[['LV2']].values)
|
| 240 |
+
industries = np.unique(np.concatenate([industries_1, industries_2]))
|
| 241 |
+
df_mw_index = pd.DataFrame(columns=industries, index=dates[country])
|
| 242 |
+
df_ew_index = pd.DataFrame(columns=industries, index=dates[country])
|
| 243 |
+
for industry in industries:
|
| 244 |
+
industry = str(industry)
|
| 245 |
+
mc = mkt.loc[:, mkt.columns.isin(company_db[company_db['LV1'] == industry]['Ticker'])]
|
| 246 |
+
prices = cp.loc[:, cp.columns.isin(company_db[company_db['LV1'] == industry]['Ticker'])]
|
| 247 |
+
|
| 248 |
+
w = mc.div(mc.sum(1).values, axis=0)
|
| 249 |
+
rets = prices.pct_change()
|
| 250 |
+
df_mw_index[industry] = (w * rets).sum(1)
|
| 251 |
+
df_ew_index[industry] = rets.mean(1)
|
| 252 |
+
mw_index[country] = df_mw_index.fillna(0)
|
| 253 |
+
ew_index[country] = df_ew_index.fillna(0)
|
| 254 |
+
|
| 255 |
+
xls = pd.ExcelFile('Data/keywords_definitivas_mongo.xlsx')
|
| 256 |
+
industry_filter = ['Pesca', 'Agricola', 'Financials-RP', 'Agriculture']
|
| 257 |
+
keywords_dict = {sheet: xls.parse(sheet) for sheet in xls.sheet_names
|
| 258 |
+
if sheet not in industry_filter}
|
| 259 |
+
xls.close()
|
| 260 |
+
del xls
|
| 261 |
+
|
| 262 |
+
new_key = "Real Estate Management & Development"
|
| 263 |
+
old_key = "Real Estate Management & Develo"
|
| 264 |
+
keywords_dict[new_key] = keywords_dict.pop(old_key)
|
| 265 |
+
|
| 266 |
+
trends_frames = {}
|
| 267 |
+
trends_frames_cl = read_trends_frames('CL')
|
| 268 |
+
trends_frames_br = read_trends_frames('BR')
|
| 269 |
+
|
| 270 |
+
for key_cl in trends_frames_cl.keys():
|
| 271 |
+
trends_frames_cl[key_cl] = trends_frames_cl[key_cl].drop(columns='Unnamed: 0')
|
| 272 |
+
|
| 273 |
+
for key_br in trends_frames_br.keys():
|
| 274 |
+
trends_frames_br[key_br] = trends_frames_br[key_br].drop(columns='Unnamed: 0')
|
| 275 |
+
|
| 276 |
+
for industry in keywords_dict.keys():
|
| 277 |
+
if not industry=='Restaurantes':
|
| 278 |
+
countries_in_industry = keywords_dict[industry].columns
|
| 279 |
+
trends_frames[industry] = {}
|
| 280 |
+
for c in countries_in_industry:
|
| 281 |
+
if c=='CL':
|
| 282 |
+
if industry == 'Real Estate Management & Development':
|
| 283 |
+
index = trends_frames_cl['Real Estate-CL'].index
|
| 284 |
+
trends_frames[industry][c] = pd.DataFrame(columns=trends_frames_cl['Real Estate-CL'].columns,
|
| 285 |
+
index=index)
|
| 286 |
+
else:
|
| 287 |
+
index = trends_frames_cl[industry+'-CL'].index
|
| 288 |
+
trends_frames_cl[industry+'-CL'] = trends_frames_cl[industry+'-CL'].loc[:, trends_frames_cl[industry+'-CL'].columns.notnull()]
|
| 289 |
+
trends_frames[industry][c] = pd.DataFrame(columns=trends_frames_cl[industry+'-CL'].columns,
|
| 290 |
+
index=index)
|
| 291 |
+
elif c=='BR':
|
| 292 |
+
if industry == 'Real Estate Management & Development':
|
| 293 |
+
index = trends_frames_br['Real Estate-BR'].index
|
| 294 |
+
trends_frames[industry][c] = pd.DataFrame(columns=trends_frames_br['Real Estate-BR'].columns,
|
| 295 |
+
index=index)
|
| 296 |
+
else:
|
| 297 |
+
index = trends_frames_br[industry + '-BR'].index
|
| 298 |
+
trends_frames[industry][c] = pd.DataFrame(columns=trends_frames_br[industry+'-BR'].columns,
|
| 299 |
+
index=index)
|
| 300 |
+
if 'CL' in countries_in_industry:
|
| 301 |
+
if industry == 'Real Estate Management & Development':
|
| 302 |
+
for col_cl in trends_frames_cl['Real Estate-CL'].columns:
|
| 303 |
+
if col_cl in keywords_dict[industry]['CL'].values:
|
| 304 |
+
trends_frames[industry]['CL'][col_cl] = trends_frames_cl['Real Estate-CL'][col_cl].dropna()
|
| 305 |
+
else:
|
| 306 |
+
for col_cl in trends_frames_cl[industry+'-CL'].columns:
|
| 307 |
+
if col_cl in keywords_dict[industry]['CL'].values:
|
| 308 |
+
trends_frames[industry]['CL'][col_cl] = trends_frames_cl[industry+'-CL'][col_cl].dropna()
|
| 309 |
+
if 'BR' in countries_in_industry:
|
| 310 |
+
if industry == 'Real Estate Management & Development':
|
| 311 |
+
for col_br in trends_frames_br['Real Estate-BR'].columns:
|
| 312 |
+
if col_br in keywords_dict[industry]['BR'].values:
|
| 313 |
+
trends_frames[industry]['BR'][col_br] = trends_frames_br['Real Estate-BR'][col_br].dropna()
|
| 314 |
+
else:
|
| 315 |
+
for col_br in trends_frames_br[industry+'-BR'].columns:
|
| 316 |
+
if col_br in keywords_dict[industry]['BR'].values:
|
| 317 |
+
trends_frames[industry]['BR'][col_br] = trends_frames_br[industry+'-BR'][col_br].dropna()
|
| 318 |
+
deseason = True
|
| 319 |
+
n_words = 5
|
| 320 |
+
for industry in keywords_dict.keys():
|
| 321 |
+
if not industry == 'Restaurantes':
|
| 322 |
+
countries_in_industry = keywords_dict[industry].columns
|
| 323 |
+
for c in countries_in_industry:
|
| 324 |
+
trends_frames[industry][c] = trends_frames[industry][c].loc[:, trends_frames[industry][c].columns.notnull()]
|
| 325 |
+
|
| 326 |
+
summary = pd.DataFrame()
|
| 327 |
+
fig1 = make_subplots(rows=2, cols=1,
|
| 328 |
+
subplot_titles=['Cambio Semanal', 'Cambio 1 Mes', 'Cambio 3 Meses', 'Cambio YTD'],
|
| 329 |
+
horizontal_spacing=0.6, )
|
| 330 |
+
fig2 = make_subplots(rows=2, cols=1,
|
| 331 |
+
subplot_titles=['Cambio Semanal', 'Cambio 1 Mes', 'Cambio 3 Meses', 'Cambio YTD'],
|
| 332 |
+
horizontal_spacing=0.6)
|
| 333 |
+
for industry, dict_ in trends_frames.items():
|
| 334 |
+
for country, df_ in dict_.items():
|
| 335 |
+
if deseason:
|
| 336 |
+
df_ = pd.DataFrame({col: df_[col] -
|
| 337 |
+
seasonal_decompose(df_[col], period=8).seasonal
|
| 338 |
+
for col in df_.columns})
|
| 339 |
+
summary[f'{industry}-{country}'] = df_.mean(1)
|
| 340 |
+
summary = (summary - summary.mean()) / summary.std()
|
| 341 |
+
|
| 342 |
+
delta_w = summary.diff(1).iloc[-1].sort_values(ascending=True)
|
| 343 |
+
delta_m = summary.diff(4).iloc[-1].sort_values(ascending=True)
|
| 344 |
+
delta_3m = summary.diff(12).iloc[-1].sort_values(ascending=True)
|
| 345 |
+
delta_ytd = summary.resample('Y').last().diff().iloc[-1].sort_values(ascending=True)
|
| 346 |
+
|
| 347 |
+
fig1.add_trace(go.Bar(x=delta_w.array, y=delta_w.index, orientation='h', marker_color=colors2[2],
|
| 348 |
+
showlegend=False), row=1, col=1)
|
| 349 |
+
|
| 350 |
+
fig2.add_trace(go.Bar(x=delta_m.array, y=delta_m.index, orientation='h', marker_color=colors2[2],
|
| 351 |
+
showlegend=False), row=1, col=1)
|
| 352 |
+
|
| 353 |
+
fig1.add_trace(go.Bar(x=delta_3m.array, y=delta_3m.index, orientation='h', marker_color=colors2[2],
|
| 354 |
+
showlegend=False), row=2, col=1)
|
| 355 |
+
|
| 356 |
+
fig2.add_trace(go.Bar(x=delta_ytd.array, y=delta_ytd.index, orientation='h', marker_color=colors2[2],
|
| 357 |
+
showlegend=False), row=2, col=1)
|
| 358 |
+
|
| 359 |
+
fig1.update_layout(title_text='Cambios en las Búsquedas', margin_b=0, margin_t=50, margin_r=0, margin_l=0)
|
| 360 |
+
fig2.update_layout(margin_b=0, margin_t=50, margin_r=0, margin_l=0)
|
| 361 |
+
col1.plotly_chart(fig1, use_container_width=True)
|
| 362 |
+
col2.plotly_chart(fig2, use_container_width=True)
|
| 363 |
+
|
| 364 |
+
for industry in trends_frames:
|
| 365 |
+
for i, (country, data) in enumerate(trends_frames[industry].items()):
|
| 366 |
+
if countries_dict[country] in select_countries:
|
| 367 |
+
|
| 368 |
+
fig_indices1 = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}],
|
| 369 |
+
[{"secondary_y": False}]],
|
| 370 |
+
subplot_titles=['GT (zscore) vs Spread Histórico',
|
| 371 |
+
'Variación YoY GT Histórico'],
|
| 372 |
+
horizontal_spacing=0.)
|
| 373 |
+
fig_indices2 = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}],
|
| 374 |
+
[{"secondary_y": False}]],
|
| 375 |
+
subplot_titles=['GT (zscore) vs Spread Último Año',
|
| 376 |
+
'Variación YoY GT Último año'],
|
| 377 |
+
horizontal_spacing=0.3)
|
| 378 |
+
|
| 379 |
+
aux_df = summary[f'{industry}-{country}']
|
| 380 |
+
aux_df.index.name = ''
|
| 381 |
+
mm_year = aux_df.rolling(52).mean()
|
| 382 |
+
mm_half = aux_df.rolling(26).mean()
|
| 383 |
+
mm_quarter = aux_df.rolling(13).mean()
|
| 384 |
+
mm_month = aux_df.rolling(4).mean()
|
| 385 |
+
mm = pd.concat([mm_year, mm_half, mm_quarter, mm_month], axis=1)
|
| 386 |
+
mm.columns = ['1Y', '6M', '3M', '1M']
|
| 387 |
+
if deseason:
|
| 388 |
+
p = '3M'
|
| 389 |
+
else:
|
| 390 |
+
p = '1Y'
|
| 391 |
+
|
| 392 |
+
fig_indices1.add_trace(go.Scatter(x=mm[p].index, y=mm[p].array, line=dict(color=colors2[0]),
|
| 393 |
+
showlegend=True, name=f'{p} MM GT Index'),
|
| 394 |
+
secondary_y=False, row=1, col=1)
|
| 395 |
+
|
| 396 |
+
fig_indices1.update_layout(title_text=f'{industry} - {country}')
|
| 397 |
+
fig_indices2.add_trace(
|
| 398 |
+
go.Scatter(x=mm[p].iloc[-52:].index, y=mm[p].iloc[-52:].array, line=dict(color=colors2[0]),
|
| 399 |
+
showlegend=False, name=f'{p} MM GT Index'),
|
| 400 |
+
secondary_y=False, row=1, col=1)
|
| 401 |
+
|
| 402 |
+
mm_4w = data.mean(1).rolling(4).mean()
|
| 403 |
+
yoy = mm_4w.pct_change(52)
|
| 404 |
+
aux2 = pd.concat([yoy], axis=1)
|
| 405 |
+
aux2.columns = ['YoY']
|
| 406 |
+
aux2.index.name = ''
|
| 407 |
+
|
| 408 |
+
fig_indices1.add_trace(go.Bar(x=aux2.dropna().index, y=aux2.dropna()['YoY'],
|
| 409 |
+
marker_color=colors2[1], showlegend=False), row=2, col=1)
|
| 410 |
+
fig_indices2.add_trace(go.Bar(x=aux2.dropna().iloc[-52:].index, y=aux2.dropna()['YoY'].iloc[-52:].array,
|
| 411 |
+
marker_color=colors2[1], showlegend=False), row=2, col=1)
|
| 412 |
+
|
| 413 |
+
if country == 'US' and industry == 'Pesca':
|
| 414 |
+
country_ = 'Chile'
|
| 415 |
+
else:
|
| 416 |
+
country_ = countries_dict[country]
|
| 417 |
+
|
| 418 |
+
spread_mw = (mw_index[country_][industry].rolling(52).apply(lambda x: (1 + x).prod()) -
|
| 419 |
+
country_index[country_]['MW'].rolling(52).apply(lambda x: (1 + x).prod()))
|
| 420 |
+
spread_ew = (ew_index[country_][industry].rolling(52).apply(lambda x: (1 + x).prod()) -
|
| 421 |
+
country_index[country_]['EW'].rolling(52).apply(lambda x: (1 + x).prod()))
|
| 422 |
+
|
| 423 |
+
spread = pd.DataFrame({'EW': spread_ew, 'MW': spread_mw})
|
| 424 |
+
|
| 425 |
+
fig_indices1.add_trace(go.Scatter(x=spread['MW'].dropna().index, y=spread['MW'].dropna().array,
|
| 426 |
+
name='Spread MW', line=dict(color=colors2[3])),
|
| 427 |
+
secondary_y=True, row=1, col=1)
|
| 428 |
+
|
| 429 |
+
fig_indices2.add_trace(
|
| 430 |
+
go.Scatter(x=spread['MW'].iloc[-260:].dropna().index, y=spread['MW'].iloc[-260:].dropna().array,
|
| 431 |
+
name='Spread MW', line=dict(color=colors2[3])),
|
| 432 |
+
secondary_y=True, row=1, col=1)
|
| 433 |
+
|
| 434 |
+
fig_indices1.update_xaxes(showticklabels=False)
|
| 435 |
+
fig_indices2.update_xaxes(showticklabels=False)
|
| 436 |
+
fig_indices1.layout.update(xaxis_rangeslider_visible=False, margin_b=20,
|
| 437 |
+
margin_r=20, margin_l=20,
|
| 438 |
+
legend=dict(orientation="h",
|
| 439 |
+
yanchor="top",
|
| 440 |
+
y=0.6,
|
| 441 |
+
xanchor="right",
|
| 442 |
+
x=1))
|
| 443 |
+
fig_indices2.layout.update(xaxis_rangeslider_visible=False,
|
| 444 |
+
margin_b=20,
|
| 445 |
+
margin_r=20, margin_l=20,
|
| 446 |
+
legend=dict(orientation="h",
|
| 447 |
+
yanchor="top",
|
| 448 |
+
y=0.6,
|
| 449 |
+
xanchor="right",
|
| 450 |
+
x=1))
|
| 451 |
+
fig_indices1.update_xaxes(showticklabels=True, row=2,
|
| 452 |
+
col=1)
|
| 453 |
+
fig_indices2.update_xaxes(showticklabels=True, row=2,
|
| 454 |
+
col=1)
|
| 455 |
+
|
| 456 |
+
fig_indices1.update_yaxes(tickformat=',.0%', row=2, col=1)
|
| 457 |
+
fig_indices2.update_yaxes(tickformat=',.0%', row=2, col=1)
|
| 458 |
+
|
| 459 |
+
if deseason:
|
| 460 |
+
df1 = pd.DataFrame({col: data[col] -
|
| 461 |
+
seasonal_decompose(data[col]).seasonal
|
| 462 |
+
for col in data.columns})
|
| 463 |
+
else:
|
| 464 |
+
df1 = data
|
| 465 |
+
|
| 466 |
+
# Top word's table plot
|
| 467 |
+
last_week = df1.iloc[-1].sort_values(ascending=False)[:n_words] / 100
|
| 468 |
+
all_time = df1.mean().sort_values(ascending=False)[:n_words] / 100
|
| 469 |
+
|
| 470 |
+
fig_W = make_subplots(subplot_titles=['Top Words en ' + f'{industry} - {country}'])
|
| 471 |
+
|
| 472 |
+
table = pd.concat([pd.Series(last_week.index),
|
| 473 |
+
pd.Series(all_time.index)], axis=1)
|
| 474 |
+
table.columns = ['Top 1W', 'Top 5Y']
|
| 475 |
+
fig_W.add_trace(go.Table(header=dict(values=table.columns),
|
| 476 |
+
cells=dict(values=[table['Top 1W'].values, table['Top 5Y'].values])))
|
| 477 |
+
fig_W.update_layout(margin_b=0, margin_t=50,
|
| 478 |
+
margin_r=0, margin_l=0,
|
| 479 |
+
height=200)
|
| 480 |
+
fig_indices1.update_layout(margin_b=0, margin_t=50,
|
| 481 |
+
margin_r=0, margin_l=0,
|
| 482 |
+
height=600)
|
| 483 |
+
fig_indices2.update_layout(margin_b=0, margin_t=50,
|
| 484 |
+
margin_r=0, margin_l=0,
|
| 485 |
+
height=600)
|
| 486 |
+
col1.plotly_chart(fig_indices1, use_container_width=True)
|
| 487 |
+
col2.plotly_chart(fig_indices2, use_container_width=True)
|
| 488 |
+
|
| 489 |
+
fig_W.update_layout(margin_b=0, margin_t=30, margin_r=10, margin_l=0)
|
| 490 |
+
st.plotly_chart(fig_W, use_container_width=True)
|
apps/Home.py
CHANGED
|
@@ -1,3 +1,331 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
from datetime import date
|
| 3 |
+
from plotly import graph_objs as go
|
| 4 |
+
import pybase64 as base64
|
| 5 |
+
import numpy as np
|
| 6 |
+
import investpy
|
| 7 |
+
import streamlit as st
|
| 8 |
+
import datetime as dt
|
| 9 |
+
import io
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def get_table_excel_link(df, selected_stocks):
|
| 13 |
+
towrite = io.BytesIO()
|
| 14 |
+
downloaded_file = df.to_excel(towrite, encoding='utf-8', index=False,
|
| 15 |
+
header=True)
|
| 16 |
+
towrite.seek(0) # reset pointer
|
| 17 |
+
file_name = 'Data'+ selected_stocks + '.xlsx'
|
| 18 |
+
style = 'style="color:black;text-decoration: none; font-size:18px;"'
|
| 19 |
+
name_mark = "Descargar " + selected_stocks + ".xlsx"
|
| 20 |
+
b64 = base64.b64encode(towrite.read()).decode() # some strings
|
| 21 |
+
linko= f'<center><a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" '+style+'download="'+file_name+'"><button>'+name_mark+'</button></a></center>'
|
| 22 |
+
return linko
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
@st.cache
|
| 26 |
+
def tabla_commodity(stocks, TODAY):
|
| 27 |
+
tabla = pd.DataFrame()
|
| 28 |
+
year_ago = date.today() - dt.timedelta(days=365)
|
| 29 |
+
year_ago = year_ago.strftime("%d/%m/%Y")
|
| 30 |
+
for stock in stocks:
|
| 31 |
+
precios = investpy.commodities.get_commodity_historical_data(
|
| 32 |
+
commodity=stock,
|
| 33 |
+
from_date=year_ago,
|
| 34 |
+
to_date=TODAY)
|
| 35 |
+
precios = precios["Close"]
|
| 36 |
+
last_price = precios.iloc[-1]
|
| 37 |
+
oned = precios.iloc[-2]
|
| 38 |
+
onew = precios.iloc[-7]
|
| 39 |
+
onem = precios.iloc[-30]
|
| 40 |
+
oney = precios.iloc[0]
|
| 41 |
+
return1m = str(round((last_price/onem-1)*100, 2))+"%"
|
| 42 |
+
return1d = str(round((last_price/oned-1)*100, 2))+"%"
|
| 43 |
+
return1w = str(round((last_price/onew-1)*100, 2))+"%"
|
| 44 |
+
return1y = str(round((last_price/oney-1)*100, 2))+"%"
|
| 45 |
+
tabla = tabla.append([[return1d, return1w, return1m, return1y]])
|
| 46 |
+
tabla.columns = ["1d", "1w", "1m", "1y"]
|
| 47 |
+
tabla.index = stocks
|
| 48 |
+
return tabla
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
@st.cache
|
| 52 |
+
def tabla_indices(index, countries, TODAY):
|
| 53 |
+
tabla = pd.DataFrame()
|
| 54 |
+
year_ago = date.today() - dt.timedelta(days=365)
|
| 55 |
+
year_ago = year_ago.strftime("%d/%m/%Y")
|
| 56 |
+
for i in range(len(index)):
|
| 57 |
+
precios = investpy.get_index_historical_data(index=index[i],
|
| 58 |
+
country=countries[i],
|
| 59 |
+
from_date=year_ago,
|
| 60 |
+
to_date=TODAY)
|
| 61 |
+
precios = precios["Close"]
|
| 62 |
+
last_price = precios.iloc[-1]
|
| 63 |
+
oned = precios.iloc[-2]
|
| 64 |
+
onew = precios.iloc[-7]
|
| 65 |
+
onem = precios.iloc[-30]
|
| 66 |
+
oney = precios.iloc[0]
|
| 67 |
+
return1m = str(round((last_price/onem-1)*100, 2))+"%"
|
| 68 |
+
return1d = str(round((last_price/oned-1)*100, 2))+"%"
|
| 69 |
+
return1w = str(round((last_price/onew-1)*100, 2))+"%"
|
| 70 |
+
return1y = str(round((last_price/oney-1)*100, 2))+"%"
|
| 71 |
+
tabla = tabla.append([[return1d, return1w, return1m, return1y]])
|
| 72 |
+
tabla.columns = ["1d", "1w", "1m", "1y"]
|
| 73 |
+
tabla.index = index
|
| 74 |
+
return tabla
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
@st.cache
|
| 78 |
+
def tabla_bonos(stocks, TODAY):
|
| 79 |
+
tabla = pd.DataFrame()
|
| 80 |
+
year_ago = date.today() - dt.timedelta(days=365)
|
| 81 |
+
year_ago = year_ago.strftime("%d/%m/%Y")
|
| 82 |
+
for stock in stocks:
|
| 83 |
+
|
| 84 |
+
precios = investpy.get_bond_historical_data(bond=stock,
|
| 85 |
+
from_date=year_ago,
|
| 86 |
+
to_date=TODAY)
|
| 87 |
+
precios = precios["Close"]
|
| 88 |
+
last_price = precios.iloc[-1]
|
| 89 |
+
oned = precios.iloc[-2]
|
| 90 |
+
onew = precios.iloc[-7]
|
| 91 |
+
onem = precios.iloc[-30]
|
| 92 |
+
oney = precios.iloc[0]
|
| 93 |
+
return1m = str(round((last_price-onem)*100, 2))+"%"
|
| 94 |
+
return1d = str(round((last_price -oned)*100, 2))+"%"
|
| 95 |
+
return1w = str(round((last_price -onew)*100, 2))+"%"
|
| 96 |
+
return1y = str(round((last_price - oney)*100, 2))+"%"
|
| 97 |
+
tabla = tabla.append([[return1d, return1w, return1m, return1y]])
|
| 98 |
+
tabla.columns = ["1d", "1w", "1m", "1y"]
|
| 99 |
+
tabla.index = stocks
|
| 100 |
+
return tabla
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def highlight_max(s):
|
| 104 |
+
if s.dtype == np.object:
|
| 105 |
+
is_neg = [False for _ in range(s.shape[0])]
|
| 106 |
+
else:
|
| 107 |
+
is_neg = s < 0
|
| 108 |
+
return ['color: red;' if cell else 'color:black' for cell in is_neg]
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def button_style():
|
| 112 |
+
style_button = """
|
| 113 |
+
<style>
|
| 114 |
+
button {
|
| 115 |
+
display: inline-block;
|
| 116 |
+
background-color: #e8e8e8;
|
| 117 |
+
border-radius: 15px;
|
| 118 |
+
border: 4px #cccccc;
|
| 119 |
+
color: #4a4a4a;
|
| 120 |
+
text-align: center;
|
| 121 |
+
font-size: 12px;
|
| 122 |
+
padding: 2px;
|
| 123 |
+
width: 250px;
|
| 124 |
+
transition: all 0.5s;
|
| 125 |
+
cursor: pointer;
|
| 126 |
+
margin: 5px;
|
| 127 |
+
}
|
| 128 |
+
button span {
|
| 129 |
+
cursor: pointer;
|
| 130 |
+
display: inline-block;
|
| 131 |
+
position: relative;
|
| 132 |
+
transition: 0.5s;
|
| 133 |
+
}
|
| 134 |
+
button span:after {
|
| 135 |
+
content: '\00bb';
|
| 136 |
+
position: absolute;
|
| 137 |
+
opacity: 0;
|
| 138 |
+
top: 0;
|
| 139 |
+
right: -20px;
|
| 140 |
+
transition: 0.5s;
|
| 141 |
+
}
|
| 142 |
+
button:hover {
|
| 143 |
+
background-color: #bb1114;
|
| 144 |
+
color:#e8e8e8;
|
| 145 |
+
}
|
| 146 |
+
button:hover span {
|
| 147 |
+
padding-right: 25px;
|
| 148 |
+
}
|
| 149 |
+
button:hover span:after {
|
| 150 |
+
opacity: 1;
|
| 151 |
+
right: 0;
|
| 152 |
+
}
|
| 153 |
+
.stMarkdown{
|
| 154 |
+
margin-bottom:0px;}
|
| 155 |
+
</style>
|
| 156 |
+
"""
|
| 157 |
+
st.markdown(style_button, unsafe_allow_html=True)
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def style_table():
|
| 161 |
+
# tr:hover {background-color: #E8E8E8;
|
| 162 |
+
# color:#BB1114;}
|
| 163 |
+
style_table = """
|
| 164 |
+
<style>
|
| 165 |
+
tr { line-height: 5px; }
|
| 166 |
+
thead {
|
| 167 |
+
background-color:#BB1114 ;
|
| 168 |
+
color: #E8E8E8;
|
| 169 |
+
}
|
| 170 |
+
tbody tr:nth-child(odd) {
|
| 171 |
+
background-color: #fff;
|
| 172 |
+
}
|
| 173 |
+
tbody tr:nth-child(even) {
|
| 174 |
+
background-color: #eee;
|
| 175 |
+
}
|
| 176 |
+
.css-1rcck9u{
|
| 177 |
+
padding:0.25rem;}
|
| 178 |
+
tbody tr:nth-child(odd)
|
| 179 |
+
stTable {
|
| 180 |
+
border-collapse: collapse;
|
| 181 |
+
background-color:red;
|
| 182 |
+
margin: 25px 0;
|
| 183 |
+
font-size: 0.9em;
|
| 184 |
+
min-width: 400px;
|
| 185 |
+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
| 186 |
+
}
|
| 187 |
+
table{
|
| 188 |
+
margin-top:0px;
|
| 189 |
+
font-size:9px;
|
| 190 |
+
padding:0px;
|
| 191 |
+
height:200px;}
|
| 192 |
+
.st-cc, .st-cb{
|
| 193 |
+
padding-top:5px;
|
| 194 |
+
padding-bottom:5px;}
|
| 195 |
+
h3, h1, h2, .svg-container {
|
| 196 |
+
animation-duration: 3s;
|
| 197 |
+
animation-name: slidein;
|
| 198 |
+
}
|
| 199 |
+
@keyframes slidein {
|
| 200 |
+
from {
|
| 201 |
+
margin-left: 100%;
|
| 202 |
+
width: 300%
|
| 203 |
+
}
|
| 204 |
+
to {
|
| 205 |
+
margin-left: 0%;
|
| 206 |
+
width: 100%;
|
| 207 |
+
}
|
| 208 |
+
}
|
| 209 |
+
</style>
|
| 210 |
+
"""
|
| 211 |
+
st.markdown(style_table, unsafe_allow_html=True)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def seleccionar_fecha(fecha_select):
|
| 215 |
+
if fecha_select == "1 week":
|
| 216 |
+
fec_in = date.today() - dt.timedelta(days=7)
|
| 217 |
+
elif fecha_select == "1 month":
|
| 218 |
+
fec_in = date.today() - dt.timedelta(days=30)
|
| 219 |
+
elif fecha_select == "3 month":
|
| 220 |
+
fec_in = date.today() - dt.timedelta(days=90)
|
| 221 |
+
elif fecha_select == "6 month":
|
| 222 |
+
fec_in = date.today() - dt.timedelta(days=180)
|
| 223 |
+
elif fecha_select == "1 year":
|
| 224 |
+
fec_in = date.today() - dt.timedelta(days=365)
|
| 225 |
+
elif fecha_select == "5 year":
|
| 226 |
+
fec_in = date.today() - dt.timedelta(days=365*5)
|
| 227 |
+
fec_in = fec_in.strftime("%d/%m/%Y")
|
| 228 |
+
return fec_in
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def stock_price():
|
| 232 |
+
style_table()
|
| 233 |
+
button_style()
|
| 234 |
+
TODAY = date.today().strftime("%d/%m/%Y")
|
| 235 |
+
YDAY = date.today() - dt.timedelta(days=1)
|
| 236 |
+
YDAY = YDAY.strftime("%d/%m/%Y")
|
| 237 |
+
commodity = ["Copper", "Silver", "Gold", "Platinum", 'Brent Oil',
|
| 238 |
+
'Heating Oil']
|
| 239 |
+
# bonos = ["Brazil 10Y", "Mexico 10Y" , "Chile 10Y", "Colombia 10Y"
|
| 240 |
+
# , "Peru 10Y"]
|
| 241 |
+
bonds10y = ["Brazil 10Y", "Mexico 10Y", "Chile 10Y", "Colombia 10Y",
|
| 242 |
+
"Peru 10Y", "China 10Y"]
|
| 243 |
+
index = ["S&P CLX IPSA", "S&P Merval", "Bovespa", "S&P 500"]
|
| 244 |
+
countries = ["chile", "argentina", "brazil", "united states"]
|
| 245 |
+
col1, col2, col3 = st.beta_columns(3)
|
| 246 |
+
cols = st.beta_columns((3, 2, 3, 2, 3, 2))
|
| 247 |
+
col1.markdown('<center><h1 style="font-size:22px;">Principales bonos 10Y</h1><center>', unsafe_allow_html=True)
|
| 248 |
+
col2.markdown('<center><h1 style="font-size:22px;">Principales commodities</h1><center>', unsafe_allow_html=True)
|
| 249 |
+
col3.markdown('<center><h1 style="font-size:22px;">Principales indices</h1><center>', unsafe_allow_html=True)
|
| 250 |
+
selected_com = cols[2].selectbox(" ", commodity)
|
| 251 |
+
selected_index = cols[4].selectbox(" ", index)
|
| 252 |
+
selected_bonds = cols[0].selectbox(" ", bonds10y)
|
| 253 |
+
fecha_select = cols[3].selectbox(" ", ["1 year", "6 month", "3 month",
|
| 254 |
+
"1 month", "1 week"])
|
| 255 |
+
fecha_select2 = cols[5].selectbox(" ", ["1 year", "6 month", "3 month",
|
| 256 |
+
"1 month", "1 week"])
|
| 257 |
+
fecha_select3 = cols[1].selectbox(" ", ["1 year", "6 month", "3 month",
|
| 258 |
+
"1 month", "1 week"])
|
| 259 |
+
# fecha_select =cols[2].button("hola")
|
| 260 |
+
fec_in = seleccionar_fecha(fecha_select)
|
| 261 |
+
fec_in2 = seleccionar_fecha(fecha_select2)
|
| 262 |
+
fec_in3 = seleccionar_fecha(fecha_select3)
|
| 263 |
+
selected_country = countries[index.index(selected_index)]
|
| 264 |
+
data_bonds = investpy.get_bond_historical_data(bond=selected_bonds,
|
| 265 |
+
from_date=fec_in3,
|
| 266 |
+
to_date=TODAY)
|
| 267 |
+
data_com = investpy.commodities.get_commodity_historical_data(
|
| 268 |
+
commodity=selected_com,
|
| 269 |
+
from_date=fec_in,
|
| 270 |
+
to_date=TODAY)
|
| 271 |
+
data_index = investpy.get_index_historical_data(index=selected_index,
|
| 272 |
+
country=selected_country,
|
| 273 |
+
from_date=fec_in2,
|
| 274 |
+
to_date=TODAY)
|
| 275 |
+
|
| 276 |
+
def plot_raw_data(col, data, color, prefijo):
|
| 277 |
+
fig = go.Figure()
|
| 278 |
+
close_ = go.Scatter(x=data.index, y=data['Close'], name="stock_close",
|
| 279 |
+
line=dict(color=color), fill='tonexty')
|
| 280 |
+
fig.add_trace(close_)
|
| 281 |
+
fig.layout.update(title_text="", xaxis_rangeslider_visible=True,
|
| 282 |
+
width=300, height=200, margin_b=0, margin_t=0,
|
| 283 |
+
margin_r=0, margin_l=0)
|
| 284 |
+
fig.update_yaxes(range=[min(data['Close'])/1.05,
|
| 285 |
+
max(data['Close'])*1.05], tickprefix=prefijo)
|
| 286 |
+
col.plotly_chart(fig)
|
| 287 |
+
plot_raw_data(cols[0], data_bonds, 'seagreen', "")
|
| 288 |
+
plot_raw_data(cols[2], data_com, 'midnightblue', "$")
|
| 289 |
+
plot_raw_data(cols[4], data_index, 'dimgrey', "$")
|
| 290 |
+
col1, col2, col3 = st.beta_columns(3)
|
| 291 |
+
cols = st.beta_columns((3, 2, 3, 2, 3, 2))
|
| 292 |
+
last_price = data_bonds.iloc[-1]["Close"]
|
| 293 |
+
first_price = data_bonds.iloc[0]["Close"]
|
| 294 |
+
returns = round((last_price/first_price-1)*100, 2)
|
| 295 |
+
cols[0].markdown('<h4 style="font-size:12px; padding-left:15px; margin-bottom:0px;">'+"Precio"+"</h4>", unsafe_allow_html=True)
|
| 296 |
+
cols[0].markdown('<p style="font-size:25px; padding-left:30px;">'+"{:,}".format(last_price)+"%</p>", unsafe_allow_html=True)
|
| 297 |
+
if returns > 0:
|
| 298 |
+
cols[1].markdown('<p style="font-size:20px; padding-top:22px; color:green;">▲ '+str(returns)+" %</p>", unsafe_allow_html=True)
|
| 299 |
+
else:
|
| 300 |
+
cols[1].markdown('<p style="font-size:20px; padding-top:22px; color:red;">▼ '+str(returns)+" %</p>", unsafe_allow_html=True)
|
| 301 |
+
last_price2 = data_com.iloc[-1]["Close"]
|
| 302 |
+
first_price2 = data_com.iloc[0]["Close"]
|
| 303 |
+
returns2 = round((last_price2/first_price2-1)*100, 2)
|
| 304 |
+
cols[2].markdown('<h4 style="font-size:12px; padding-left:15px; margin-bottom:0px;">'+"Precio"+"</h4>", unsafe_allow_html=True)
|
| 305 |
+
cols[2].markdown('<p style="font-size:25px; padding-left:30px;">$'+"{:,}".format(last_price2)+"</p>", unsafe_allow_html=True)
|
| 306 |
+
if returns2 > 0:
|
| 307 |
+
cols[3].markdown('<p style="font-size:20px; padding-top:22px; color:green;">▲ '+str(returns2)+" %</p>", unsafe_allow_html=True)
|
| 308 |
+
else:
|
| 309 |
+
cols[3].markdown('<p style="font-size:20px; padding-top:22px; color:red;">▼ '+str(returns2)+" %</p>", unsafe_allow_html=True)
|
| 310 |
+
last_price3 = data_index.iloc[-1]["Close"]
|
| 311 |
+
first_price3 = data_index.iloc[0]["Close"]
|
| 312 |
+
returns3 = round((last_price3/first_price3-1)*100, 2)
|
| 313 |
+
cols[4].markdown('<h4 style="font-size:12px; padding-left:15px; margin-bottom:0px;">'+"Precio"+"</h4>", unsafe_allow_html=True)
|
| 314 |
+
cols[4].markdown('<p style="font-size:25px; padding-left:30px;">$'+"{:,}".format(last_price3)+"</p>", unsafe_allow_html=True)
|
| 315 |
+
if returns3 > 0:
|
| 316 |
+
cols[5].markdown('<p style="font-size:20px; padding-top:22px; color:green;">▲ '+str(returns3)+" %</p>", unsafe_allow_html=True)
|
| 317 |
+
else:
|
| 318 |
+
cols[5].markdown('<p style="font-size:20px; padding-top:22px; color:red;">▼ '+str(returns3)+" %</p>", unsafe_allow_html=True)
|
| 319 |
+
col1, col2, col3 = st.beta_columns(3)
|
| 320 |
+
col1.table(tabla_bonos(bonds10y, TODAY))
|
| 321 |
+
col2.table(tabla_commodity(commodity, TODAY))
|
| 322 |
+
col3.table(tabla_indices(index, countries, TODAY))
|
| 323 |
+
|
| 324 |
+
col1, col2, col3 = st.beta_columns(3)
|
| 325 |
+
col2.markdown(get_table_excel_link(data_com, selected_com),
|
| 326 |
+
unsafe_allow_html=True)
|
| 327 |
+
col3.markdown(get_table_excel_link(data_index, selected_index),
|
| 328 |
+
unsafe_allow_html=True)
|
| 329 |
+
col1.markdown(get_table_excel_link(data_bonds, selected_bonds),
|
| 330 |
+
unsafe_allow_html=True)
|
| 331 |
+
get_table_excel_link
|
apps/Mom_industrias.py
CHANGED
|
@@ -1,3 +1,702 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
import os
|
| 3 |
+
from plotly.subplots import make_subplots
|
| 4 |
+
import plotly.graph_objects as go
|
| 5 |
+
from datetime import datetime, timedelta, date
|
| 6 |
+
import streamlit as st
|
| 7 |
+
import sys
|
| 8 |
+
from math import ceil
|
| 9 |
+
from modules import tables
|
| 10 |
+
import io
|
| 11 |
+
import boto3
|
| 12 |
+
from Data.credentials import credentials_s3 as creds3
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def save_s3(key, secret_key, bucket, df, path):
|
| 19 |
+
with io.BytesIO() as output:
|
| 20 |
+
with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
|
| 21 |
+
df.to_excel(writer, 'sheet_name')
|
| 22 |
+
data = output.getvalue()
|
| 23 |
+
s3 = boto3.resource('s3', aws_access_key_id=key,
|
| 24 |
+
aws_secret_access_key=secret_key)
|
| 25 |
+
s3.Bucket(bucket).put_object(Key=path, Body=data)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
@st.experimental_memo
|
| 29 |
+
def read_excel_s3(key, secret_key, bucket, path):
|
| 30 |
+
s3_client = boto3.client('s3', aws_access_key_id=key,
|
| 31 |
+
aws_secret_access_key=secret_key)
|
| 32 |
+
response = s3_client.get_object(Bucket=bucket, Key=path)
|
| 33 |
+
data = response["Body"].read()
|
| 34 |
+
df = pd.read_excel(io.BytesIO(
|
| 35 |
+
data), sheet_name='sheet_name', index_col='date')
|
| 36 |
+
return df
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def sectors_lv1_dicc():
|
| 40 |
+
sectors_dicc = {}
|
| 41 |
+
company_db = pd.read_excel(
|
| 42 |
+
'Data/Company_Base_Definitivo.xlsx', sheet_name='Compilado')
|
| 43 |
+
sectors = list(company_db['LV1'].unique())
|
| 44 |
+
for sector in sectors:
|
| 45 |
+
sectors_dicc[sector] = list(set(list(company_db[company_db['LV1'] == sector]['Country'].unique()))
|
| 46 |
+
.intersection(['Argentina', 'Brazil', 'Chile', 'Colombia', 'Mexico', 'Peru']))
|
| 47 |
+
return sectors_dicc
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def colores_corporativos(colors=None):
|
| 51 |
+
|
| 52 |
+
color_dict = {'green': (55, 95, 77),
|
| 53 |
+
'light_blue': (110, 162, 201),
|
| 54 |
+
'light_gray': (135, 146, 158),
|
| 55 |
+
'dark_purple': (119, 28, 95),
|
| 56 |
+
'red': (204, 0, 51),
|
| 57 |
+
'blue': (42, 83, 113),
|
| 58 |
+
'purple': (159, 37, 127),
|
| 59 |
+
'light_green': (122, 178, 153),
|
| 60 |
+
'gray': (66, 74, 82),
|
| 61 |
+
'yellow': (195, 195, 9),}
|
| 62 |
+
|
| 63 |
+
for key in color_dict:
|
| 64 |
+
color_dict[key] = tuple(v/255 for v in color_dict[key])
|
| 65 |
+
|
| 66 |
+
if colors is None:
|
| 67 |
+
return color_dict
|
| 68 |
+
else:
|
| 69 |
+
aux = {col: color_dict[col] for col in colors}
|
| 70 |
+
return aux
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def update_data(start=str(date.today()-timedelta(int(1.5*365))), today=str(date.today())):
|
| 74 |
+
fields = ['IQ_CLOSEPRICE_ADJ', 'IQ_MARKETCAP', 'IQ_VALUE_TRADED']
|
| 75 |
+
key = creds3["S3_KEY_ID"]
|
| 76 |
+
secret_key = creds3["S3_SECRET_KEY"]
|
| 77 |
+
bucket = creds3["S3_BUCKET"]
|
| 78 |
+
path = 'Momentum.xlsx'
|
| 79 |
+
for f in fields:
|
| 80 |
+
# Cargamos de Mongo data de empresas
|
| 81 |
+
save_s3(key=key, secret_key=secret_key, bucket=bucket,
|
| 82 |
+
df=tables.EquityMaster(field=f).query(
|
| 83 |
+
start=start, end=today, rename=['asset']),
|
| 84 |
+
path=f + '.xlsx')
|
| 85 |
+
ud = pd.read_excel('Data/update_data.xlsx')
|
| 86 |
+
ud = ud[ud['View'] != 'Mom Industrias']
|
| 87 |
+
today = date.today().strftime('%d-%m-%Y')
|
| 88 |
+
ud = ud.append({"View": 'Mom Industrias',
|
| 89 |
+
"Last_Update": today}, ignore_index=True)
|
| 90 |
+
ud.to_excel('Data/update_data.xlsx', index=False)
|
| 91 |
+
|
| 92 |
+
@st.cache(suppress_st_warning=True)
|
| 93 |
+
def data_request(today, start, countries, criteria='LV1'):
|
| 94 |
+
"""
|
| 95 |
+
Hace las consultas básicas necesarias para poder visaulizar StN.
|
| 96 |
+
:param today: fecha de hoy. Este parámetro está sólo para poder usar st.cache.
|
| 97 |
+
:param start: desde cuándo se está haciendo la consulta.
|
| 98 |
+
:param countries: países que solicita el usuario
|
| 99 |
+
:param criteria: Criterio a usar en country_sector.
|
| 100 |
+
:return: data_dict, company_db, country_sector)
|
| 101 |
+
"""""
|
| 102 |
+
key = creds3["S3_KEY_ID"]
|
| 103 |
+
secret_key = creds3["S3_SECRET_KEY"]
|
| 104 |
+
bucket = creds3["S3_BUCKET"]
|
| 105 |
+
path = 'Momentum.xlsx'
|
| 106 |
+
# Cargamos mapeos
|
| 107 |
+
file = 'Data/Company_Base_Definitivo.xlsx'
|
| 108 |
+
company_db = pd.read_excel(file, sheet_name='Compilado', index_col='ID_Quant',
|
| 109 |
+
engine='openpyxl')
|
| 110 |
+
# Pequeño arreglo de meli y globant
|
| 111 |
+
company_db.loc[[7, 72], 'Country'] = 'Brazil'
|
| 112 |
+
|
| 113 |
+
data_dict = {}
|
| 114 |
+
|
| 115 |
+
paths = ['IQ_CLOSEPRICE_ADJ.xlsx',
|
| 116 |
+
'IQ_MARKETCAP.xlsx', 'IQ_VALUE_TRADED.xlsx']
|
| 117 |
+
for p in paths:
|
| 118 |
+
data_dict[p[:-5]] = read_excel_s3(key=key,
|
| 119 |
+
secret_key=secret_key, bucket=bucket, path=p)
|
| 120 |
+
|
| 121 |
+
# Vemos solo las parejas de pais-sector que existen para ahorrar parejas
|
| 122 |
+
country_sector = (company_db[['Country', criteria]].drop_duplicates().
|
| 123 |
+
sort_values(['Country', criteria]))
|
| 124 |
+
|
| 125 |
+
country_sector = country_sector.loc[country_sector['Country'].isin(
|
| 126 |
+
countries)]
|
| 127 |
+
return data_dict, company_db, country_sector
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def mm_eval(series):
|
| 131 |
+
return int(series.iloc[-1] > series.mean())
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
@st.cache(suppress_st_warning=True)
|
| 135 |
+
def country_request(country, start, end):
|
| 136 |
+
return tables.MacroMaster(country=country, instrument='INDEX').query(start=start, end=end)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
@st.cache(suppress_st_warning=True)
|
| 140 |
+
def univ_request(company_db, c):
|
| 141 |
+
return company_db.query(f"Country == '{c}'").index.astype(str)
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
@st.cache(suppress_st_warning=True)
|
| 145 |
+
def mm_sum(prices_c, p_list):
|
| 146 |
+
return sum([prices_c.rolling(p * 20).apply(mm_eval) for p in p_list])
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
@st.experimental_memo
|
| 150 |
+
def dictionaries_maker(start, countries, country_sector, criteria, company_db, data_dict):
|
| 151 |
+
rel_rets = {}
|
| 152 |
+
cs_ids = {}
|
| 153 |
+
w_hist = {}
|
| 154 |
+
bm_dict = {c: country_request(c, start, str(date.today()))
|
| 155 |
+
for c in countries}
|
| 156 |
+
|
| 157 |
+
for c in countries:
|
| 158 |
+
bm_rets = tables.MacroMaster(
|
| 159 |
+
country=c, instrument='INDEX').query(start=start)
|
| 160 |
+
rel_ret_c = {}
|
| 161 |
+
for s in country_sector.loc[country_sector['Country'] == c, criteria]:
|
| 162 |
+
univ = (company_db.query(f"Country == '{c}' and {criteria} == '{s}'")
|
| 163 |
+
.index.astype(str))
|
| 164 |
+
univ = list(set(univ & data_dict['IQ_MARKETCAP'].columns
|
| 165 |
+
& data_dict['IQ_CLOSEPRICE_ADJ'].columns))
|
| 166 |
+
w = data_dict['IQ_MARKETCAP'][univ].ffill().fillna(0)
|
| 167 |
+
w = w.div(w.sum(1), axis=0)
|
| 168 |
+
w_hist[f'{c}-{s}'] = w
|
| 169 |
+
p_ind = data_dict['IQ_CLOSEPRICE_ADJ'][univ].ffill()
|
| 170 |
+
ret_ind = (w * p_ind.pct_change()).fillna(0).sum(1)
|
| 171 |
+
rel_ret_c[s] = ret_ind - bm_rets
|
| 172 |
+
cs_ids[f'{c}-{s}'] = univ
|
| 173 |
+
|
| 174 |
+
rel_rets[c] = pd.DataFrame(rel_ret_c)
|
| 175 |
+
|
| 176 |
+
return rel_rets, cs_ids, w_hist, bm_dict
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
def signal_to_noise():
|
| 180 |
+
"""
|
| 181 |
+
Despliega un formulario de streamlit y grafica lo indicado por el usuario.
|
| 182 |
+
:return: None
|
| 183 |
+
"""
|
| 184 |
+
form_stn = st.form("StN")
|
| 185 |
+
stn_view = form_stn.selectbox('¿Cómo desea visualizar StN?:',
|
| 186 |
+
('Nivel o Cambios por País',
|
| 187 |
+
'Grafico Agregado de StN'))
|
| 188 |
+
|
| 189 |
+
if stn_view == 'Nivel o Cambios por País':
|
| 190 |
+
n = form_stn.slider('Inserte para cuántas semanas desea visualizar cambios (Con 0 se muestra el nivel StN).',
|
| 191 |
+
min_value=0, max_value=12)
|
| 192 |
+
else:
|
| 193 |
+
n = 0
|
| 194 |
+
|
| 195 |
+
# Países a visualizar
|
| 196 |
+
countries = form_stn.multiselect('País : ',
|
| 197 |
+
('Todos', 'Argentina', 'Brazil',
|
| 198 |
+
'Chile', 'Colombia', 'Mexico', 'Peru'))
|
| 199 |
+
if 'Todos' in countries:
|
| 200 |
+
countries = ['Argentina', 'Brazil',
|
| 201 |
+
'Chile', 'Colombia', 'Mexico', 'Peru']
|
| 202 |
+
|
| 203 |
+
countries_q = len(countries)
|
| 204 |
+
|
| 205 |
+
update_button = form_stn.form_submit_button("Actualizar datos")
|
| 206 |
+
if update_button:
|
| 207 |
+
update_data()
|
| 208 |
+
|
| 209 |
+
accept = form_stn.form_submit_button('Visualizar')
|
| 210 |
+
|
| 211 |
+
start = '2017'
|
| 212 |
+
criteria = 'LV1'
|
| 213 |
+
|
| 214 |
+
st.write("### Está visualizando: StN")
|
| 215 |
+
|
| 216 |
+
colors = list(colores_corporativos().values())
|
| 217 |
+
colors2 = []
|
| 218 |
+
for i in range(len(colors)):
|
| 219 |
+
colors2.append("rgb" + str(colors[i]))
|
| 220 |
+
|
| 221 |
+
if accept:
|
| 222 |
+
|
| 223 |
+
today = str(date.today())
|
| 224 |
+
# Acá cargamos los datos necesarios
|
| 225 |
+
data = data_request(today, start, countries)
|
| 226 |
+
data_dict = data[0]
|
| 227 |
+
company_db = data[1]
|
| 228 |
+
country_sector = data[2]
|
| 229 |
+
st.write('Data desde ' + start + ' hasta ' +
|
| 230 |
+
str(data_dict['IQ_CLOSEPRICE_ADJ'].index[-1].date()))
|
| 231 |
+
|
| 232 |
+
rel_rets, cs_ids, w_hist, bm_dict = dictionaries_maker(start,
|
| 233 |
+
countries,
|
| 234 |
+
country_sector,
|
| 235 |
+
criteria,
|
| 236 |
+
company_db,
|
| 237 |
+
data_dict)
|
| 238 |
+
|
| 239 |
+
stn_p = 20 * 5
|
| 240 |
+
signal_to_noise_dict = {c: df.rolling(stn_p).sum() / df.abs().rolling(stn_p).sum().abs()
|
| 241 |
+
for c, df in rel_rets.items()}
|
| 242 |
+
if stn_view == 'Nivel o Cambios por País':
|
| 243 |
+
index = list(range(len(colors2)))
|
| 244 |
+
colors2 = dict(zip(index, colors2))
|
| 245 |
+
if n == 0:
|
| 246 |
+
st.write('### Nivel de StN')
|
| 247 |
+
fig = make_subplots(rows=1, cols=1, subplot_titles=countries)
|
| 248 |
+
if countries_q == 1:
|
| 249 |
+
for i, (c, df) in enumerate(signal_to_noise_dict.items()):
|
| 250 |
+
fig.add_trace(go.Bar(x=df.iloc[-1].sort_values().array, y=df.iloc[-1].sort_values().index,
|
| 251 |
+
orientation='h', showlegend=False,
|
| 252 |
+
marker_color=colors2[3]))
|
| 253 |
+
fig.update_yaxes(visible=True, showticklabels=True)
|
| 254 |
+
fig.update_xaxes(visible=False, showticklabels=False)
|
| 255 |
+
fig.update_layout(height=800)
|
| 256 |
+
with st.container():
|
| 257 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 258 |
+
else:
|
| 259 |
+
col1, col2 = st.columns(2)
|
| 260 |
+
titles_1 = []
|
| 261 |
+
titles_2 = []
|
| 262 |
+
for k in range(countries_q):
|
| 263 |
+
if k % 2 == 0:
|
| 264 |
+
titles_1.append(countries[k])
|
| 265 |
+
else:
|
| 266 |
+
titles_2.append(countries[k])
|
| 267 |
+
|
| 268 |
+
fig1 = make_subplots(rows=1 + (countries_q > 2) + (countries_q > 4), cols=1,
|
| 269 |
+
subplot_titles=titles_1)
|
| 270 |
+
fig2 = make_subplots(rows=1 + (countries_q > 2) + (countries_q > 4), cols=1,
|
| 271 |
+
subplot_titles=titles_2)
|
| 272 |
+
|
| 273 |
+
for i, (c, df) in enumerate(signal_to_noise_dict.items()):
|
| 274 |
+
if i % 2 == 0:
|
| 275 |
+
fig1.add_trace(go.Bar(x=df.iloc[-1].sort_values().array, y=df.iloc[-1].sort_values().index,
|
| 276 |
+
orientation='h', showlegend=False,
|
| 277 |
+
marker_color=colors2[3]),
|
| 278 |
+
row=(i == 0) + 2 *
|
| 279 |
+
(i == 2) + 3 * (i == 4),
|
| 280 |
+
col=1)
|
| 281 |
+
else:
|
| 282 |
+
fig2.add_trace(go.Bar(x=df.iloc[-1].sort_values().array, y=df.iloc[-1].sort_values().index,
|
| 283 |
+
orientation='h', showlegend=False,
|
| 284 |
+
marker_color=colors2[3]),
|
| 285 |
+
row=(i == 1) + 2 *
|
| 286 |
+
(i == 3) + 3 * (i == 5),
|
| 287 |
+
col=1)
|
| 288 |
+
|
| 289 |
+
fig1.update_yaxes(visible=True, showticklabels=True)
|
| 290 |
+
fig2.update_yaxes(visible=True, showticklabels=True)
|
| 291 |
+
fig1.update_xaxes(visible=False, showticklabels=False)
|
| 292 |
+
fig2.update_xaxes(visible=False, showticklabels=False)
|
| 293 |
+
fig1.update_layout(height=800)
|
| 294 |
+
fig2.update_layout(height=800)
|
| 295 |
+
col1.plotly_chart(fig1, use_container_width=True)
|
| 296 |
+
col2.plotly_chart(fig2, use_container_width=True)
|
| 297 |
+
else:
|
| 298 |
+
fig = make_subplots(rows=1, cols=1, subplot_titles=countries)
|
| 299 |
+
if countries_q == 1:
|
| 300 |
+
for i, (c, df) in enumerate(signal_to_noise_dict.items()):
|
| 301 |
+
fig.add_trace(go.Bar(x=df.iloc[-1].sort_values().array, y=df.iloc[-1].sort_values().index,
|
| 302 |
+
orientation='h', showlegend=False,
|
| 303 |
+
marker_color=colors2[3]))
|
| 304 |
+
fig.update_yaxes(visible=True, showticklabels=True)
|
| 305 |
+
fig.update_xaxes(visible=False, showticklabels=False)
|
| 306 |
+
fig.update_layout(height=800)
|
| 307 |
+
with st.container():
|
| 308 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 309 |
+
else:
|
| 310 |
+
st.write('### Cambios en ' + str(n) + ' Semanas')
|
| 311 |
+
|
| 312 |
+
if countries_q == 1:
|
| 313 |
+
fig = make_subplots(
|
| 314 |
+
rows=1, cols=1, subplot_titles=countries)
|
| 315 |
+
for i, (c, df) in enumerate(signal_to_noise_dict.items()):
|
| 316 |
+
fig.add_trace(go.Bar(x=df.diff(5 * n).iloc[-1].sort_values().array,
|
| 317 |
+
y=df.diff(
|
| 318 |
+
5 * n).iloc[-1].sort_values().index,
|
| 319 |
+
orientation='h', showlegend=False,
|
| 320 |
+
marker_color=colors2[3]))
|
| 321 |
+
fig.update_yaxes(visible=True, showticklabels=True)
|
| 322 |
+
fig.update_xaxes(
|
| 323 |
+
visible=False, showticklabels=False)
|
| 324 |
+
fig.update_layout(height=800)
|
| 325 |
+
with st.container():
|
| 326 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 327 |
+
else:
|
| 328 |
+
col1, col2 = st.columns(2)
|
| 329 |
+
titles_1 = []
|
| 330 |
+
titles_2 = []
|
| 331 |
+
for k in range(countries_q):
|
| 332 |
+
if k % 2 == 0:
|
| 333 |
+
titles_1.append(countries[k])
|
| 334 |
+
else:
|
| 335 |
+
titles_2.append(countries[k])
|
| 336 |
+
|
| 337 |
+
fig1 = make_subplots(rows=1 + (countries_q > 2) + (countries_q > 4),
|
| 338 |
+
cols=1, subplot_titles=titles_1)
|
| 339 |
+
fig2 = make_subplots(rows=1 + (countries_q > 2) + (countries_q > 4),
|
| 340 |
+
cols=1, subplot_titles=titles_2)
|
| 341 |
+
for i, (c, df) in enumerate(signal_to_noise_dict.items()):
|
| 342 |
+
if i % 2 == 0:
|
| 343 |
+
fig1.add_trace(go.Bar(x=df.diff(5 * n).iloc[-1].sort_values().array,
|
| 344 |
+
y=df.diff(
|
| 345 |
+
5 * n).iloc[-1].sort_values().index,
|
| 346 |
+
orientation='h', showlegend=False,
|
| 347 |
+
marker_color=colors2[3]),
|
| 348 |
+
row=(i == 0) + 2 * (i == 2) + 3 * (i == 4), col=1)
|
| 349 |
+
else:
|
| 350 |
+
fig2.add_trace(go.Bar(x=df.diff(5 * n).iloc[-1].sort_values().array,
|
| 351 |
+
y=df.diff(
|
| 352 |
+
5 * n).iloc[-1].sort_values().index,
|
| 353 |
+
orientation='h', showlegend=False,
|
| 354 |
+
marker_color=colors2[3]),
|
| 355 |
+
row=(i == 1) + 2 * (i == 3) + 3 * (i == 5), col=1)
|
| 356 |
+
fig1.update_yaxes(visible=True, showticklabels=True)
|
| 357 |
+
fig2.update_yaxes(visible=True, showticklabels=True)
|
| 358 |
+
fig1.update_xaxes(visible=False, showticklabels=False)
|
| 359 |
+
fig2.update_xaxes(visible=False, showticklabels=False)
|
| 360 |
+
fig1.update_layout(height=1000, margin_b=20,
|
| 361 |
+
margin_r=20, margin_l=20)
|
| 362 |
+
fig2.update_layout(height=1000, margin_b=20,
|
| 363 |
+
margin_r=20, margin_l=20)
|
| 364 |
+
col1.plotly_chart(fig1, use_container_width=True)
|
| 365 |
+
col2.plotly_chart(fig2, use_container_width=True)
|
| 366 |
+
|
| 367 |
+
if stn_view == 'Grafico Agregado de StN':
|
| 368 |
+
mc_th = 5000
|
| 369 |
+
aux_stn = pd.concat([df.rename(columns={s: f'{c}-{s}' for s in df.columns})
|
| 370 |
+
for c, df in signal_to_noise_dict.items() if c in countries], axis=1)
|
| 371 |
+
mc_per_ind = pd.Series([data_dict['IQ_MARKETCAP'][cs_ids[cs]].rolling(60, 10).mean().iloc[-1].sum()
|
| 372 |
+
for cs in aux_stn.columns], index=aux_stn.columns)
|
| 373 |
+
|
| 374 |
+
st.markdown('### StN General ')
|
| 375 |
+
col1, col2, col3 = st.columns(3)
|
| 376 |
+
aux_stn = aux_stn.loc[:, (mc_per_ind > mc_th).values]
|
| 377 |
+
|
| 378 |
+
# Ahora creamos los dataframes para cada margen de tiempo
|
| 379 |
+
stn_general = aux_stn.iloc[-1].sort_values() # General
|
| 380 |
+
stn_1week = aux_stn.diff(5).iloc[-1].sort_values() # 1 Week Chg
|
| 381 |
+
stn_1month = aux_stn.diff(20).iloc[-1].sort_values() # 1 Month Chg
|
| 382 |
+
|
| 383 |
+
# Procedemos a graficar
|
| 384 |
+
fig1 = make_subplots(subplot_titles=['General'])
|
| 385 |
+
fig2 = make_subplots(subplot_titles=['1W Chg'])
|
| 386 |
+
fig3 = make_subplots(subplot_titles=['1M Chg'])
|
| 387 |
+
fig1.add_trace(
|
| 388 |
+
go.Bar(x=stn_general.array, y=stn_general.index,
|
| 389 |
+
orientation='h', showlegend=False,
|
| 390 |
+
marker_color=colors2[3]))
|
| 391 |
+
fig2.add_trace(
|
| 392 |
+
go.Bar(x=stn_1week.array, y=stn_1week.index, orientation='h',
|
| 393 |
+
showlegend=False,
|
| 394 |
+
marker_color=colors2[3]))
|
| 395 |
+
fig3.add_trace(
|
| 396 |
+
go.Bar(x=stn_1month.array, y=stn_1month.index, orientation='h',
|
| 397 |
+
showlegend=False,
|
| 398 |
+
marker_color=colors2[3]))
|
| 399 |
+
fig1.update_xaxes(visible=False, showticklabels=False)
|
| 400 |
+
fig2.update_xaxes(visible=False, showticklabels=False)
|
| 401 |
+
fig3.update_xaxes(visible=False, showticklabels=False)
|
| 402 |
+
|
| 403 |
+
col1.plotly_chart(fig1, use_container_width=True)
|
| 404 |
+
col2.plotly_chart(fig2, use_container_width=True)
|
| 405 |
+
col3.plotly_chart(fig3, use_container_width=True)
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
def medias_moviles():
|
| 409 |
+
"""
|
| 410 |
+
Despliega un formulario de streamlit y grafica lo indicado por el usuario.
|
| 411 |
+
:return: None
|
| 412 |
+
"""
|
| 413 |
+
sectors_dict = sectors_lv1_dicc()
|
| 414 |
+
select_sector = st.selectbox(
|
| 415 |
+
'Qué sector desea visualizar?', list(sectors_dict.keys()))
|
| 416 |
+
form_mm = st.form("MM")
|
| 417 |
+
start = form_mm.date_input(
|
| 418 |
+
'¿Desde qué fecha desea visualizar?', value=date.today() - timedelta(365))
|
| 419 |
+
start = datetime.combine(start, datetime.min.time())
|
| 420 |
+
countries = form_mm.multiselect('¿Qué país(es) desea visualizar?', [
|
| 421 |
+
'Todos'] + sectors_dict[select_sector])
|
| 422 |
+
if 'Todos' in countries:
|
| 423 |
+
countries = sectors_dict[select_sector]
|
| 424 |
+
|
| 425 |
+
update_button = form_mm.form_submit_button("Actualizar datos")
|
| 426 |
+
if update_button:
|
| 427 |
+
update_data()
|
| 428 |
+
|
| 429 |
+
accept = form_mm.form_submit_button('Visualizar')
|
| 430 |
+
|
| 431 |
+
criteria = 'LV1'
|
| 432 |
+
|
| 433 |
+
st.write("### Está visualizando: Medias Moviles")
|
| 434 |
+
|
| 435 |
+
colors = list(colores_corporativos().values())
|
| 436 |
+
colors2 = []
|
| 437 |
+
for i in range(len(colors)):
|
| 438 |
+
colors2.append("rgb" + str(colors[i]))
|
| 439 |
+
|
| 440 |
+
if accept:
|
| 441 |
+
|
| 442 |
+
if not countries:
|
| 443 |
+
countries = sectors_dict[select_sector]
|
| 444 |
+
|
| 445 |
+
today = str(date.today())
|
| 446 |
+
# Acá cargamos los datos necesarios
|
| 447 |
+
data = data_request(today, start, countries)
|
| 448 |
+
data_dict = data[0]
|
| 449 |
+
company_db = data[1]
|
| 450 |
+
country_sector = data[2]
|
| 451 |
+
|
| 452 |
+
st.write('Data desde ' + str(start.date()) + ' hasta ' +
|
| 453 |
+
str(data_dict['IQ_CLOSEPRICE_ADJ'].index[-1].date()))
|
| 454 |
+
|
| 455 |
+
rel_rets, cs_ids, w_hist, bm_dict = dictionaries_maker(start,
|
| 456 |
+
countries,
|
| 457 |
+
country_sector,
|
| 458 |
+
criteria,
|
| 459 |
+
company_db,
|
| 460 |
+
data_dict)
|
| 461 |
+
stn_p = 20 * 5
|
| 462 |
+
signal_to_noise_dict = {
|
| 463 |
+
c: df.rolling(stn_p).sum() / df.abs().rolling(stn_p).sum().abs()
|
| 464 |
+
for c, df in rel_rets.items()}
|
| 465 |
+
st.write('Sector: ' + select_sector)
|
| 466 |
+
ma_p = [20, 60, 250]
|
| 467 |
+
aux_stn = pd.concat(
|
| 468 |
+
[df.rename(columns={s: f'{c}-{s}' for s in df.columns})
|
| 469 |
+
for c, df in signal_to_noise_dict.items() if c in countries],
|
| 470 |
+
axis=1)
|
| 471 |
+
aux_rr = pd.concat(
|
| 472 |
+
[df.rename(columns={s: f'{c}-{s}' for s in df.columns})
|
| 473 |
+
for c, df in rel_rets.items() if c in countries], axis=1)
|
| 474 |
+
aux_rr = aux_rr[aux_stn.columns]
|
| 475 |
+
if len(countries) > 1:
|
| 476 |
+
col1, col2 = st.columns(2)
|
| 477 |
+
titles_1 = []
|
| 478 |
+
titles_2 = []
|
| 479 |
+
dicc_tit_1 = {}
|
| 480 |
+
dicc_tit_2 = {}
|
| 481 |
+
for i, country in enumerate(countries):
|
| 482 |
+
if i % 2 == 0:
|
| 483 |
+
title_1=str(country) + ' - ' + str(select_sector)
|
| 484 |
+
titles_1.append(title_1)
|
| 485 |
+
dicc_tit_1[title_1] = make_subplots()
|
| 486 |
+
else:
|
| 487 |
+
title_2=str(country) + ' - ' + str(select_sector)
|
| 488 |
+
titles_2.append(title_2)
|
| 489 |
+
dicc_tit_2[title_2] = make_subplots()
|
| 490 |
+
countries_q = len(countries)
|
| 491 |
+
indices = list(range(ceil(countries_q / 2)))
|
| 492 |
+
m = 0
|
| 493 |
+
for i, c in enumerate(countries):
|
| 494 |
+
df = (aux_rr[c + '-' + select_sector] + 1).cumprod() - 1
|
| 495 |
+
df_mm = pd.DataFrame(
|
| 496 |
+
{p: df.rolling(p, min_periods=1).mean() for p in ma_p})
|
| 497 |
+
df = df.to_frame()
|
| 498 |
+
df[[f'MA_{p}' for p in ma_p]] = df_mm
|
| 499 |
+
df = df.loc[df.index >= start]
|
| 500 |
+
df.rename(
|
| 501 |
+
columns={c + '-' + select_sector: 'Indice'}, inplace=True)
|
| 502 |
+
df = df - df['Indice'][0]
|
| 503 |
+
if i % 2 == 0:
|
| 504 |
+
list_plot_1 =list(dicc_tit_1.keys())
|
| 505 |
+
for k in range(len(ma_p)):
|
| 506 |
+
if k == 0:
|
| 507 |
+
dicc_tit_1[list_plot_1[i//2 + i % 2]].add_trace(
|
| 508 |
+
go.Scatter(x=df.index, y=df['Indice'],
|
| 509 |
+
line=dict(
|
| 510 |
+
color=colors2[len(ma_p) + 1]),
|
| 511 |
+
name='Indice'),
|
| 512 |
+
row=indices[m] + 1, col=1)
|
| 513 |
+
dicc_tit_1[list_plot_1[i//2 + i % 2]].add_trace(
|
| 514 |
+
go.Scatter(x=df.index,
|
| 515 |
+
y=df['MA_' + str(ma_p[k])],
|
| 516 |
+
line=dict(color=colors2[k]),
|
| 517 |
+
name='MA_' + str(ma_p[k])),
|
| 518 |
+
row=indices[m] + 1, col=1)
|
| 519 |
+
dicc_tit_1[list_plot_1[i//2 + i % 2]].update_layout(
|
| 520 |
+
height=350, width=400)
|
| 521 |
+
dicc_tit_1[list_plot_1[i//2 + i % 2]].layout.update(
|
| 522 |
+
title_text=list_plot_1[i//2 + i % 2],
|
| 523 |
+
xaxis_rangeslider_visible=False, margin_b=20,
|
| 524 |
+
margin_r=20, margin_l=20,
|
| 525 |
+
legend=dict(orientation="h",
|
| 526 |
+
yanchor="bottom",
|
| 527 |
+
y=1.0,
|
| 528 |
+
xanchor="right",
|
| 529 |
+
x=1))
|
| 530 |
+
col1.plotly_chart(dicc_tit_1[list_plot_1[i//2 + i % 2]],
|
| 531 |
+
use_container_width=True)
|
| 532 |
+
else:
|
| 533 |
+
list_plot_2 = list(dicc_tit_2.keys())
|
| 534 |
+
for k in range(len(ma_p)):
|
| 535 |
+
if k == 0:
|
| 536 |
+
dicc_tit_2[list_plot_2[i//2]].add_trace(
|
| 537 |
+
go.Scatter(x=df.index, y=df['Indice'],
|
| 538 |
+
line=dict(
|
| 539 |
+
color=colors2[len(ma_p) + 1]),
|
| 540 |
+
name='Indice'),
|
| 541 |
+
row=indices[m] + 1, col=1)
|
| 542 |
+
dicc_tit_2[list_plot_2[i//2]].add_trace(
|
| 543 |
+
go.Scatter(x=df.index,
|
| 544 |
+
y=df['MA_' + str(ma_p[k])],
|
| 545 |
+
line=dict(color=colors2[k]),
|
| 546 |
+
name='MA_' + str(ma_p[k])),
|
| 547 |
+
row=indices[m] + 1, col=1)
|
| 548 |
+
dicc_tit_2[list_plot_2[i//2]].update_layout(
|
| 549 |
+
height=350, width=400)
|
| 550 |
+
|
| 551 |
+
dicc_tit_2[list_plot_2[i//2]].layout.update(
|
| 552 |
+
title_text=list_plot_2[i//2],
|
| 553 |
+
xaxis_rangeslider_visible=False, margin_b=20,
|
| 554 |
+
margin_r=20, margin_l=20,
|
| 555 |
+
legend=dict(orientation="h",
|
| 556 |
+
yanchor="bottom",
|
| 557 |
+
y=1.0,
|
| 558 |
+
xanchor="right",
|
| 559 |
+
x=1))
|
| 560 |
+
col2.plotly_chart(dicc_tit_2[list_plot_2[i//2]],
|
| 561 |
+
use_container_width=True)
|
| 562 |
+
else:
|
| 563 |
+
country = countries[0]
|
| 564 |
+
titles = [str(country) + ' - ' + str(select_sector)]
|
| 565 |
+
fig1 = make_subplots(rows=len(titles), cols=1,
|
| 566 |
+
subplot_titles=titles)
|
| 567 |
+
df = (aux_rr[country + '-' + select_sector] + 1).cumprod() - 1
|
| 568 |
+
df_mm = pd.DataFrame(
|
| 569 |
+
{p: df.rolling(p, min_periods=1).mean() for p in ma_p})
|
| 570 |
+
df = df.to_frame()
|
| 571 |
+
df[[f'MA_{p}' for p in ma_p]] = df_mm
|
| 572 |
+
df = df.loc[df.index >= start]
|
| 573 |
+
df.rename(columns={country + '-' +
|
| 574 |
+
select_sector: 'Indice'}, inplace=True)
|
| 575 |
+
df = df - df['Indice'][0]
|
| 576 |
+
for k in range(len(ma_p)):
|
| 577 |
+
fig1.add_trace(go.Scatter(x=df.index,
|
| 578 |
+
y=df['MA_' + str(ma_p[k])],
|
| 579 |
+
line=dict(color=colors2[k]),
|
| 580 |
+
name='MA_' + str(ma_p[k]),
|
| 581 |
+
showlegend=True), row=1, col=1)
|
| 582 |
+
fig1.add_trace(go.Scatter(x=df.index, y=df['Indice'],
|
| 583 |
+
line=dict(color=colors2[len(ma_p) + 1]),
|
| 584 |
+
name='Indice',
|
| 585 |
+
showlegend=True),
|
| 586 |
+
row=1, col=1)
|
| 587 |
+
|
| 588 |
+
fig1.update_layout(height=200, width=400, margin_b=0, margin_t=0,
|
| 589 |
+
margin_r=0, margin_l=0)
|
| 590 |
+
st.plotly_chart(fig1, use_container_width=True)
|
| 591 |
+
|
| 592 |
+
|
| 593 |
+
def difusion():
|
| 594 |
+
"""
|
| 595 |
+
Despliega un formulario de streamlit y grafica lo indicado por el usuario.
|
| 596 |
+
:return: None
|
| 597 |
+
"""
|
| 598 |
+
start = '2017'
|
| 599 |
+
|
| 600 |
+
form_dif = st.form("Difusión")
|
| 601 |
+
countries = form_dif.multiselect('¿Qué países quiere visualizar?',
|
| 602 |
+
('Todos', 'Argentina', 'Brazil',
|
| 603 |
+
'Chile', 'Colombia', 'Mexico', 'Peru'))
|
| 604 |
+
if 'Todos' in countries:
|
| 605 |
+
countries = ['Argentina', 'Brazil',
|
| 606 |
+
'Chile', 'Colombia', 'Mexico', 'Peru']
|
| 607 |
+
|
| 608 |
+
update_button = form_dif.form_submit_button("Actualizar datos")
|
| 609 |
+
if update_button:
|
| 610 |
+
update_data()
|
| 611 |
+
|
| 612 |
+
accept = form_dif.form_submit_button('Visualizar')
|
| 613 |
+
|
| 614 |
+
criteria = 'LV1'
|
| 615 |
+
|
| 616 |
+
st.write("### Está visualizando: Difusión")
|
| 617 |
+
|
| 618 |
+
colores = list(colores_corporativos().values())
|
| 619 |
+
colores2 = []
|
| 620 |
+
|
| 621 |
+
for i in range(len(colores)):
|
| 622 |
+
colores2.append("rgb" + str(colores[i]))
|
| 623 |
+
|
| 624 |
+
if accept:
|
| 625 |
+
|
| 626 |
+
today = str(date.today())
|
| 627 |
+
# Acá cargamos los datos necesarios
|
| 628 |
+
data = data_request(today, start, countries)
|
| 629 |
+
data_dict = data[0]
|
| 630 |
+
company_db = data[1]
|
| 631 |
+
country_sector = data[2]
|
| 632 |
+
st.write('Data desde ' + str(date.today() - timedelta(365)) + ' hasta ' + str(
|
| 633 |
+
data_dict['IQ_CLOSEPRICE_ADJ'].index[-1].date()))
|
| 634 |
+
|
| 635 |
+
rel_rets, cs_ids, w_hist, bm_dict = dictionaries_maker(start,
|
| 636 |
+
countries,
|
| 637 |
+
country_sector,
|
| 638 |
+
criteria,
|
| 639 |
+
company_db,
|
| 640 |
+
data_dict)
|
| 641 |
+
|
| 642 |
+
p_list = [1, 3, 12]
|
| 643 |
+
prices = data_dict['IQ_CLOSEPRICE_ADJ'].ffill()
|
| 644 |
+
|
| 645 |
+
mm_countries = countries
|
| 646 |
+
start = datetime.today() - timedelta(365)
|
| 647 |
+
|
| 648 |
+
fig_mm = make_subplots(specs=[[{"secondary_y":
|
| 649 |
+
True}]]*len(mm_countries),
|
| 650 |
+
subplot_titles=mm_countries,
|
| 651 |
+
rows=len(mm_countries), cols=1)
|
| 652 |
+
for i, c in enumerate(mm_countries):
|
| 653 |
+
univ = univ_request(company_db, c)
|
| 654 |
+
univ = list(set(univ) & set(prices.columns))
|
| 655 |
+
prices_c = prices[univ].iloc[-500:]
|
| 656 |
+
mm_sum_df = sum([prices_c.rolling(p * 20).apply(mm_eval)
|
| 657 |
+
for p in p_list])
|
| 658 |
+
mm_sum_df = mm_sum_df.iloc[-252:].dropna(how='all')
|
| 659 |
+
|
| 660 |
+
bull = (mm_sum_df == len(p_list)).sum(1) / mm_sum_df.notna().sum(1)
|
| 661 |
+
bear = (mm_sum_df == 0).sum(1) / mm_sum_df.notna().sum(1)
|
| 662 |
+
delta = (bull - bear).to_frame()
|
| 663 |
+
delta.columns = [f'Bull-Bear {c}']
|
| 664 |
+
bm_rets = bm_dict[c]
|
| 665 |
+
delta['aux'] = bm_rets
|
| 666 |
+
delta[f'{c} Index'] = (1 + delta['aux']).cumprod()
|
| 667 |
+
|
| 668 |
+
bull = bull.reindex(pd.to_datetime(bull.index))
|
| 669 |
+
bear = bear.reindex(pd.to_datetime(bear.index))
|
| 670 |
+
delta = delta.reindex(pd.to_datetime(delta.index))
|
| 671 |
+
|
| 672 |
+
bull = bull.loc[bull.index >= start]
|
| 673 |
+
bear = bear.loc[bear.index >= start]
|
| 674 |
+
delta = delta.loc[delta.index >= start]
|
| 675 |
+
|
| 676 |
+
# Bull
|
| 677 |
+
fig_mm.add_trace(go.Scatter(x=bull.index, y=bull.array,
|
| 678 |
+
name='Bull',
|
| 679 |
+
line=dict(color=colores2[5]),
|
| 680 |
+
showlegend=(i == 0)),
|
| 681 |
+
secondary_y=False, row=i + 1,
|
| 682 |
+
col=1)
|
| 683 |
+
# Bear
|
| 684 |
+
fig_mm.add_trace(go.Scatter(x=bear.index, y=bear.array, name='Bear', line=dict(color=colores2[0]),
|
| 685 |
+
showlegend=(i == 0)), secondary_y=False, row=i + 1,
|
| 686 |
+
col=1)
|
| 687 |
+
# Bull-Bear
|
| 688 |
+
fig_mm.add_trace(
|
| 689 |
+
go.Scatter(x=delta.index, y=delta[f'Bull-Bear {c}'], name='Bull - Bear', line=dict(color=colores2[6]),
|
| 690 |
+
showlegend=(i == 0)), row=i + 1, col=1)
|
| 691 |
+
# Indice
|
| 692 |
+
fig_mm.add_trace(go.Scatter(x=delta.index, y=delta[f'{c} Index'], name='Index ', line=dict(color='black'),
|
| 693 |
+
showlegend=(i == 0)), secondary_y=True, row=i + 1, col=1)
|
| 694 |
+
fig_mm.update_yaxes(title_text="Valor",
|
| 695 |
+
secondary_y=False, row=i + 1, col=1)
|
| 696 |
+
fig_mm.update_layout(yaxis1={'tickformat': ',.0%'})
|
| 697 |
+
fig_mm.update_yaxes(title_text="Indice",
|
| 698 |
+
secondary_y=True, row=i + 1, col=1)
|
| 699 |
+
|
| 700 |
+
with st.container():
|
| 701 |
+
fig_mm.update_layout(height=400 * len(mm_countries))
|
| 702 |
+
st.plotly_chart(fig_mm, use_container_width=True)
|
apps/Panel_de_control.py
CHANGED
|
@@ -1,3 +1,95 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
Created on Tue Jan 4 18:23:14 2022
|
| 4 |
+
|
| 5 |
+
@author: bullm
|
| 6 |
+
"""
|
| 7 |
+
import plotly.graph_objects as go
|
| 8 |
+
import plotly.express as px
|
| 9 |
+
import pandas as pd
|
| 10 |
+
import streamlit as st
|
| 11 |
+
import numpy as np
|
| 12 |
+
import matplotlib.pyplot as plt
|
| 13 |
+
|
| 14 |
+
# path = 'C:\\Users\\bullm\\Desktop\\Portal_LVAM\\Data\\'
|
| 15 |
+
# for key in stats_competencia.keys():
|
| 16 |
+
# print(key)
|
| 17 |
+
# stats_competencia[key].to_excel(path+key+'.xlsx')
|
| 18 |
+
# tabla_factores_general.to_excel(path+'factores_general.xlsx')
|
| 19 |
+
|
| 20 |
+
def spider_plot(df, title, alpha=0.1, n_dec=1, y=[]):
|
| 21 |
+
|
| 22 |
+
if len(y) == 0:
|
| 23 |
+
min_val = df.min().min()
|
| 24 |
+
min_val = np.floor(min_val-np.abs(min_val)*alpha, n_dec)
|
| 25 |
+
max_val = df.max().max()
|
| 26 |
+
max_val = np.ceil(max_val+np.abs(max_val)*alpha, n_dec)
|
| 27 |
+
mean_val = np.round((min_val + max_val)/2, 1)
|
| 28 |
+
|
| 29 |
+
y = [min_val, mean_val, max_val]
|
| 30 |
+
|
| 31 |
+
categories = list(df.index)
|
| 32 |
+
N = df.shape[0]
|
| 33 |
+
|
| 34 |
+
# We are going to plot the first line of the data frame.
|
| 35 |
+
# But we need to repeat the first value to close the circular graph:
|
| 36 |
+
values = np.round(df.iloc[:, 0].values.flatten().tolist(), 2)
|
| 37 |
+
values = np.hstack((values, values[0])).T
|
| 38 |
+
|
| 39 |
+
values2 = np.round(df.iloc[:, 1].values.flatten().tolist(), 2)
|
| 40 |
+
values2 = np.hstack((values2, values2[0])).T
|
| 41 |
+
|
| 42 |
+
# What will be the angle of each axis in the plot?
|
| 43 |
+
angles = [n / float(N) * 2 * np.pi for n in range(N)]
|
| 44 |
+
angles += angles[:1]
|
| 45 |
+
|
| 46 |
+
# Initialise the spider plot
|
| 47 |
+
fig = plt.figure(figsize=(10, 15))
|
| 48 |
+
ax = plt.subplot(111, polar=True)
|
| 49 |
+
ax.set_title(title, fontsize=20)
|
| 50 |
+
|
| 51 |
+
# Draw one axe per variable + add labels labels yet
|
| 52 |
+
plt.xticks(angles[:-1], categories, color="black", size=18)
|
| 53 |
+
|
| 54 |
+
# Draw ylabels
|
| 55 |
+
ax.set_rlabel_position(0)
|
| 56 |
+
plt.yticks(y, [str(i) for i in y], color="black", size=15)
|
| 57 |
+
plt.ylim(y[0], y[-1])
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
# Plot data
|
| 62 |
+
ax.plot(angles, values, linewidth=1, linestyle='solid', c='dimgrey')
|
| 63 |
+
ax.plot(angles, values2, linewidth=1, linestyle='solid', c='darkred')
|
| 64 |
+
|
| 65 |
+
handles, labels = ax.get_legend_handles_labels()
|
| 66 |
+
|
| 67 |
+
ax.legend(labels=['Cartera', 'Benchmark'], loc='lower left',
|
| 68 |
+
fontsize=15, bbox_to_anchor=(-0.1, -0.1))
|
| 69 |
+
|
| 70 |
+
# Fill area
|
| 71 |
+
ax.fill(angles, values, 'b', alpha=0.1)
|
| 72 |
+
|
| 73 |
+
return fig
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def panel_de_control():
|
| 77 |
+
df = pd.read_excel("Data/factores_general.xlsx")
|
| 78 |
+
|
| 79 |
+
radar = go.Scatterpolar(
|
| 80 |
+
r = list(df["Benchmark"]),
|
| 81 |
+
theta = list(df['Unnamed: 0']),
|
| 82 |
+
fill = 'toself'
|
| 83 |
+
)
|
| 84 |
+
radar2 = go.Scatterpolar(
|
| 85 |
+
r = list(df["Cartera"]),
|
| 86 |
+
theta = list(df['Unnamed: 0']),
|
| 87 |
+
fill = 'toself'
|
| 88 |
+
)
|
| 89 |
+
data = [radar, radar2]
|
| 90 |
+
fig = go.Figure(data = data)
|
| 91 |
+
col1, col2 = st.columns(2)
|
| 92 |
+
col1.plotly_chart(fig, use_container_width=True)
|
| 93 |
+
df.index= df['Unnamed: 0']
|
| 94 |
+
df = df[["Cartera", 'Benchmark']]
|
| 95 |
+
col2.pyplot(spider_plot(df, '', y=[0, 50, 100] ))
|
apps/Scoring.py
CHANGED
|
@@ -1,3 +1,303 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
import streamlit as st
|
| 3 |
+
import pybase64 as base64
|
| 4 |
+
import io
|
| 5 |
+
from logs_portal import log
|
| 6 |
+
import os
|
| 7 |
+
from datetime import date
|
| 8 |
+
from modules import tables
|
| 9 |
+
import boto3
|
| 10 |
+
from Data.credentials import credentials_s3 as creds3
|
| 11 |
+
from streamlit_echarts import st_echarts
|
| 12 |
+
from st_aggrid import GridOptionsBuilder, AgGrid, GridUpdateMode, DataReturnMode, JsCode
|
| 13 |
+
import numpy as np
|
| 14 |
+
from streamlit_lottie import st_lottie
|
| 15 |
+
import json
|
| 16 |
+
|
| 17 |
+
def generador_variable_pond(name, col_s1):
|
| 18 |
+
col_s1.markdown("""<p style="margin-top:35px;
|
| 19 |
+
font-size:20px;
|
| 20 |
+
text-align:center;
|
| 21 |
+
margin-bottom:30px;
|
| 22 |
+
">{Var}</p>""".format(Var=name),
|
| 23 |
+
unsafe_allow_html=True)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def button_style():
|
| 27 |
+
style_button = """
|
| 28 |
+
<style>
|
| 29 |
+
button {
|
| 30 |
+
display: inline-block;
|
| 31 |
+
background-color: white;
|
| 32 |
+
border-radius: 15px;
|
| 33 |
+
border: 4px #cccccc;
|
| 34 |
+
color: #4a4a4a;
|
| 35 |
+
text-align: center;
|
| 36 |
+
font-size: 18px;
|
| 37 |
+
padding: 2px;
|
| 38 |
+
width: 200px;
|
| 39 |
+
transition: all 0.5s;
|
| 40 |
+
cursor: pointer;
|
| 41 |
+
margin-top: 25px;
|
| 42 |
+
}
|
| 43 |
+
button span {
|
| 44 |
+
cursor: pointer;
|
| 45 |
+
display: inline-block;
|
| 46 |
+
position: relative;
|
| 47 |
+
transition: 0.5s;
|
| 48 |
+
}
|
| 49 |
+
button span:after {
|
| 50 |
+
content: '\00bb';
|
| 51 |
+
position: absolute;
|
| 52 |
+
opacity: 0;
|
| 53 |
+
top: 0;
|
| 54 |
+
right: -20px;
|
| 55 |
+
transition: 0.5s;
|
| 56 |
+
}
|
| 57 |
+
button:hover {
|
| 58 |
+
background-color: #bb1114;
|
| 59 |
+
color:#e8e8e8;
|
| 60 |
+
}
|
| 61 |
+
button:hover span {
|
| 62 |
+
padding-right: 25px;
|
| 63 |
+
}
|
| 64 |
+
button:hover span:after {
|
| 65 |
+
opacity: 1;
|
| 66 |
+
right: 0;
|
| 67 |
+
}
|
| 68 |
+
</style>
|
| 69 |
+
"""
|
| 70 |
+
st.markdown(style_button, unsafe_allow_html=True)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def get_table_excel_link(df, name):
|
| 76 |
+
towrite = io.BytesIO()
|
| 77 |
+
writer = pd.ExcelWriter(towrite, engine='xlsxwriter')
|
| 78 |
+
downloaded_file = df.to_excel(writer, encoding='utf-8', index=False,
|
| 79 |
+
header=True)
|
| 80 |
+
workbook = writer.book
|
| 81 |
+
worksheet = writer.sheets["Sheet1"]
|
| 82 |
+
#set the column width as per your requirement
|
| 83 |
+
worksheet.set_column('A:BZ', 18)
|
| 84 |
+
writer.save()
|
| 85 |
+
towrite.seek(0) # reset pointer
|
| 86 |
+
file_name = 'Scoring.xlsx'
|
| 87 |
+
style = 'style="color:black;text-decoration: none; font-size:18px;" '
|
| 88 |
+
name_mark = name
|
| 89 |
+
b64 = base64.b64encode(towrite.read()).decode() # some strings
|
| 90 |
+
linko = f'<center><a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" '+style+'download="'+file_name+'"><button>'+name_mark+'</button></a></center>'
|
| 91 |
+
return linko
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def read_excel_s3(key, secret_key, bucket, path):
|
| 98 |
+
s3_client = boto3.client('s3', aws_access_key_id = key, aws_secret_access_key= secret_key)
|
| 99 |
+
response = s3_client.get_object(Bucket=bucket, Key=path)
|
| 100 |
+
data = response["Body"].read()
|
| 101 |
+
df = pd.read_excel(io.BytesIO(data), engine='openpyxl')
|
| 102 |
+
return df
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def display_table(df: pd.DataFrame, name):
|
| 106 |
+
# Configure AgGrid options
|
| 107 |
+
gb = GridOptionsBuilder.from_dataframe(df)
|
| 108 |
+
gb.configure_selection(selection_mode="multiple", use_checkbox=True,)
|
| 109 |
+
gb.configure_column(name, headerCheckboxSelection = True)
|
| 110 |
+
gb.configure_columns(("TICKER", "COUNTRY", "LV1"), pinned=True)
|
| 111 |
+
return AgGrid(
|
| 112 |
+
df, gridOptions=gb.build(),
|
| 113 |
+
update_mode=GridUpdateMode.SELECTION_CHANGED,
|
| 114 |
+
enable_enterprise_modules=True)
|
| 115 |
+
|
| 116 |
+
@st.experimental_memo
|
| 117 |
+
def read_scoring():
|
| 118 |
+
key = creds3["S3_KEY_ID"]
|
| 119 |
+
secret_key = creds3["S3_SECRET_KEY"]
|
| 120 |
+
bucket = creds3["S3_BUCKET"]
|
| 121 |
+
path ="scoring.xlsx"
|
| 122 |
+
scoring = read_excel_s3(key, secret_key, bucket, path)
|
| 123 |
+
return scoring
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
# @log
|
| 130 |
+
def general():
|
| 131 |
+
|
| 132 |
+
with open("Data/lotties/99268-laading-22.json", "r") as f:
|
| 133 |
+
spinner = json.load(f)
|
| 134 |
+
cols1, cols2= st.sidebar.columns((3,1))
|
| 135 |
+
place = cols2.empty()
|
| 136 |
+
with place:
|
| 137 |
+
st_lottie(spinner)
|
| 138 |
+
# scoring.index = scoring['Ticker']
|
| 139 |
+
button_style()
|
| 140 |
+
scoring_completo = read_scoring()
|
| 141 |
+
col1, col2, col3 = st.columns((4,1,1))
|
| 142 |
+
col1.write("Last Update: " + scoring_completo.iloc[0]["TODAY"])
|
| 143 |
+
col1.write("Valores en MM USD")
|
| 144 |
+
place1=col2.empty()
|
| 145 |
+
place2 =col3.empty()
|
| 146 |
+
scoring_completo = scoring_completo.drop(columns=["TODAY"])
|
| 147 |
+
scoring_completo[["Nota", 'W Latino', "W Small", 'Nota ESG']] = scoring_completo[["Nota", "W Latino", 'W Small', 'Nota ESG']].fillna(0)
|
| 148 |
+
scoring = scoring_completo.copy()
|
| 149 |
+
# convert just columns "a" and "b"
|
| 150 |
+
metrics = ['MOMENTUM Precio', 'MOMENTUM Fundamental',
|
| 151 |
+
'VALUE','PROF', 'Distres_Prom', 'PROF', 'Delta 1M', 'QUALITY', 'Nota ESG']
|
| 152 |
+
metrics2 = ['Market_Cap'] + metrics
|
| 153 |
+
|
| 154 |
+
scoring[metrics2] = scoring[metrics2].round()
|
| 155 |
+
scoring[["W Latino", "W Small", "BM Latino", "BM Small"]] = scoring[["W Latino", "W Small", "BM Latino", "BM Small"]] * 100
|
| 156 |
+
scoring[["W Latino", "W Small", "BM Latino", "BM Small"]] = scoring[["W Latino", "W Small", "BM Latino", "BM Small"]].round(2).fillna(0)
|
| 157 |
+
metrics_aggrid = ['Ticker', 'Portfolio_Country', 'LV1', 'Market_Cap',
|
| 158 |
+
'ADTV','Large/Small', 'Delta 1M','Distres_Prom', 'MOMENTUM Precio', 'MOMENTUM Fundamental',
|
| 159 |
+
'VALUE','PROF', 'QUALITY', 'Score', "Nota",
|
| 160 |
+
'Nota ESG', 'Stop Loss', "W Latino", "W Small", "BM Latino","BM Small"]
|
| 161 |
+
scoring = scoring[metrics_aggrid]
|
| 162 |
+
scoring[metrics_aggrid] = scoring[metrics_aggrid].replace(np.nan, -1)
|
| 163 |
+
|
| 164 |
+
metrics3 = ['TICKER', 'COUNTRY', 'LV1', 'MKT CAP', 'ADTV', 'L/S', 'Δ 1M',
|
| 165 |
+
'DISTRES', 'MOM PREC',
|
| 166 |
+
'MOM FUND', 'VALUE','PROF', 'QUALITY', 'SCORE',
|
| 167 |
+
"NOTA", 'ESG', 'STOP LOSS', "W LAT", "W SMALL", "BM LAT", "BM SMALL"]
|
| 168 |
+
metrics4 = [
|
| 169 |
+
'MOM PREC', 'MOM FUND', 'VALUE', 'QUALITY','DISTRES', 'PROF']
|
| 170 |
+
scoring.columns = metrics3
|
| 171 |
+
button = st.button("Refresh")
|
| 172 |
+
r = display_table(scoring, 'TICKER')
|
| 173 |
+
rad = 'Home'
|
| 174 |
+
if button:
|
| 175 |
+
st.experimental_memo.clear()
|
| 176 |
+
st.experimental_rerun()
|
| 177 |
+
with place1:
|
| 178 |
+
link = get_table_excel_link(scoring_completo, "Scoring completo")
|
| 179 |
+
st.markdown(link, unsafe_allow_html=True)
|
| 180 |
+
with place2:
|
| 181 |
+
link2 = get_table_excel_link(scoring, "Scoring resumen")
|
| 182 |
+
st.markdown(link2, unsafe_allow_html=True)
|
| 183 |
+
w_lat = []
|
| 184 |
+
w_small = []
|
| 185 |
+
bm_lat = []
|
| 186 |
+
bm_small = []
|
| 187 |
+
col1, col2, col3, col4, col5 = st.columns((1,1,1,1,3))
|
| 188 |
+
large = col1.checkbox("LUXMEXEQ", True)
|
| 189 |
+
small = col2.checkbox("LUXLATSML", True)
|
| 190 |
+
m1la = col3.checkbox("M1LA")
|
| 191 |
+
msm = col4.checkbox("MSLUELAN")
|
| 192 |
+
|
| 193 |
+
if "large" not in st.session_state:
|
| 194 |
+
st.session_state.large=False
|
| 195 |
+
if "small" not in st.session_state:
|
| 196 |
+
st.session_state.small=False
|
| 197 |
+
if "bm_sm" not in st.session_state:
|
| 198 |
+
st.session_state.bm_sm=False
|
| 199 |
+
if "bm_lat" not in st.session_state:
|
| 200 |
+
st.session_state.bm_lat=False
|
| 201 |
+
|
| 202 |
+
if large:
|
| 203 |
+
st.session_state.large = True
|
| 204 |
+
else:
|
| 205 |
+
st.session_state.large = False
|
| 206 |
+
if small:
|
| 207 |
+
st.session_state.small =True
|
| 208 |
+
else:
|
| 209 |
+
st.session_state.small = False
|
| 210 |
+
if m1la:
|
| 211 |
+
st.session_state.bm_lat = True
|
| 212 |
+
else:
|
| 213 |
+
st.session_state.bm_lat = False
|
| 214 |
+
if msm:
|
| 215 |
+
st.session_state.bm_sm =True
|
| 216 |
+
else:
|
| 217 |
+
st.session_state.bm_sm = False
|
| 218 |
+
col1, col2, col3 = st.columns((2.5, 1, 1))
|
| 219 |
+
try:
|
| 220 |
+
series_data = []
|
| 221 |
+
names=[]
|
| 222 |
+
for metric in metrics4:
|
| 223 |
+
w_lat.append((scoring[metric]*scoring["W LAT"]/100).sum())
|
| 224 |
+
w_small.append((scoring[metric]*scoring["W SMALL"]/100).sum())
|
| 225 |
+
bm_lat.append((scoring[metric]*scoring["BM LAT"]/100).sum())
|
| 226 |
+
bm_small.append((scoring[metric]*scoring["BM SMALL"]/100).sum())
|
| 227 |
+
if st.session_state.large:
|
| 228 |
+
series_data.append({"value":w_lat,
|
| 229 |
+
"name": "LUXMEXEQ"})
|
| 230 |
+
names.append("LUXMEXEQ")
|
| 231 |
+
if st.session_state.small:
|
| 232 |
+
series_data.append({"value":w_small,
|
| 233 |
+
"name": "LUXLATSML"})
|
| 234 |
+
names.append("LUXLATSML")
|
| 235 |
+
if st.session_state.bm_lat:
|
| 236 |
+
series_data.append({"value":bm_lat,
|
| 237 |
+
"name": "M1LA"})
|
| 238 |
+
names.append("M1LA")
|
| 239 |
+
if st.session_state.bm_sm:
|
| 240 |
+
series_data.append({"value":bm_small,
|
| 241 |
+
"name": "MSLUELAN"})
|
| 242 |
+
names.append("MSLUELAN")
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
if len(r['selected_rows'])>0:
|
| 248 |
+
for emp in r['selected_rows']:
|
| 249 |
+
selected = emp.copy()
|
| 250 |
+
name = selected['TICKER']
|
| 251 |
+
names.append(name)
|
| 252 |
+
indicators = []
|
| 253 |
+
series_value = []
|
| 254 |
+
for met in metrics4:
|
| 255 |
+
indicators.append({'name': met, "max": 100})
|
| 256 |
+
series_value.append(selected[met])
|
| 257 |
+
series_data.append({"value": series_value,
|
| 258 |
+
"name": name})
|
| 259 |
+
with col2:
|
| 260 |
+
st.metric('SCORE PROMEDIO - ' + name,
|
| 261 |
+
int(np.array(series_value).mean()))
|
| 262 |
+
else:
|
| 263 |
+
indicators = []
|
| 264 |
+
for met in metrics4:
|
| 265 |
+
indicators.append({'name': met, "max": 100})
|
| 266 |
+
option = {
|
| 267 |
+
"title": {"text": 'Score'},
|
| 268 |
+
"legend": {"data": names},
|
| 269 |
+
"radar": {
|
| 270 |
+
"indicator": indicators
|
| 271 |
+
},
|
| 272 |
+
"series": [
|
| 273 |
+
{
|
| 274 |
+
"name": "",
|
| 275 |
+
"type": "radar",
|
| 276 |
+
"data": series_data,
|
| 277 |
+
}
|
| 278 |
+
],
|
| 279 |
+
}
|
| 280 |
+
with col1:
|
| 281 |
+
st_echarts(option, height="400px", width="80%")
|
| 282 |
+
except Exception as exc:
|
| 283 |
+
st.write(exc)
|
| 284 |
+
pass
|
| 285 |
+
|
| 286 |
+
# st.image("img/Scoring.png", width="100%")
|
| 287 |
+
place.empty()
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
def diagrama():
|
| 292 |
+
|
| 293 |
+
import pandas as pd
|
| 294 |
+
import pandas_profiling
|
| 295 |
+
import streamlit as st
|
| 296 |
+
|
| 297 |
+
from streamlit_pandas_profiling import st_profile_report
|
| 298 |
+
st.image("img/Scoring.png")
|
| 299 |
+
df = read_scoring()
|
| 300 |
+
df=df[['MOMENTUM Precio','MOMENTUM Fundamental', 'VALUE','QUALITY', 'PROF','Distres_Prom','Score' ]]
|
| 301 |
+
pr = df.profile_report()
|
| 302 |
+
|
| 303 |
+
st_profile_report(pr)
|
apps/Tasas.py
CHANGED
|
@@ -1,3 +1,950 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
Created on Tue Aug 24 09:38:58 2021
|
| 5 |
+
|
| 6 |
+
@author: benjaminull
|
| 7 |
+
"""
|
| 8 |
+
import investpy
|
| 9 |
+
import datetime as dt
|
| 10 |
+
from datetime import date
|
| 11 |
+
import streamlit as st
|
| 12 |
+
from plotly import graph_objs as go
|
| 13 |
+
import pandas as pd
|
| 14 |
+
import pybase64 as base64
|
| 15 |
+
import io
|
| 16 |
+
from plotly.subplots import make_subplots
|
| 17 |
+
from logs_portal import log
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def formatnum(numero):
|
| 21 |
+
return '{:,.2f}'.format(numero).replace(",", "@").replace(".", ",").replace("@", ".")
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def button_style():
|
| 25 |
+
style_button = """
|
| 26 |
+
<style>
|
| 27 |
+
button {
|
| 28 |
+
display: inline-block;
|
| 29 |
+
background-color: #e8e8e8;
|
| 30 |
+
border-radius: 15px;
|
| 31 |
+
border: 4px #cccccc;
|
| 32 |
+
color: #4a4a4a;
|
| 33 |
+
text-align: center;
|
| 34 |
+
font-size: 20px;
|
| 35 |
+
padding: 2px;
|
| 36 |
+
width: 12em;
|
| 37 |
+
transition: all 0.5s;
|
| 38 |
+
cursor: pointer;
|
| 39 |
+
margin: 0px;
|
| 40 |
+
margin-top: 30px;
|
| 41 |
+
}
|
| 42 |
+
button span {
|
| 43 |
+
cursor: pointer;
|
| 44 |
+
display: inline-block;
|
| 45 |
+
position: relative;
|
| 46 |
+
transition: 0.5s;
|
| 47 |
+
}
|
| 48 |
+
button span:after {
|
| 49 |
+
content: '\00bb';
|
| 50 |
+
position: absolute;
|
| 51 |
+
opacity: 0;
|
| 52 |
+
top: 0;
|
| 53 |
+
right: -20px;
|
| 54 |
+
transition: 0.5s;
|
| 55 |
+
}
|
| 56 |
+
button:hover {
|
| 57 |
+
background-color: #bb1114;
|
| 58 |
+
color:#e8e8e8;
|
| 59 |
+
}
|
| 60 |
+
button:hover span {
|
| 61 |
+
padding-right: 25px;
|
| 62 |
+
}
|
| 63 |
+
button:hover span:after {
|
| 64 |
+
opacity: 1;
|
| 65 |
+
right: 0;
|
| 66 |
+
}
|
| 67 |
+
.stMarkdown{
|
| 68 |
+
margin-bottom:0px;}
|
| 69 |
+
</style>
|
| 70 |
+
"""
|
| 71 |
+
st.markdown(style_button, unsafe_allow_html=True)
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def get_table_excel_link(df, selected_stocks):
|
| 75 |
+
towrite = io.BytesIO()
|
| 76 |
+
downloaded_file = df.to_excel(towrite, encoding='utf-8', index=False,
|
| 77 |
+
header=True)
|
| 78 |
+
towrite.seek(0) # reset pointer
|
| 79 |
+
file_name = 'Data ' + selected_stocks+'.xlsx'
|
| 80 |
+
style = 'style="color:black;text-decoration: none; font-size:18px;"'
|
| 81 |
+
name_mark = "Descargar " + selected_stocks + ".xlsx"
|
| 82 |
+
b64 = base64.b64encode(towrite.read()).decode() # some strings
|
| 83 |
+
linko= f'<center><a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" '+style+'download="'+file_name+'"><button>'+name_mark+'</button></a></center>'
|
| 84 |
+
return linko
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def style_table():
|
| 88 |
+
# tr:hover {background-color: #E8E8E8;
|
| 89 |
+
# color:#BB1114;}
|
| 90 |
+
style_table = """
|
| 91 |
+
<style>
|
| 92 |
+
tbody tr:hover {
|
| 93 |
+
color:#BB1114;}
|
| 94 |
+
tr { line-height: 5px; }
|
| 95 |
+
thead {
|
| 96 |
+
background-color:#BB1114 ;
|
| 97 |
+
color: #E8E8E8;
|
| 98 |
+
}
|
| 99 |
+
tbody tr:nth-child(odd) {
|
| 100 |
+
background-color: #fff;
|
| 101 |
+
}
|
| 102 |
+
tbody tr:nth-child(even) {
|
| 103 |
+
background-color: #eee;
|
| 104 |
+
}
|
| 105 |
+
.css-1rcck9u{
|
| 106 |
+
padding:0.25rem;}
|
| 107 |
+
tbody tr:nth-child(odd)
|
| 108 |
+
stTable {
|
| 109 |
+
border-collapse: collapse;
|
| 110 |
+
background-color:red;
|
| 111 |
+
margin: 25px 0;
|
| 112 |
+
font-size: 0.9em;
|
| 113 |
+
min-width: 400px;
|
| 114 |
+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
| 115 |
+
}
|
| 116 |
+
table{
|
| 117 |
+
margin-top:0px;
|
| 118 |
+
font-size:12px;
|
| 119 |
+
padding:0px;
|
| 120 |
+
height:200px;}
|
| 121 |
+
|
| 122 |
+
@keyframes slidein {
|
| 123 |
+
from {
|
| 124 |
+
margin-left: 100%;
|
| 125 |
+
width: 300%
|
| 126 |
+
}
|
| 127 |
+
to {
|
| 128 |
+
margin-left: 0%;
|
| 129 |
+
width: 100%;
|
| 130 |
+
}
|
| 131 |
+
}
|
| 132 |
+
</style>
|
| 133 |
+
"""
|
| 134 |
+
st.markdown(style_table, unsafe_allow_html=True)
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def grafico_avanzado_com(col_filter, col_button, col_chart, lista, TODAY):
|
| 138 |
+
titulo = "Commodities"
|
| 139 |
+
options = lista
|
| 140 |
+
|
| 141 |
+
fecha_0 = col_filter.selectbox("Periodo ", ["1 year", "1 week",
|
| 142 |
+
"1 month", "3 month",
|
| 143 |
+
"6 month", "5 year",
|
| 144 |
+
"10 year", "15 year"])
|
| 145 |
+
info = pd.DataFrame()
|
| 146 |
+
orden = ["Date"]
|
| 147 |
+
|
| 148 |
+
fecha1 = seleccionar_fecha(fecha_0)
|
| 149 |
+
fig2 = go.Figure()
|
| 150 |
+
for price in options:
|
| 151 |
+
data = investpy.commodities.get_commodity_historical_data(
|
| 152 |
+
price,
|
| 153 |
+
from_date=fecha1,
|
| 154 |
+
to_date=TODAY)
|
| 155 |
+
info[price] = data['Close']
|
| 156 |
+
close_ = go.Scatter(x=data.index,
|
| 157 |
+
y=data['Close']/data.iloc[0]["Close"],
|
| 158 |
+
name=price)
|
| 159 |
+
fig2.add_trace(close_)
|
| 160 |
+
orden.append(price)
|
| 161 |
+
info["Date"] = info.index
|
| 162 |
+
info["Date"] = info["Date"].dt.date
|
| 163 |
+
info = info[orden]
|
| 164 |
+
col_button.markdown(get_table_excel_link(info, "Commodities"),
|
| 165 |
+
unsafe_allow_html=True)
|
| 166 |
+
fig2.layout.update(title_text=titulo,
|
| 167 |
+
xaxis_rangeslider_visible=True,
|
| 168 |
+
height=500,
|
| 169 |
+
margin_b=20,
|
| 170 |
+
margin_r=20,
|
| 171 |
+
margin_l=20,
|
| 172 |
+
legend=dict(orientation="h",
|
| 173 |
+
yanchor="bottom",
|
| 174 |
+
y=1.02,
|
| 175 |
+
xanchor="right",
|
| 176 |
+
x=1))
|
| 177 |
+
col_chart.plotly_chart(fig2, use_container_width=True)
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def grafico_avanzado_div(col_chart, col_filter, col_button, monedabase, lista, TODAY):
|
| 181 |
+
button_style()
|
| 182 |
+
titulo = "Divisas"
|
| 183 |
+
base = "USD"
|
| 184 |
+
options = lista
|
| 185 |
+
fecha_0 = col_filter.selectbox("Periodo", ["1 year",
|
| 186 |
+
"1 week",
|
| 187 |
+
"1 month",
|
| 188 |
+
"3 month",
|
| 189 |
+
"6 month",
|
| 190 |
+
"5 year",
|
| 191 |
+
"10 year",
|
| 192 |
+
"15 year"])
|
| 193 |
+
info = pd.DataFrame()
|
| 194 |
+
orden = ["Date"]
|
| 195 |
+
fig = make_subplots(specs=[[{"secondary_y": True}]])
|
| 196 |
+
fecha1 = seleccionar_fecha(fecha_0)
|
| 197 |
+
i = 0
|
| 198 |
+
for price in options:
|
| 199 |
+
titulo = titulo
|
| 200 |
+
selected_cc = base + "/" + price
|
| 201 |
+
data = investpy.currency_crosses.get_currency_cross_historical_data(selected_cc, from_date=fecha1, to_date=TODAY)
|
| 202 |
+
info[price] = data['Close']
|
| 203 |
+
close_ = go.Scatter(x=data.index,
|
| 204 |
+
y=data['Close']/data.iloc[0]['Close'],
|
| 205 |
+
name=price)
|
| 206 |
+
fig.add_trace(close_)
|
| 207 |
+
orden.append(price)
|
| 208 |
+
i = i+1
|
| 209 |
+
info["Date"] = info.index
|
| 210 |
+
info["Date"] = info["Date"].dt.date
|
| 211 |
+
info = info[orden]
|
| 212 |
+
col_button.markdown(get_table_excel_link(info, "Divisas"),
|
| 213 |
+
unsafe_allow_html=True)
|
| 214 |
+
fig.layout.update(title_text=titulo,
|
| 215 |
+
xaxis_rangeslider_visible=True,
|
| 216 |
+
height=500,
|
| 217 |
+
margin_b=20,
|
| 218 |
+
margin_r=20,
|
| 219 |
+
margin_l=20,
|
| 220 |
+
legend=dict(orientation="h",
|
| 221 |
+
yanchor="bottom",
|
| 222 |
+
y=1.02,
|
| 223 |
+
xanchor="right",
|
| 224 |
+
x=1))
|
| 225 |
+
col_chart.plotly_chart(fig, use_container_width=True)
|
| 226 |
+
import plotly.express as px
|
| 227 |
+
|
| 228 |
+
def grafico_avanzado_ind(col_chart,
|
| 229 |
+
col_filter,
|
| 230 |
+
col_button,
|
| 231 |
+
lista,
|
| 232 |
+
countries,
|
| 233 |
+
today, fechas):
|
| 234 |
+
button_style()
|
| 235 |
+
dict_indices = dict(zip(lista, countries))
|
| 236 |
+
fecha_0 = col_filter.selectbox("Periodo ", fechas)
|
| 237 |
+
fecha1 = seleccionar_fecha(fecha_0)
|
| 238 |
+
titulo = "Indices"
|
| 239 |
+
options = lista
|
| 240 |
+
info = pd.DataFrame()
|
| 241 |
+
orden = ["Date"]
|
| 242 |
+
fig2 = go.Figure()
|
| 243 |
+
i = 0
|
| 244 |
+
for price in options:
|
| 245 |
+
|
| 246 |
+
data = investpy.get_index_historical_data(
|
| 247 |
+
index=price,
|
| 248 |
+
country=dict_indices[price],
|
| 249 |
+
from_date=fecha1,
|
| 250 |
+
to_date=today)
|
| 251 |
+
info[price] = data['Close']
|
| 252 |
+
close_ = go.Scatter(x=data.index,
|
| 253 |
+
y=data['Close']/data.iloc[0]["Close"],
|
| 254 |
+
name=price,
|
| 255 |
+
line=dict(
|
| 256 |
+
color=px.colors.qualitative.Pastel[i]))
|
| 257 |
+
|
| 258 |
+
fig2.add_trace(close_)
|
| 259 |
+
orden.append(price)
|
| 260 |
+
i=i+1
|
| 261 |
+
info["Date"] = info.index
|
| 262 |
+
info["Date"] = info["Date"].dt.date
|
| 263 |
+
info = info[orden]
|
| 264 |
+
col_button.markdown(get_table_excel_link(info, "Indices"),
|
| 265 |
+
unsafe_allow_html=True)
|
| 266 |
+
fig2.layout.update(title_text=titulo,
|
| 267 |
+
xaxis_rangeslider_visible=True,
|
| 268 |
+
height=500,
|
| 269 |
+
margin_b=20,
|
| 270 |
+
margin_r=20,
|
| 271 |
+
margin_l=20,
|
| 272 |
+
|
| 273 |
+
legend=dict(orientation="h",
|
| 274 |
+
yanchor="bottom",
|
| 275 |
+
y=1.02,
|
| 276 |
+
xanchor="right",
|
| 277 |
+
x=1))
|
| 278 |
+
col_chart.plotly_chart(fig2, use_container_width=True)
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
def grafico_avanzado_tasas(col_filter, col_button, col_chart, bonds, TODAY):
|
| 282 |
+
titulo = "Tasas"
|
| 283 |
+
fecha_0 = col_filter.selectbox("Periodo ", ["1 year", "1 week",
|
| 284 |
+
"1 month", "3 month",
|
| 285 |
+
"6 month", "5 year",
|
| 286 |
+
"10 year", "15 year"])
|
| 287 |
+
fecha1 = seleccionar_fecha(fecha_0)
|
| 288 |
+
options = bonds
|
| 289 |
+
info = pd.DataFrame()
|
| 290 |
+
orden = ["Date"]
|
| 291 |
+
fig2 = go.Figure()
|
| 292 |
+
i = 0
|
| 293 |
+
for price in options:
|
| 294 |
+
i = i + 1
|
| 295 |
+
data = investpy.get_bond_historical_data(bond=price,
|
| 296 |
+
from_date=fecha1,
|
| 297 |
+
to_date=TODAY)
|
| 298 |
+
info[price] = data['Close']
|
| 299 |
+
close_ = go.Scatter(x=data.index,
|
| 300 |
+
y=data['Close']/data.iloc[0]["Close"],
|
| 301 |
+
name=price,
|
| 302 |
+
line=dict(
|
| 303 |
+
color=px.colors.qualitative.Pastel[i]))
|
| 304 |
+
fig2.add_trace(close_)
|
| 305 |
+
orden.append(price)
|
| 306 |
+
info["Date"] = info.index
|
| 307 |
+
info["Date"] = info["Date"].dt.date
|
| 308 |
+
info = info[orden]
|
| 309 |
+
col_button.markdown(get_table_excel_link(info, "Tasas"),
|
| 310 |
+
unsafe_allow_html=True)
|
| 311 |
+
# place0.header(titulo)
|
| 312 |
+
fig2.layout.update(title_text=titulo,
|
| 313 |
+
xaxis_rangeslider_visible=True,
|
| 314 |
+
height=500,
|
| 315 |
+
margin_b=20,
|
| 316 |
+
margin_r=20,
|
| 317 |
+
margin_l=20,
|
| 318 |
+
|
| 319 |
+
legend=dict(orientation="h",
|
| 320 |
+
yanchor="bottom",
|
| 321 |
+
y=1.02,
|
| 322 |
+
xanchor="right",
|
| 323 |
+
x=1))
|
| 324 |
+
col_chart.plotly_chart(fig2, use_container_width=True)
|
| 325 |
+
|
| 326 |
+
def view_macro():
|
| 327 |
+
col_filter1, col_button1, col_filter2, col_button2 = st.columns(4)
|
| 328 |
+
col_chart1, col_chart2 = st.columns(2)
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
index = ["S&P CLX IPSA",
|
| 332 |
+
"S&P Merval",
|
| 333 |
+
"Bovespa",
|
| 334 |
+
"S&P Lima General",
|
| 335 |
+
"COLCAP",
|
| 336 |
+
"S&P/BMV IPC",
|
| 337 |
+
"S&P 500",]
|
| 338 |
+
# "FTSE 100",
|
| 339 |
+
# "China A50",
|
| 340 |
+
# "Nikkei 225"]
|
| 341 |
+
countries = ["chile",
|
| 342 |
+
"argentina",
|
| 343 |
+
"brazil",
|
| 344 |
+
"peru",
|
| 345 |
+
"colombia",
|
| 346 |
+
"mexico",
|
| 347 |
+
"united states",]
|
| 348 |
+
# "united kingdom",
|
| 349 |
+
# "china",
|
| 350 |
+
# "japan"]
|
| 351 |
+
place2_index_st = st.empty()
|
| 352 |
+
today = date.today().strftime("%d/%m/%Y")
|
| 353 |
+
fechas = ["1 year",
|
| 354 |
+
"1 week",
|
| 355 |
+
"1 month",
|
| 356 |
+
"3 month",
|
| 357 |
+
"6 month",
|
| 358 |
+
"5 year",
|
| 359 |
+
"10 year",
|
| 360 |
+
"15 year"]
|
| 361 |
+
cc2_i = ["USD", "EUR", 'MXN', "GBP"]
|
| 362 |
+
cc2_f = ["CLP", "EUR", "GBP", "MXN", "JPY", "BRL", "PEN"]
|
| 363 |
+
try:
|
| 364 |
+
grafico_avanzado_ind(col_chart1,
|
| 365 |
+
col_filter1,
|
| 366 |
+
col_button1,
|
| 367 |
+
index,
|
| 368 |
+
countries,
|
| 369 |
+
today,
|
| 370 |
+
fechas)
|
| 371 |
+
except Exception as exc:
|
| 372 |
+
st.write(exc)
|
| 373 |
+
grafico_avanzado_div(col_chart2,
|
| 374 |
+
col_filter2,
|
| 375 |
+
col_button2,
|
| 376 |
+
cc2_i,
|
| 377 |
+
cc2_f,
|
| 378 |
+
today)
|
| 379 |
+
commodity = sorted(["Copper",
|
| 380 |
+
"Silver",
|
| 381 |
+
"Gold",
|
| 382 |
+
"Platinum",
|
| 383 |
+
'Brent Oil',
|
| 384 |
+
'Crude Oil WTI',
|
| 385 |
+
"Natural Gas"])
|
| 386 |
+
col_filter1, col_button1, col_filter2, col_button2 = st.columns(4)
|
| 387 |
+
col_chart1, col_chart2 = st.columns(2)
|
| 388 |
+
|
| 389 |
+
|
| 390 |
+
grafico_avanzado_com(col_filter1, col_button1, col_chart1, commodity, today)
|
| 391 |
+
bonds = ["Chile 10Y", "Peru 10Y", "China 10Y", "U.S. 10Y", "U.K. 10Y",
|
| 392 |
+
"Germany 10y", "Japan 10Y", "Brazil 10Y"]
|
| 393 |
+
try:
|
| 394 |
+
grafico_avanzado_tasas(col_filter2, col_button2, col_chart2, bonds, today)
|
| 395 |
+
except Exception as exc:
|
| 396 |
+
st.write(exc)
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
@st.cache
|
| 401 |
+
def tabla_bonos(stocks, TODAY):
|
| 402 |
+
tabla = pd.DataFrame()
|
| 403 |
+
year_ago = date.today() - dt.timedelta(days=365)
|
| 404 |
+
year_ago = year_ago.strftime("%d/%m/%Y")
|
| 405 |
+
for stock in stocks:
|
| 406 |
+
precios = investpy.get_bond_historical_data(bond=stock,
|
| 407 |
+
from_date=year_ago,
|
| 408 |
+
to_date=TODAY)
|
| 409 |
+
precios = precios["Close"]
|
| 410 |
+
last_price = precios.iloc[-1]
|
| 411 |
+
oned = precios.iloc[-2]
|
| 412 |
+
onew = precios.iloc[-5]
|
| 413 |
+
onem = precios.iloc[-20]
|
| 414 |
+
oney = precios.iloc[0]
|
| 415 |
+
return1m = str(round((last_price - onem), 2))+"%"
|
| 416 |
+
return1d = str(round((last_price - oned), 2))+"%"
|
| 417 |
+
return1w = str(round((last_price - onew), 2))+"%"
|
| 418 |
+
return1y = str(round((last_price - oney), 2))+"%"
|
| 419 |
+
last_price = str(round(last_price, 2))+"%"
|
| 420 |
+
tabla = tabla.append([[last_price, return1d, return1w, return1m,
|
| 421 |
+
return1y]])
|
| 422 |
+
tabla.columns = ["Tasa", "1d", "1w", "1m", "1y"]
|
| 423 |
+
tabla.index = stocks
|
| 424 |
+
return tabla
|
| 425 |
+
|
| 426 |
+
|
| 427 |
+
@st.cache
|
| 428 |
+
def tabla_pendiente(stocks, TODAY):
|
| 429 |
+
tabla = pd.DataFrame()
|
| 430 |
+
year_ago = date.today() - dt.timedelta(days=365)
|
| 431 |
+
year_ago = year_ago.strftime("%d/%m/%Y")
|
| 432 |
+
for stock in stocks:
|
| 433 |
+
precios1 = investpy.get_bond_historical_data(bond=stock + " 2Y",
|
| 434 |
+
from_date=year_ago,
|
| 435 |
+
to_date=TODAY)
|
| 436 |
+
precios2 = investpy.get_bond_historical_data(bond=stock + " 10Y",
|
| 437 |
+
from_date=year_ago,
|
| 438 |
+
to_date=TODAY)
|
| 439 |
+
precios = precios2 - precios1
|
| 440 |
+
precios = precios["Close"]
|
| 441 |
+
last_price = precios.iloc[-1]
|
| 442 |
+
oned = precios.iloc[-2]
|
| 443 |
+
onew = precios.iloc[-5]
|
| 444 |
+
onem = precios.iloc[-20]
|
| 445 |
+
oney = precios.iloc[0]
|
| 446 |
+
return1m = str(round((last_price - onem), 2))+"%"
|
| 447 |
+
return1d = str(round((last_price - oned), 2))+"%"
|
| 448 |
+
return1w = str(round((last_price - onew), 2))+"%"
|
| 449 |
+
return1y = str(round((last_price - oney), 2))+"%"
|
| 450 |
+
last_price = str(round((last_price), 2))+"%"
|
| 451 |
+
tabla = tabla.append([[last_price, return1d, return1w, return1m,
|
| 452 |
+
return1y]])
|
| 453 |
+
tabla.columns = ["Pendiente", "1d", "1w", "1m", "1y"]
|
| 454 |
+
tabla.index = stocks
|
| 455 |
+
return tabla
|
| 456 |
+
|
| 457 |
+
|
| 458 |
+
@st.cache
|
| 459 |
+
def tabla_divisas(stocks, TODAY):
|
| 460 |
+
tabla = pd.DataFrame()
|
| 461 |
+
year_ago = date.today() - dt.timedelta(days=365)
|
| 462 |
+
year_ago = year_ago.strftime("%d/%m/%Y")
|
| 463 |
+
for stock in stocks:
|
| 464 |
+
precios = investpy.currency_crosses.get_currency_cross_historical_data(
|
| 465 |
+
stock,
|
| 466 |
+
from_date=year_ago,
|
| 467 |
+
to_date=TODAY)
|
| 468 |
+
precios = precios["Close"]
|
| 469 |
+
last_price = precios.iloc[-1]
|
| 470 |
+
oned = precios.iloc[-2]
|
| 471 |
+
onew = precios.iloc[-5]
|
| 472 |
+
onem = precios.iloc[-20]
|
| 473 |
+
oney = precios.iloc[0]
|
| 474 |
+
return1m = str(round((last_price/onem-1)*100, 2))+"%"
|
| 475 |
+
return1d = str(round((last_price/oned-1)*100, 2))+"%"
|
| 476 |
+
return1w = str(round((last_price/onew-1)*100, 2))+"%"
|
| 477 |
+
return1y = str(round((last_price/oney-1)*100, 2))+"%"
|
| 478 |
+
last_price = "$" + str(round(last_price, 2))
|
| 479 |
+
tabla = tabla.append([[last_price, return1d, return1w, return1m,
|
| 480 |
+
return1y]])
|
| 481 |
+
tabla.columns = ["Precio","1d", "1w", "1m", "1y"]
|
| 482 |
+
tabla.index = stocks
|
| 483 |
+
return tabla
|
| 484 |
+
|
| 485 |
+
|
| 486 |
+
@st.cache
|
| 487 |
+
def tabla_commodity(stocks, TODAY):
|
| 488 |
+
tabla = pd.DataFrame()
|
| 489 |
+
year_ago = date.today() - dt.timedelta(days=365)
|
| 490 |
+
year_ago = year_ago.strftime("%d/%m/%Y")
|
| 491 |
+
for stock in stocks:
|
| 492 |
+
precios = investpy.commodities.get_commodity_historical_data(
|
| 493 |
+
commodity=stock,
|
| 494 |
+
from_date=year_ago,
|
| 495 |
+
to_date=TODAY)
|
| 496 |
+
precios = precios["Close"]
|
| 497 |
+
last_price = precios.iloc[-1]
|
| 498 |
+
oned = precios.iloc[-2]
|
| 499 |
+
onew = precios.iloc[-5]
|
| 500 |
+
onem = precios.iloc[-20]
|
| 501 |
+
oney = precios.iloc[0]
|
| 502 |
+
return1m = str(round((last_price/onem-1)*100, 2))+"%"
|
| 503 |
+
return1d = str(round((last_price/oned-1)*100, 2))+"%"
|
| 504 |
+
return1w = str(round((last_price/onew-1)*100, 2))+"%"
|
| 505 |
+
return1y = str(round((last_price/oney-1)*100, 2))+"%"
|
| 506 |
+
last_price = "$" + str(round(last_price, 2))
|
| 507 |
+
tabla = tabla.append([[last_price, return1d, return1w, return1m, return1y]])
|
| 508 |
+
tabla.columns = ["Precio","1d", "1w", "1m", "1y"]
|
| 509 |
+
tabla.index = stocks
|
| 510 |
+
return tabla
|
| 511 |
+
|
| 512 |
+
|
| 513 |
+
@st.cache
|
| 514 |
+
def tabla_indices(index, countries, TODAY):
|
| 515 |
+
tabla = pd.DataFrame()
|
| 516 |
+
year_ago = date.today() - dt.timedelta(days=365)
|
| 517 |
+
year_ago = year_ago.strftime("%d/%m/%Y")
|
| 518 |
+
for i in range(len(index)):
|
| 519 |
+
precios = investpy.get_index_historical_data(index=index[i],
|
| 520 |
+
country=countries[i],
|
| 521 |
+
from_date=year_ago,
|
| 522 |
+
to_date=TODAY)
|
| 523 |
+
precios = precios["Close"]
|
| 524 |
+
last_price = precios.iloc[-1]
|
| 525 |
+
oned = precios.iloc[-2]
|
| 526 |
+
onew = precios.iloc[-5]
|
| 527 |
+
onem = precios.iloc[-20]
|
| 528 |
+
oney = precios.iloc[0]
|
| 529 |
+
return1m = str(round((last_price/onem-1)*100, 2))+"%"
|
| 530 |
+
return1d = str(round((last_price/oned-1)*100, 2))+"%"
|
| 531 |
+
return1w = str(round((last_price/onew-1)*100, 2))+"%"
|
| 532 |
+
return1y = str(round((last_price/oney-1)*100, 2))+"%"
|
| 533 |
+
last_price = "$" + str(round(last_price, 2))
|
| 534 |
+
tabla = tabla.append([[last_price, return1d, return1w, return1m, return1y]])
|
| 535 |
+
tabla.columns = ["Precio","1d", "1w", "1m", "1y"]
|
| 536 |
+
tabla.index = index
|
| 537 |
+
return tabla
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
def to_number(valor):
|
| 541 |
+
if valor == "1w":
|
| 542 |
+
value = 0.25
|
| 543 |
+
if valor == "1m":
|
| 544 |
+
value = 1
|
| 545 |
+
elif valor == "3m":
|
| 546 |
+
value = 3
|
| 547 |
+
elif valor == "6m":
|
| 548 |
+
value = 6
|
| 549 |
+
return value
|
| 550 |
+
|
| 551 |
+
|
| 552 |
+
def seleccionar_fecha(fecha_select):
|
| 553 |
+
if fecha_select == "1 week" or fecha_select == "1w":
|
| 554 |
+
fec_in = date.today() - dt.timedelta(days=7)
|
| 555 |
+
elif fecha_select == "1 month":
|
| 556 |
+
fec_in = date.today() - dt.timedelta(days=30)
|
| 557 |
+
elif fecha_select == "3 month":
|
| 558 |
+
fec_in = date.today() - dt.timedelta(days=90)
|
| 559 |
+
elif fecha_select == "6 month":
|
| 560 |
+
fec_in = date.today() - dt.timedelta(days=180)
|
| 561 |
+
elif fecha_select == "1 year":
|
| 562 |
+
fec_in = date.today() - dt.timedelta(days=365)
|
| 563 |
+
elif fecha_select == "5 year":
|
| 564 |
+
fec_in = date.today() - dt.timedelta(days=365*5)
|
| 565 |
+
elif fecha_select == "10 year":
|
| 566 |
+
fec_in = date.today() - dt.timedelta(days=365*10)
|
| 567 |
+
elif fecha_select == "15 year":
|
| 568 |
+
fec_in = date.today() - dt.timedelta(days=365*15)
|
| 569 |
+
fec_in = fec_in.strftime("%d/%m/%Y")
|
| 570 |
+
return fec_in
|
| 571 |
+
|
| 572 |
+
|
| 573 |
+
|
| 574 |
+
|
| 575 |
+
|
| 576 |
+
|
| 577 |
+
@log
|
| 578 |
+
def curva_yield():
|
| 579 |
+
today = date.today()
|
| 580 |
+
col1, col2 = st.columns(2)
|
| 581 |
+
pais = col1.selectbox("Pais", ["Chile", "Brazil", "Mexico", "Colombia",
|
| 582 |
+
"Peru", "Japan", "U.S."])
|
| 583 |
+
meses = col2.selectbox("periodo", ["1w", "1m", "3m", "6m", "1y"])
|
| 584 |
+
if meses == "1w":
|
| 585 |
+
one_months_ago = seleccionar_fecha(meses)
|
| 586 |
+
elif meses == "1y":
|
| 587 |
+
one_months_ago = today.replace(year=today.year - 1).strftime("%d/%m/%Y")
|
| 588 |
+
else:
|
| 589 |
+
mes = to_number(meses)
|
| 590 |
+
one_months_ago = today.replace(month=today.month - mes).strftime("%d/%m/%Y")
|
| 591 |
+
today = today.strftime("%d/%m/%Y")
|
| 592 |
+
if pais == "Chile":
|
| 593 |
+
bonos = ['Chile 1Y', 'Chile 2Y', 'Chile 3Y', 'Chile 4Y', 'Chile 5Y',
|
| 594 |
+
'Chile 8Y', 'Chile 10Y']
|
| 595 |
+
proporcion = [1, 2, 3, 4, 5, 8, 10]
|
| 596 |
+
elif pais == "Brazil":
|
| 597 |
+
bonos = ['Brazil 3m', 'Brazil 6m', 'Brazil 1Y', 'Brazil 2Y',
|
| 598 |
+
'Brazil 3Y', 'Brazil 5Y', 'Brazil 8Y', 'Brazil 10Y']
|
| 599 |
+
proporcion = [0.25, 0.5, 1, 2, 3, 5, 8, 10]
|
| 600 |
+
elif pais == "Mexico":
|
| 601 |
+
bonos = ['Mexico 3m', 'Mexico 6m', 'Mexico 1Y', "Mexico 3Y",
|
| 602 |
+
'Mexico 5Y', 'Mexico 7Y', 'Mexico 10Y']
|
| 603 |
+
proporcion = [0.25, 0.5, 1, 3, 5, 7, 10]
|
| 604 |
+
elif pais == "Colombia":
|
| 605 |
+
bonos = ['Colombia 1Y', 'Colombia 4Y', 'Colombia 5Y', 'Colombia 10Y']
|
| 606 |
+
proporcion = [1, 4, 5, 10]
|
| 607 |
+
elif pais == "Peru":
|
| 608 |
+
bonos = ['Peru 2Y', 'Peru 5Y', 'Peru 10Y']
|
| 609 |
+
proporcion = [2, 5, 10]
|
| 610 |
+
elif pais == "Japan":
|
| 611 |
+
bonos = ['Japan 3m', 'Japan 6m', 'Japan 1Y', "Japan 2Y",
|
| 612 |
+
'Japan 3Y', 'Japan 5Y', 'Japan 8Y', 'Japan 10Y']
|
| 613 |
+
proporcion = [0.25, 0.5, 1, 3, 5, 7, 10]
|
| 614 |
+
elif pais == "U.S.":
|
| 615 |
+
bonos = ['U.S. 3m', 'U.S. 6m', 'U.S. 1Y', "U.S. 2Y",
|
| 616 |
+
'U.S. 3Y', 'U.S. 5Y', 'U.S. 8Y', 'U.S. 10Y']
|
| 617 |
+
proporcion = [0.25, 0.5, 1, 3, 5, 7, 10]
|
| 618 |
+
data_today = []
|
| 619 |
+
data_one_month = []
|
| 620 |
+
delta = []
|
| 621 |
+
for bono in bonos:
|
| 622 |
+
data_bono = investpy.bonds.get_bond_historical_data(bono,
|
| 623 |
+
one_months_ago,
|
| 624 |
+
today)
|
| 625 |
+
data_today.append(data_bono.iloc[-1]["Close"])
|
| 626 |
+
data_one_month.append(data_bono.iloc[0]["Close"])
|
| 627 |
+
delta.append(data_bono.iloc[-1]["Close"] - data_bono.iloc[0]["Close"])
|
| 628 |
+
|
| 629 |
+
def plot_tasas():
|
| 630 |
+
fig = go.Figure()
|
| 631 |
+
today = go.Scatter(x=proporcion, y=data_today, name="Yield today",
|
| 632 |
+
line=dict(color="darkred"))
|
| 633 |
+
onemonth = go.Scatter(x=proporcion, y=data_one_month, name="Yield" +
|
| 634 |
+
meses + " ago", line=dict(color="dimgrey"))
|
| 635 |
+
fig.add_trace(today)
|
| 636 |
+
fig.add_trace(onemonth)
|
| 637 |
+
fig.layout.update(title_text="",
|
| 638 |
+
width=900, height=300, margin_b=0, margin_t=0,
|
| 639 |
+
margin_r=0, margin_l=0, legend=dict(orientation="h",
|
| 640 |
+
yanchor="bottom",
|
| 641 |
+
y=1.0,
|
| 642 |
+
xanchor="right",
|
| 643 |
+
x=1),
|
| 644 |
+
xaxis={'visible': False,
|
| 645 |
+
'showticklabels': False})
|
| 646 |
+
st.plotly_chart(fig)
|
| 647 |
+
fig2 = go.Figure()
|
| 648 |
+
fig2.add_trace(go.Bar(
|
| 649 |
+
x=proporcion,
|
| 650 |
+
y=delta,
|
| 651 |
+
name='Delta',
|
| 652 |
+
marker_color='dimgrey'
|
| 653 |
+
))
|
| 654 |
+
if pais == "Brazil" or pais == "Mexico":
|
| 655 |
+
fig2.layout.update(title_text="",
|
| 656 |
+
width=900, height=200, margin_b=0, margin_t=0,
|
| 657 |
+
margin_r=0, margin_l=15,
|
| 658 |
+
xaxis=go.layout.XAxis(tickangle=70))
|
| 659 |
+
fig2.update_xaxes(range=[-0.3, proporcion[-1]+0.5], ticktext=bonos,
|
| 660 |
+
tickvals=proporcion)
|
| 661 |
+
else:
|
| 662 |
+
fig2.layout.update(title_text="",
|
| 663 |
+
width=900, height=200, margin_b=0, margin_t=0,
|
| 664 |
+
margin_r=0, margin_l=0,
|
| 665 |
+
xaxis=go.layout.XAxis(tickangle=70))
|
| 666 |
+
fig2.update_xaxes(ticktext=bonos, tickvals=proporcion,
|
| 667 |
+
range=[0.5, proporcion[-1]+0.5])
|
| 668 |
+
fig2.update_layout(barmode='group')
|
| 669 |
+
st.plotly_chart(fig2)
|
| 670 |
+
plot_tasas()
|
| 671 |
+
|
| 672 |
+
|
| 673 |
+
def plot_raw_data(col, data, color, prefijo, ancho, largo):
|
| 674 |
+
fig = go.Figure()
|
| 675 |
+
close_ = go.Scatter(x=data.index, y=data['Close'], name="stock_close",
|
| 676 |
+
line=dict(color=color), fill='tonexty')
|
| 677 |
+
fig.add_trace(close_)
|
| 678 |
+
fig.layout.update(title_text="", xaxis_rangeslider_visible=True,
|
| 679 |
+
width=ancho, height=largo, margin_b=0, margin_t=0,
|
| 680 |
+
margin_r=0, margin_l=0)
|
| 681 |
+
fig.update_yaxes(range=[min(data['Close'])/1.05,
|
| 682 |
+
max(data['Close'])*1.05], tickprefix=prefijo)
|
| 683 |
+
col.plotly_chart(fig, use_container_width=True)
|
| 684 |
+
|
| 685 |
+
|
| 686 |
+
# Brasil, Mexico, Chile, Colombia, Peru, USA, Alemania, UK, China, Japon
|
| 687 |
+
@log
|
| 688 |
+
def tasa10y_2y():
|
| 689 |
+
button_style()
|
| 690 |
+
TODAY = date.today().strftime("%d/%m/%Y")
|
| 691 |
+
bond_10y = ["Chile 10Y", "Peru 10Y", "China 10Y", "U.S. 10Y", "U.K. 10Y",
|
| 692 |
+
"Germany 10y", "Japan 10Y", "Brazil 10Y"]
|
| 693 |
+
bond_2y = ["Chile 2Y",
|
| 694 |
+
"Peru 2Y", "China 2Y", "U.S. 2Y", "U.K. 2Y", "Germany 2y",
|
| 695 |
+
"Japan 2Y", "Brazil 2Y"]
|
| 696 |
+
paises = ["Chile", "Peru", "China", "U.S.", "U.K.", "Alemania",
|
| 697 |
+
"Japon", "Brasil"]
|
| 698 |
+
col1, col2 = st.columns((1.681, 1))
|
| 699 |
+
selected = col1.selectbox("Seleccionar pais", paises)
|
| 700 |
+
fecha_select = col2.selectbox(" ", ["1 year", "1 week", "1 month",
|
| 701 |
+
"3 month", "6 month", "5 year",
|
| 702 |
+
"10 year", "15 year"])
|
| 703 |
+
fec_in = seleccionar_fecha(fecha_select)
|
| 704 |
+
data_bonds10y = investpy.get_bond_historical_data(
|
| 705 |
+
bond=bond_10y[paises.index(selected)],
|
| 706 |
+
from_date=fec_in,
|
| 707 |
+
to_date=TODAY)
|
| 708 |
+
data_bonds2y = investpy.get_bond_historical_data(
|
| 709 |
+
bond=bond_2y[paises.index(selected)],
|
| 710 |
+
from_date=fec_in,
|
| 711 |
+
to_date=TODAY)
|
| 712 |
+
data_final = data_bonds10y["Close"]-data_bonds2y["Close"]
|
| 713 |
+
fig = go.Figure()
|
| 714 |
+
close_ = go.Scatter(x=data_bonds10y.index, y=data_final, name="Delta",
|
| 715 |
+
line=dict(color="midnightblue"), fill='tonexty')
|
| 716 |
+
fig.add_trace(close_)
|
| 717 |
+
fig.layout.update(title_text="", xaxis_rangeslider_visible=True,
|
| 718 |
+
width=900, height=400, margin_b=0, margin_t=0,
|
| 719 |
+
margin_r=0, margin_l=0)
|
| 720 |
+
fig.update_yaxes(range=[min(data_final)/1.05,
|
| 721 |
+
max(data_final)*1.05])
|
| 722 |
+
cols = st.columns((1.681*2.681, 1.681, 1))
|
| 723 |
+
col1, col2 = st.columns((1.681, 1))
|
| 724 |
+
col1.plotly_chart(fig, use_container_width=True)
|
| 725 |
+
data_final2 = pd.DataFrame()
|
| 726 |
+
data_final2["Date"] = list(data_final.index)
|
| 727 |
+
cierre = list(data_bonds10y["Close"]-data_bonds2y["Close"])
|
| 728 |
+
data_final2["Delta"] = list(data_bonds10y["Close"]-data_bonds2y["Close"])
|
| 729 |
+
last_price = cierre[-1]
|
| 730 |
+
first_price = cierre[0]
|
| 731 |
+
returns = round(((last_price - first_price)), 2)
|
| 732 |
+
cols[1].markdown('<p style="font-size:15px; padding-left:20px; margin-bottom:0px;">'+"Tasa 10Y - 2Y"+"</p>", unsafe_allow_html=True)
|
| 733 |
+
cols[1].markdown('<p style="font-size:35px; padding-left:30px;">'+formatnum(last_price)+"%</p>", unsafe_allow_html=True)
|
| 734 |
+
if returns > 0:
|
| 735 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:green;">▲ '+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 736 |
+
else:
|
| 737 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:red;">▼ '+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 738 |
+
st.markdown(get_table_excel_link(data_final2, selected),
|
| 739 |
+
unsafe_allow_html=True)
|
| 740 |
+
paises = ["Brazil", "Chile",
|
| 741 |
+
"Peru", "China", "U.S.", "U.K.", "Germany",
|
| 742 |
+
"Japan"]
|
| 743 |
+
style_table()
|
| 744 |
+
col2.dataframe(tabla_pendiente(paises, TODAY))
|
| 745 |
+
|
| 746 |
+
|
| 747 |
+
@log
|
| 748 |
+
def bonos():
|
| 749 |
+
st.sidebar.subheader("Opciones")
|
| 750 |
+
largo = 350
|
| 751 |
+
ancho = 450
|
| 752 |
+
button_style()
|
| 753 |
+
placeholder = st.empty()
|
| 754 |
+
placeholder1 = st.empty()
|
| 755 |
+
TODAY = date.today().strftime("%d/%m/%Y")
|
| 756 |
+
cols = st.columns((1.681*2.5, 1.681, 1))
|
| 757 |
+
col1, col2 = st.columns((1.6, 1))
|
| 758 |
+
paises = ["Brazil", "Mexico", "Chile", "Colombia",
|
| 759 |
+
"Peru", "China", "U.S.", "U.K.", "Germany",
|
| 760 |
+
"Japan"]
|
| 761 |
+
time = ["2Y", "10Y"]
|
| 762 |
+
# #################
|
| 763 |
+
selected_pais = cols[0].selectbox(" ", paises)
|
| 764 |
+
selected_time = cols[1].selectbox(" ", time)
|
| 765 |
+
fecha_select = cols[2].selectbox(" ", ["1 year", "1 week", "1 month",
|
| 766 |
+
"3 month", "6 month", "5 year",
|
| 767 |
+
"10 year", "15 year"])
|
| 768 |
+
fec_in = seleccionar_fecha(fecha_select)
|
| 769 |
+
selected = selected_pais + " " + selected_time
|
| 770 |
+
data_bonds = investpy.get_bond_historical_data(bond=selected,
|
| 771 |
+
from_date=fec_in,
|
| 772 |
+
to_date=TODAY)
|
| 773 |
+
|
| 774 |
+
plot_raw_data(col1, data_bonds, 'dimgrey', "", ancho, largo)
|
| 775 |
+
|
| 776 |
+
last_price = data_bonds.iloc[-1]["Close"]
|
| 777 |
+
first_price = data_bonds.iloc[0]["Close"]
|
| 778 |
+
returns = round((last_price - first_price), 2)
|
| 779 |
+
cols[0].title("Tasa " + selected)
|
| 780 |
+
cols[1].markdown('<p style="font-size:15px; padding-left:20px; margin-bottom:0px;">'+"Tasa"+"</p>", unsafe_allow_html=True)
|
| 781 |
+
cols[1].markdown('<p style="font-size:35px; padding-left:30px;">'+formatnum(last_price)+"%</p>", unsafe_allow_html=True)
|
| 782 |
+
if returns > 0:
|
| 783 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:green;">▲ +'+ formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 784 |
+
else:
|
| 785 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:red;">▼ '+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 786 |
+
# #################
|
| 787 |
+
style_table()
|
| 788 |
+
bonds10y = ["Brazil 10Y",
|
| 789 |
+
"Mexico 10Y",
|
| 790 |
+
"Chile 10Y",
|
| 791 |
+
"Colombia 10Y",
|
| 792 |
+
"Peru 10Y","China 10Y", "U.S. 10Y", "U.K. 10Y", "Germany 10y",
|
| 793 |
+
"Japan 10Y", ]
|
| 794 |
+
col2.dataframe(tabla_bonos(bonds10y, TODAY))
|
| 795 |
+
data_bonds["Date"] = data_bonds.index
|
| 796 |
+
data_bonds["Date"] = data_bonds["Date"].dt.date
|
| 797 |
+
data_toexcel = data_bonds[["Date", "Close"]]
|
| 798 |
+
st.markdown(get_table_excel_link(data_toexcel, selected),
|
| 799 |
+
unsafe_allow_html=True)
|
| 800 |
+
# graph_advance = st.sidebar.checkbox("Graficos avanzados")
|
| 801 |
+
# if graph_advance:
|
| 802 |
+
|
| 803 |
+
|
| 804 |
+
|
| 805 |
+
@log
|
| 806 |
+
def Commodities():
|
| 807 |
+
st.sidebar.subheader("Opciones")
|
| 808 |
+
largo = 350
|
| 809 |
+
ancho = 450
|
| 810 |
+
placeholder = st.empty()
|
| 811 |
+
placeholder1 = st.empty()
|
| 812 |
+
button_style()
|
| 813 |
+
TODAY = date.today().strftime("%d/%m/%Y")
|
| 814 |
+
col1, col2 = st.columns((1.681, 1))
|
| 815 |
+
cols = st.columns((1.681*2.681, 1.681, 1))
|
| 816 |
+
commodity = sorted(["Copper", "Silver", "Gold", "Platinum", 'Brent Oil',
|
| 817 |
+
'Crude Oil WTI', "Natural Gas"])
|
| 818 |
+
# #################
|
| 819 |
+
selected_com = col1.selectbox(" ", commodity)
|
| 820 |
+
fecha_select = col2.selectbox(" ", ["1 year", "1 week", "1 month",
|
| 821 |
+
"3 month", "6 month", "5 year",
|
| 822 |
+
"10 year", "15 year"])
|
| 823 |
+
fec_in = seleccionar_fecha(fecha_select)
|
| 824 |
+
data_com = investpy.commodities.get_commodity_historical_data(
|
| 825 |
+
commodity=selected_com,
|
| 826 |
+
from_date=fec_in,
|
| 827 |
+
to_date=TODAY)
|
| 828 |
+
col1, col2 = st.columns((1.681, 1))
|
| 829 |
+
plot_raw_data(col1, data_com, 'dimgrey', "", ancho, largo)
|
| 830 |
+
last_price = data_com.iloc[-1]["Close"]
|
| 831 |
+
first_price = data_com.iloc[0]["Close"]
|
| 832 |
+
returns = round(((last_price/first_price-1)*100), 2)
|
| 833 |
+
cols[0].title("Precio " + selected_com)
|
| 834 |
+
cols[1].markdown('<h4 style="font-size:15px; padding-left:20px; margin-bottom:0px;">'+"Precio"+"</h4>", unsafe_allow_html=True)
|
| 835 |
+
cols[1].markdown('<p style="font-size:30px; padding-left:30px;">$'+formatnum(last_price)+"</p>", unsafe_allow_html=True)
|
| 836 |
+
if returns > 0:
|
| 837 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:green;">▲ +'+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 838 |
+
else:
|
| 839 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:red;">▼ '+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 840 |
+
##################
|
| 841 |
+
|
| 842 |
+
style_table()
|
| 843 |
+
col2.dataframe(tabla_commodity(commodity, TODAY))
|
| 844 |
+
data_com["Date"] = data_com.index
|
| 845 |
+
data_com["Date"] = data_com["Date"].dt.date
|
| 846 |
+
data_com_toexcel = data_com[["Date", "Close"]]
|
| 847 |
+
st.markdown(get_table_excel_link(data_com_toexcel, selected_com),
|
| 848 |
+
unsafe_allow_html=True)
|
| 849 |
+
|
| 850 |
+
|
| 851 |
+
|
| 852 |
+
@log
|
| 853 |
+
def Indices():
|
| 854 |
+
st.sidebar.subheader("Opciones")
|
| 855 |
+
largo = 350
|
| 856 |
+
ancho = 450
|
| 857 |
+
placeholder = st.empty()
|
| 858 |
+
placeholder1 = st.empty()
|
| 859 |
+
button_style()
|
| 860 |
+
TODAY = date.today().strftime("%d/%m/%Y")
|
| 861 |
+
col1, col2 = st.columns((1.681, 1))
|
| 862 |
+
cols = st.columns((1.681*2.681, 1.681, 1.2))
|
| 863 |
+
index = ["S&P CLX IPSA", "S&P Merval", "Bovespa", "S&P Lima General",
|
| 864 |
+
"COLCAP", "S&P/BMV IPC", "S&P 500", "FTSE 100", "China A50",
|
| 865 |
+
"Nikkei 225"]
|
| 866 |
+
countries = ["chile", "argentina", "brazil", "peru", "colombia", "mexico",
|
| 867 |
+
"united states", "united kingdom", "china", "japan"]
|
| 868 |
+
##################
|
| 869 |
+
selected_index = col1.selectbox(" ", index)
|
| 870 |
+
fecha_select = col2.selectbox(" ", ["1 year", "1 week", "1 month",
|
| 871 |
+
"3 month", "6 month", "5 year",
|
| 872 |
+
"10 year", "15 year"])
|
| 873 |
+
fec_in = seleccionar_fecha(fecha_select)
|
| 874 |
+
data_index = investpy.get_index_historical_data(
|
| 875 |
+
index=selected_index,
|
| 876 |
+
country=countries[index.index(selected_index)],
|
| 877 |
+
from_date=fec_in,
|
| 878 |
+
to_date=TODAY)
|
| 879 |
+
col1, col2 = st.columns((1.681, 1))
|
| 880 |
+
plot_raw_data(col1, data_index, 'dimgrey', "", ancho, largo)
|
| 881 |
+
last_price = data_index.iloc[-1]["Close"]
|
| 882 |
+
first_price = data_index.iloc[0]["Close"]
|
| 883 |
+
returns = round(((last_price/first_price-1)*100), 2)
|
| 884 |
+
cols[0].title("Precio " + selected_index)
|
| 885 |
+
cols[1].markdown('<h4 style="font-size:15px; padding-left:20px; margin-bottom:0px;">'+"Precio"+"</h4>", unsafe_allow_html=True)
|
| 886 |
+
cols[1].markdown('<p style="font-size:30px; padding-left:30px;">$'+formatnum(last_price)+"</p>", unsafe_allow_html=True)
|
| 887 |
+
if returns > 0:
|
| 888 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:green;">▲ +'+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 889 |
+
else:
|
| 890 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:red;">▼ '+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 891 |
+
##################
|
| 892 |
+
style_table()
|
| 893 |
+
col2.dataframe(tabla_indices(index, countries, TODAY))
|
| 894 |
+
data_index["Date"] = data_index.index
|
| 895 |
+
data_index["Date"] = data_index["Date"].dt.date
|
| 896 |
+
data_index_toexcel = data_index[["Date", "Close"]]
|
| 897 |
+
st.markdown(get_table_excel_link(data_index_toexcel, selected_index),
|
| 898 |
+
unsafe_allow_html=True)
|
| 899 |
+
|
| 900 |
+
|
| 901 |
+
|
| 902 |
+
@log
|
| 903 |
+
def Divisas():
|
| 904 |
+
st.sidebar.subheader("Opciones")
|
| 905 |
+
largo = 350
|
| 906 |
+
ancho = 450
|
| 907 |
+
placeholder = st.empty()
|
| 908 |
+
placeholder1 = st.empty()
|
| 909 |
+
button_style()
|
| 910 |
+
TODAY = date.today().strftime("%d/%m/%Y")
|
| 911 |
+
cols = st.columns(3)
|
| 912 |
+
cc1 = ["USD/CLP", "EUR/CLP", "GBP/CLP", "BRL/CLP", "JPY/CLP", "MXN/CLP",
|
| 913 |
+
"PEN/CLP"]
|
| 914 |
+
##################
|
| 915 |
+
cc2_i = ["USD", "EUR", 'MXN', "GBP"]
|
| 916 |
+
cc2_f = ["CLP", "USD", "EUR", "GBP", "MXN", "JPY", "BRL", "PEN"]
|
| 917 |
+
##################
|
| 918 |
+
selected_cc2_i = cols[0].selectbox(" ", cc2_i)
|
| 919 |
+
selected_cc2_f = cols[1].selectbox(" ", cc2_f)
|
| 920 |
+
selected_cc2 = selected_cc2_i + "/" + selected_cc2_f
|
| 921 |
+
fecha_select2 = cols[2].selectbox(" ", ["1 year", "1 week", "1 month",
|
| 922 |
+
"3 month", "6 month",
|
| 923 |
+
"5 year", "10 year",
|
| 924 |
+
"15 year"])
|
| 925 |
+
fec_in2 = seleccionar_fecha(fecha_select2)
|
| 926 |
+
data_cc2 = investpy.currency_crosses.get_currency_cross_historical_data(
|
| 927 |
+
selected_cc2, from_date=fec_in2, to_date=TODAY)
|
| 928 |
+
cols = st.columns((1.681*2.681, 1.681, 1))
|
| 929 |
+
col1, col2 = st.columns((1.681, 1))
|
| 930 |
+
plot_raw_data(col1, data_cc2, 'midnightblue', "", ancho, largo)
|
| 931 |
+
last_price = data_cc2.iloc[-1]["Close"]
|
| 932 |
+
first_price = data_cc2.iloc[0]["Close"]
|
| 933 |
+
returns = round(((last_price/first_price-1)*100), 2)
|
| 934 |
+
cols[0].title(selected_cc2)
|
| 935 |
+
cols[1].markdown('<p style="font-size:15px; padding-left:15px; margin-bottom:0px;">'+"Precio"+"</p>", unsafe_allow_html=True)
|
| 936 |
+
cols[1].markdown('<p style="font-size:30px; padding-left:30px;">' + formatnum(last_price)+ " "+selected_cc2_f +"</p>", unsafe_allow_html=True)
|
| 937 |
+
if returns > 0:
|
| 938 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:green;">▲ '+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 939 |
+
else:
|
| 940 |
+
cols[2].markdown('<p style="font-size:22px; padding-top:27px; color:red;">▼ '+formatnum(returns)+" %</p>", unsafe_allow_html=True)
|
| 941 |
+
style_table()
|
| 942 |
+
# col1.dataframe(tabla_indices(index, countries, TODAY))
|
| 943 |
+
# col2.dataframe(tabla_indices(index2, countries, TODAY))
|
| 944 |
+
data_cc2["Date"] = data_cc2.index
|
| 945 |
+
data_cc2["Date"] = data_cc2["Date"].dt.date
|
| 946 |
+
data_cc2_toexcel = data_cc2[["Date", "Close"]]
|
| 947 |
+
st.markdown(get_table_excel_link(data_cc2_toexcel, selected_cc2),
|
| 948 |
+
unsafe_allow_html=True)
|
| 949 |
+
col2.dataframe(tabla_divisas(cc1, TODAY))
|
| 950 |
+
|
apps/analisis_inmob.py
CHANGED
|
@@ -1,3 +1,347 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Imports
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import streamlit as st
|
| 4 |
+
import pybase64 as base64
|
| 5 |
+
# from modules.tables import RealEstateMaste
|
| 6 |
+
from sqlalchemy import create_engine
|
| 7 |
+
import plotly.express as px
|
| 8 |
+
import io
|
| 9 |
+
import urllib.request
|
| 10 |
+
import bs4 as bs
|
| 11 |
+
import scipy.stats as stats
|
| 12 |
+
import plotly.figure_factory as ff
|
| 13 |
+
import scipy.stats as stats
|
| 14 |
+
import plotly.graph_objects as go
|
| 15 |
+
import numpy as np
|
| 16 |
+
from datetime import date
|
| 17 |
+
from datetime import timedelta
|
| 18 |
+
from Data.credentials import credentials_postgresql as credpost
|
| 19 |
+
|
| 20 |
+
def formatnum(numero):
|
| 21 |
+
'''
|
| 22 |
+
Esta función permite dar formato a los montos de saldo y valor cuota en
|
| 23 |
+
las cartolas.
|
| 24 |
+
'''
|
| 25 |
+
return '{:,.0f}'.format(numero).replace(",", "@").replace(".", ",").replace("@", ".")
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def get_UF():
|
| 29 |
+
link = "https://valoruf.cl/"
|
| 30 |
+
req = urllib.request.Request(link)
|
| 31 |
+
res = urllib.request.urlopen(req)
|
| 32 |
+
resData = res.read()
|
| 33 |
+
soup = bs.BeautifulSoup(resData)
|
| 34 |
+
uf = soup.find(class_="vpr").contents[0]
|
| 35 |
+
uf_value = uf.split(' ')[1]
|
| 36 |
+
uf_value = uf_value.replace('.', '')
|
| 37 |
+
uf_value = uf_value.replace(',', '.')
|
| 38 |
+
return uf_value
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def button_style():
|
| 42 |
+
style_button = """
|
| 43 |
+
<style>
|
| 44 |
+
button {
|
| 45 |
+
display: inline-block;
|
| 46 |
+
background-color: #e8e8e8;
|
| 47 |
+
border-radius: 15px;
|
| 48 |
+
border: 4px #cccccc;
|
| 49 |
+
color: #4a4a4a;
|
| 50 |
+
text-align: center;
|
| 51 |
+
font-size: 18px;
|
| 52 |
+
padding: 2px;
|
| 53 |
+
width: 300px;
|
| 54 |
+
transition: all 0.5s;
|
| 55 |
+
cursor: pointer;
|
| 56 |
+
margin: 5px;
|
| 57 |
+
}
|
| 58 |
+
button span {
|
| 59 |
+
cursor: pointer;
|
| 60 |
+
display: inline-block;
|
| 61 |
+
position: relative;
|
| 62 |
+
transition: 0.5s;
|
| 63 |
+
}
|
| 64 |
+
button span:after {
|
| 65 |
+
content: '\00bb';
|
| 66 |
+
position: absolute;
|
| 67 |
+
opacity: 0;
|
| 68 |
+
top: 0;
|
| 69 |
+
right: -20px;
|
| 70 |
+
transition: 0.5s;
|
| 71 |
+
}
|
| 72 |
+
button:hover {
|
| 73 |
+
background-color: #bb1114;
|
| 74 |
+
color:#e8e8e8;
|
| 75 |
+
}
|
| 76 |
+
button:hover span {
|
| 77 |
+
padding-right: 25px;
|
| 78 |
+
}
|
| 79 |
+
button:hover span:after {
|
| 80 |
+
opacity: 1;
|
| 81 |
+
right: 0;
|
| 82 |
+
}
|
| 83 |
+
</style>
|
| 84 |
+
"""
|
| 85 |
+
st.markdown(style_button, unsafe_allow_html=True)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def plot_column(data, column, nom_var_inv, placeholder, sigmas=3, limite=None):
|
| 89 |
+
data = data.rename(columns=nom_var_inv)
|
| 90 |
+
column = nom_var_inv[column]
|
| 91 |
+
limit = data[column].mean() + sigmas * data[column].std()
|
| 92 |
+
data = data.loc[data[column] <= limit]
|
| 93 |
+
if limite is not None:
|
| 94 |
+
data = data.loc[data[column] <= limite]
|
| 95 |
+
fig = px.scatter_mapbox(data_frame=data, lat='latitud', lon='longitud',
|
| 96 |
+
zoom=10, color=column,
|
| 97 |
+
hover_data=['codigo', 'Superficie', 'dormitorios', 'banos', 'Precio en CLP'],
|
| 98 |
+
color_continuous_scale=px.colors.diverging.RdYlBu,
|
| 99 |
+
width=1000, height=800)
|
| 100 |
+
placeholder.plotly_chart(fig, use_container_width=True)
|
| 101 |
+
|
| 102 |
+
def plot_column2(data, column, nom_var_inv, placeholder, zoom, sigmas=10, limite=None):
|
| 103 |
+
data = data.rename(columns=nom_var_inv)
|
| 104 |
+
column = nom_var_inv[column]
|
| 105 |
+
limit = data[column].mean() + sigmas * data[column].std()
|
| 106 |
+
data = data.loc[data[column] <= limit]
|
| 107 |
+
if limite is not None:
|
| 108 |
+
data = data.loc[data[column] <= limite]
|
| 109 |
+
fig = px.scatter_mapbox(data_frame=data, lat='latitud', lon='longitud',
|
| 110 |
+
zoom=zoom, color=column,
|
| 111 |
+
hover_data=['codigo', 'Superficie', 'dormitorios', 'banos', 'Precio en CLP', 'Comuna'],
|
| 112 |
+
color_continuous_scale=px.colors.diverging.RdYlBu,
|
| 113 |
+
width=1000, height=800,size='Superficie',size_max=25)
|
| 114 |
+
placeholder.plotly_chart(fig, use_container_width=True)
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def get_comuna(direction):
|
| 118 |
+
values = direction.split(',')
|
| 119 |
+
return values[-2]
|
| 120 |
+
|
| 121 |
+
def unit_separator(string):
|
| 122 |
+
values = string.split(" ")
|
| 123 |
+
return values[0]
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def transform_df(scraping_df):
|
| 127 |
+
# Extract numbers from string
|
| 128 |
+
# Change datatype
|
| 129 |
+
# Add 'Comuna' and 'Región'
|
| 130 |
+
scraping_df[["Comuna"]] = scraping_df[["direccion"]].applymap(lambda x: get_comuna(x))
|
| 131 |
+
# Scrap UF value for date
|
| 132 |
+
#scraping_df[["Valor UF"]] = get_UF()
|
| 133 |
+
return scraping_df
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def get_table_excel_link(df, name):
|
| 137 |
+
towrite = io.BytesIO()
|
| 138 |
+
downloaded_file = df.to_excel(towrite, encoding='utf-8', index=False,
|
| 139 |
+
header=True)
|
| 140 |
+
towrite.seek(0) # reset pointer
|
| 141 |
+
file_name = 'Data' + name + '.xlsx'
|
| 142 |
+
style = 'style="color:black;text-decoration: none; font-size:18px;"'
|
| 143 |
+
name_mark = "Descargar " + name + ".xlsx"
|
| 144 |
+
b64 = base64.b64encode(towrite.read()).decode() # some strings
|
| 145 |
+
linko= f'<center><a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" '+style+'download="'+file_name+'"><button>'+name_mark+'</button></a></center>'
|
| 146 |
+
return linko
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
@st.cache(allow_output_mutation=True)
|
| 150 |
+
def query_inmob():
|
| 151 |
+
url = credpost["POSTGRESQL"]
|
| 152 |
+
engine = create_engine(url, echo=False)
|
| 153 |
+
semana_pasada = date.today() - timedelta(7)
|
| 154 |
+
semana_pasada = semana_pasada.strftime("%Y-%m-%d")
|
| 155 |
+
data = pd.read_sql_query("""select * from scraping_inmob where Fecha >
|
| 156 |
+
'{Fecha} 00:00:00' ORDER BY Fecha desc""".format(Fecha=semana_pasada) , con=engine)
|
| 157 |
+
return data
|
| 158 |
+
|
| 159 |
+
def run_scrapping():
|
| 160 |
+
button_style()
|
| 161 |
+
px.set_mapbox_access_token('pk.eyJ1IjoibW9rc2VuYmVyZyIsImEiOiJja3QwOTc3dHgyNzBhMnFsczJ2Y2w3bWJlIn0.m8c3duvR5hQVjbjEByorWQ')
|
| 162 |
+
data = query_inmob()
|
| 163 |
+
precio_uf = get_UF()
|
| 164 |
+
data["valor_uf"] = data["valor_peso"]/float(precio_uf)
|
| 165 |
+
data['predicted_venta_por_m2_UF']=data['predicted_venta_por_m2']/float(precio_uf)
|
| 166 |
+
nom_var = {"Precio en UF": "valor_uf",
|
| 167 |
+
"Precio en CLP": "valor_peso",
|
| 168 |
+
"Superficie": "superficie",
|
| 169 |
+
"Predicted venta por M2 en CLP": "predicted_venta_por_m2",
|
| 170 |
+
"Predicted venta por M2 en UF": "predicted_venta_por_m2_UF",
|
| 171 |
+
"Predicted arriendo por M2": "predicted_arriendo_por_m2",
|
| 172 |
+
"Predicted yield anual": "predicted_yield_anual"
|
| 173 |
+
}
|
| 174 |
+
nom_var_inv = {v: k for k, v in nom_var.items()}
|
| 175 |
+
var = list(nom_var.keys())
|
| 176 |
+
with st.form(key='my_form'):
|
| 177 |
+
col1, col2, col3, col4 = st.columns((9, 1, 9, 1))
|
| 178 |
+
cols = st.columns((9, 1, 5, 5))
|
| 179 |
+
pre_selection = col1.selectbox("Variable", var)
|
| 180 |
+
selection = nom_var[pre_selection]
|
| 181 |
+
mercado = col3.selectbox("Mercado", ["Venta", "Arriendo", "Todos"])
|
| 182 |
+
if mercado != "Todos":
|
| 183 |
+
mercado = mercado.lower()
|
| 184 |
+
data_mercado = data[data["mercado"] == mercado]
|
| 185 |
+
else:
|
| 186 |
+
data_mercado = data
|
| 187 |
+
cifras = len(str(int(max(data_mercado[selection]))))
|
| 188 |
+
tipo_prop = cols[0].selectbox("Tipo de propiedad",
|
| 189 |
+
["Todos", "Casa", "Departamento"])
|
| 190 |
+
if tipo_prop != "Todos":
|
| 191 |
+
tipo_prop2 = tipo_prop.lower()
|
| 192 |
+
data_mercado = data_mercado[data_mercado["tipo_propiedad"] == tipo_prop2]
|
| 193 |
+
if cifras > 3:
|
| 194 |
+
corte = 10 ** (cifras - 3)
|
| 195 |
+
cota_final = (int(max(data_mercado[selection].dropna()))//corte+1) *corte
|
| 196 |
+
cota_inf = cols[2].number_input(label="Valor Mínimo",
|
| 197 |
+
min_value=0,
|
| 198 |
+
value=0,
|
| 199 |
+
max_value=cota_final
|
| 200 |
+
)
|
| 201 |
+
cota_sup = cols[3].number_input(label="Valor Máximo",
|
| 202 |
+
min_value=0,
|
| 203 |
+
value=cota_final,
|
| 204 |
+
max_value=cota_final
|
| 205 |
+
)
|
| 206 |
+
else:
|
| 207 |
+
cota_final = max(data_mercado[selection].dropna())+1
|
| 208 |
+
cota_inf = cols[2].number_input(label="Valor Mínimo",
|
| 209 |
+
min_value=0.0,
|
| 210 |
+
value=0.0,
|
| 211 |
+
step=0.1,
|
| 212 |
+
max_value=cota_final
|
| 213 |
+
)
|
| 214 |
+
cota_sup = cols[3].number_input(label="Valor Máximo",
|
| 215 |
+
min_value=0.0,
|
| 216 |
+
step=0.1,
|
| 217 |
+
value=cota_final,
|
| 218 |
+
max_value=cota_final
|
| 219 |
+
)
|
| 220 |
+
data_final = data_mercado[data_mercado[selection] < cota_sup]
|
| 221 |
+
data_final = data_final[data_final[selection] > cota_inf]
|
| 222 |
+
submit_button = st.form_submit_button(label='Actualizar')
|
| 223 |
+
col1, col2 = st.columns((0.65, 1))
|
| 224 |
+
placeholder = st.empty()
|
| 225 |
+
placeholder2 = st.empty()
|
| 226 |
+
placeholder2.markdown(get_table_excel_link(data, "Data Completa"),
|
| 227 |
+
unsafe_allow_html=True)
|
| 228 |
+
plot_column(data, selection, nom_var_inv, placeholder)
|
| 229 |
+
|
| 230 |
+
if submit_button:
|
| 231 |
+
plot_column(data_final, selection, nom_var_inv, placeholder)
|
| 232 |
+
|
| 233 |
+
st.markdown(get_table_excel_link(data_final, " Data filtrada"),
|
| 234 |
+
unsafe_allow_html=True)
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
def scraping_localizado():
|
| 239 |
+
button_style()
|
| 240 |
+
data = query_inmob()
|
| 241 |
+
data = transform_df(data)
|
| 242 |
+
precio_uf = get_UF()
|
| 243 |
+
data["valor_uf"] = data["valor_peso"]/float(precio_uf)
|
| 244 |
+
data['predicted_venta_por_m2_UF'] = data['predicted_venta_por_m2']/float(precio_uf)
|
| 245 |
+
nom_var = {"Precio en UF": "valor_uf",
|
| 246 |
+
"Precio en CLP": "valor_peso",
|
| 247 |
+
"Superficie": "superficie",
|
| 248 |
+
"Predicted venta por M2 en CLP": "predicted_venta_por_m2",
|
| 249 |
+
"Predicted venta por M2 en UF": "predicted_venta_por_m2_UF",
|
| 250 |
+
"Predicted arriendo por M2": "predicted_arriendo_por_m2",
|
| 251 |
+
"Predicted yield anual": "predicted_yield_anual"
|
| 252 |
+
}
|
| 253 |
+
nom_var_inv = {v : k for k, v in nom_var.items()}
|
| 254 |
+
var = list(nom_var.keys())
|
| 255 |
+
with st.form(key='my_form'):
|
| 256 |
+
col1, col2, col3, col4 = st.columns((9, 1, 9, 1))
|
| 257 |
+
cols = st.columns((9, 1, 5, 5))
|
| 258 |
+
pre_selection = col1.selectbox("Variable", var)
|
| 259 |
+
selection = nom_var[pre_selection]
|
| 260 |
+
mercado = col3.selectbox("Mercado", ["Venta", "Arriendo", "Todos"])
|
| 261 |
+
banos = col1.slider("Baños", value=(1, 5), min_value=0, max_value=10)
|
| 262 |
+
dormitorios = col3.slider("Dormitorios", value=(1, 5), min_value=0,
|
| 263 |
+
max_value=10)
|
| 264 |
+
com = ["Todas"] + sorted(list(dict.fromkeys(data["Comuna"])))
|
| 265 |
+
comuna = col1.selectbox("Comuna", com)
|
| 266 |
+
zoom = col3.number_input("Zoom", value=12)
|
| 267 |
+
if mercado != "Todos":
|
| 268 |
+
mercado = mercado.lower()
|
| 269 |
+
data_mercado = data[data["mercado"] == mercado]
|
| 270 |
+
else:
|
| 271 |
+
data_mercado = data
|
| 272 |
+
if comuna != "Todas":
|
| 273 |
+
data_mercado = data_mercado[data_mercado["Comuna"] == comuna]
|
| 274 |
+
if len(data_mercado) > 0:
|
| 275 |
+
cifras = len(str(int(max(data_mercado[selection].dropna()))))
|
| 276 |
+
else:
|
| 277 |
+
cifras = 0
|
| 278 |
+
tipo_prop = cols[0].selectbox("Tipo de Propiedad",
|
| 279 |
+
["Todos", "Casa", "Departamento"])
|
| 280 |
+
if tipo_prop != "Todos":
|
| 281 |
+
tipo_prop2 = tipo_prop.lower()
|
| 282 |
+
data_mercado = data_mercado[data_mercado["tipo_propiedad"] == tipo_prop2]
|
| 283 |
+
if cifras > 3:
|
| 284 |
+
corte = 10 ** (cifras - 3)
|
| 285 |
+
cota_final = (int(max(data_mercado[selection].dropna()))//corte+1)*corte
|
| 286 |
+
cota_inf = cols[2].number_input(label="Valor Mínimo",
|
| 287 |
+
min_value=0,
|
| 288 |
+
value=0,
|
| 289 |
+
max_value=cota_final
|
| 290 |
+
)
|
| 291 |
+
cota_sup = cols[3].number_input(label="Valor Máximo",
|
| 292 |
+
min_value=0,
|
| 293 |
+
value=cota_final,
|
| 294 |
+
max_value=cota_final
|
| 295 |
+
)
|
| 296 |
+
else:
|
| 297 |
+
cota_final = max(data_mercado[selection].dropna())+1
|
| 298 |
+
cota_inf = cols[2].number_input(label="Valor Mínimo",
|
| 299 |
+
min_value=0.0,
|
| 300 |
+
value=0.0,
|
| 301 |
+
step=0.1,
|
| 302 |
+
max_value=cota_final
|
| 303 |
+
)
|
| 304 |
+
cota_sup = cols[3].number_input(label="Valor Máximo",
|
| 305 |
+
min_value=0.0,
|
| 306 |
+
step=0.1,
|
| 307 |
+
value=cota_final,
|
| 308 |
+
max_value=cota_final
|
| 309 |
+
)
|
| 310 |
+
|
| 311 |
+
data_final = data_mercado[data_mercado[selection] < cota_sup]
|
| 312 |
+
data_final = data_final[data_final[selection] > cota_inf]
|
| 313 |
+
data_final = data_final[data_final["banos"] > banos[0]]
|
| 314 |
+
data_final = data_final[data_final["banos"] < banos[1]]
|
| 315 |
+
data_final = data_final[data_final["dormitorios"] > dormitorios[0]]
|
| 316 |
+
data_final = data_final[data_final["dormitorios"] < dormitorios[1]]
|
| 317 |
+
st.write('Stats principales del análisis')
|
| 318 |
+
st.write('Valor promedio en UF por metro cuadrado: {:.2f} UF'.format((data_final['valor_uf']/data_final['superficie']).mean()))
|
| 319 |
+
st.write('Superficie promedio: {:.0f} m2'.format(data_final['superficie'].mean()))
|
| 320 |
+
st.write('N° de dormitorios promedio: {:.2f}'.format(data_final['dormitorios'].mean()))
|
| 321 |
+
st.write('N° de baños promedio: {:.2f}'.format(data_final['banos'].mean()))
|
| 322 |
+
|
| 323 |
+
submit_button = st.form_submit_button(label='Actualizar')
|
| 324 |
+
col1, col2 = st.columns((0.65, 1))
|
| 325 |
+
placeholder = st.empty()
|
| 326 |
+
placeholder2 = st.empty()
|
| 327 |
+
placeholder3 = st.empty()
|
| 328 |
+
placeholder2.markdown(get_table_excel_link(data, "Data Completa"),
|
| 329 |
+
unsafe_allow_html=True)
|
| 330 |
+
plot_column2(data, selection, nom_var_inv, placeholder, zoom)
|
| 331 |
+
dist_gamma = stats.gamma.rvs(1, scale=250000, size=2965)
|
| 332 |
+
if submit_button:
|
| 333 |
+
plot_column2(data_final, selection, nom_var_inv, placeholder, zoom)
|
| 334 |
+
st.markdown(get_table_excel_link(data_final, " Data filtrada"),
|
| 335 |
+
unsafe_allow_html=True)
|
| 336 |
+
data_hist = data_final[data_final["mercado"] == "venta"]
|
| 337 |
+
data_hist = data_hist[data_hist["valor_peso"] > 40000000]
|
| 338 |
+
data_hist = data_hist[data_hist["valor_peso"] < 1000000000]["valor_peso"] * 0.2
|
| 339 |
+
fig2 = px.histogram((data_hist), x='valor_peso')
|
| 340 |
+
#placeholder3.plotly_chart(fig2)
|
| 341 |
+
|
| 342 |
+
# streamlit run analisis_inmob.py
|
| 343 |
+
# scraping_localizado()
|
| 344 |
+
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
|
apps/mailer_quant.py
CHANGED
|
@@ -1,3 +1,63 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import email, smtplib, ssl
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
from email import encoders
|
| 4 |
+
from email.mime.base import MIMEBase
|
| 5 |
+
from email.mime.multipart import MIMEMultipart
|
| 6 |
+
from email.mime.text import MIMEText
|
| 7 |
+
import os
|
| 8 |
+
|
| 9 |
+
class Mailer():
|
| 10 |
+
|
| 11 |
+
def __init__(self, subject, body, html, receiver):
|
| 12 |
+
self.subject = subject
|
| 13 |
+
self.body = body
|
| 14 |
+
self.html = html
|
| 15 |
+
self.sender_email = os.environ.get('EMAIL_SENDER')
|
| 16 |
+
self.receiver_email = receiver
|
| 17 |
+
self.password = os.environ.get('EMAIL_PASSWORD')
|
| 18 |
+
self.message = None
|
| 19 |
+
self.create_message()
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def create_message(self, filepath=None, filename=None):
|
| 23 |
+
# Create a multipart message and set headers
|
| 24 |
+
message = MIMEMultipart()
|
| 25 |
+
message["From"] = self.sender_email
|
| 26 |
+
message["To"] = self.receiver_email
|
| 27 |
+
message["Subject"] = self.subject
|
| 28 |
+
message["Bcc"] = self.receiver_email # Recommended for mass emails
|
| 29 |
+
# Add body to email
|
| 30 |
+
if self.html:
|
| 31 |
+
message.attach(MIMEText(self.html, "html"))
|
| 32 |
+
elif self.body:
|
| 33 |
+
message.attach(MIMEText(self.body, "plain"))
|
| 34 |
+
#filename = "test.pdf" # In same directory as script
|
| 35 |
+
# Open PDF file in binary mode
|
| 36 |
+
if filepath and filename:
|
| 37 |
+
with open(filepath, "rb") as attachment:
|
| 38 |
+
# Add file as application/octet-stream
|
| 39 |
+
# Email client can usually download this automatically as attachment
|
| 40 |
+
part = MIMEBase("application", "octet-stream")
|
| 41 |
+
part.set_payload(attachment.read())
|
| 42 |
+
|
| 43 |
+
# Encode file in ASCII characters to send by email
|
| 44 |
+
encoders.encode_base64(part)
|
| 45 |
+
|
| 46 |
+
# Add header as key/value pair to attachment part
|
| 47 |
+
part.add_header(
|
| 48 |
+
"Content-Disposition",
|
| 49 |
+
f"attachment; filename= {filename}",
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
# Add attachment to message and convert message to string
|
| 53 |
+
message.attach(part)
|
| 54 |
+
self.text = message.as_string()
|
| 55 |
+
return
|
| 56 |
+
|
| 57 |
+
def send_message(self, receiver):
|
| 58 |
+
# Log in to server using secure context and send email
|
| 59 |
+
context = ssl.create_default_context()
|
| 60 |
+
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
|
| 61 |
+
server.login(self.sender_email, self.password)
|
| 62 |
+
server.sendmail(self.sender_email, receiver, self.text)
|
| 63 |
+
|
apps/simulacion_vc.py
CHANGED
|
@@ -1,3 +1,1414 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
Created on Tue Sep 21 11:53:13 2021
|
| 5 |
+
|
| 6 |
+
@author: benjaminull
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
import streamlit as st
|
| 11 |
+
import plotly.express as px
|
| 12 |
+
import pandas as pd
|
| 13 |
+
import scipy.stats as stats
|
| 14 |
+
import plotly.express as px
|
| 15 |
+
import scipy.stats as stats
|
| 16 |
+
import plotly.graph_objects as go
|
| 17 |
+
from sqlalchemy import create_engine
|
| 18 |
+
import pybase64 as base64
|
| 19 |
+
import io
|
| 20 |
+
import matplotlib.pyplot as plt
|
| 21 |
+
from io import StringIO
|
| 22 |
+
import pandas as pd
|
| 23 |
+
|
| 24 |
+
@st.cache(allow_output_mutation=True)
|
| 25 |
+
def read_excel(path):
|
| 26 |
+
df = pd.read_excel(path)
|
| 27 |
+
return df
|
| 28 |
+
|
| 29 |
+
@st.cache(allow_output_mutation=True)
|
| 30 |
+
def read_excel2(path):
|
| 31 |
+
df = pd.read_excel(path)
|
| 32 |
+
return df
|
| 33 |
+
|
| 34 |
+
def explorar_data():
|
| 35 |
+
df = read_excel('base_personas.xlsx')
|
| 36 |
+
df2 = read_excel2('base_personas.xlsx')
|
| 37 |
+
data = df.copy()
|
| 38 |
+
data2 = df2.copy()
|
| 39 |
+
l=[]
|
| 40 |
+
|
| 41 |
+
variable = st.selectbox(" ",list(data.columns))
|
| 42 |
+
for i in list(data2.columns):
|
| 43 |
+
if i not in ["FE", "EDAD", variable]:
|
| 44 |
+
try:
|
| 45 |
+
data2[i] = data2[i]* data2["FE"]
|
| 46 |
+
except:
|
| 47 |
+
pass
|
| 48 |
+
col1, col2 = st.beta_columns(2)
|
| 49 |
+
minim = col1.number_input("Edad minima", min_value=0, max_value=105)
|
| 50 |
+
maxim = col2.number_input("Edad maxima", min_value=0, max_value=105, value=105)
|
| 51 |
+
data = data[data["EDAD"] < maxim]
|
| 52 |
+
data = data[data["EDAD"] > minim]
|
| 53 |
+
data2 = data2[data2["EDAD"] < maxim]
|
| 54 |
+
data2 = data2[data2["EDAD"] > minim]
|
| 55 |
+
pond = st.checkbox("Ponderar por FE")
|
| 56 |
+
import plotly.graph_objects as go
|
| 57 |
+
if pond:
|
| 58 |
+
data_f3 = data2.groupby([ variable, "EDAD"]).sum()
|
| 59 |
+
data_f3 = data_f3.loc[:,data_f3.columns[0]].unstack(level=1).replace(np.nan, 0)
|
| 60 |
+
st.write(data_f3)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
fig = go.Figure()
|
| 64 |
+
for i in list(data_f3.index):
|
| 65 |
+
fig.add_trace(go.Scatter(
|
| 66 |
+
x=list(data_f3.columns), y=list(data_f3.loc[i,:]),
|
| 67 |
+
mode='lines',
|
| 68 |
+
line=dict(width=0.5),
|
| 69 |
+
stackgroup='one',
|
| 70 |
+
groupnorm='percent' # sets the normalization for the sum of the stackgroup
|
| 71 |
+
))
|
| 72 |
+
|
| 73 |
+
fig.update_layout(
|
| 74 |
+
showlegend=True,
|
| 75 |
+
xaxis_type='category',
|
| 76 |
+
yaxis=dict(
|
| 77 |
+
type='linear',
|
| 78 |
+
range=[1, 100],
|
| 79 |
+
ticksuffix='%'))
|
| 80 |
+
|
| 81 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 82 |
+
|
| 83 |
+
else:
|
| 84 |
+
data_f = data.groupby([ variable, "EDAD"]).count()
|
| 85 |
+
data_f2 = data_f.loc[:,data_f.columns[0]].unstack(level=1).replace(np.nan, 0)
|
| 86 |
+
st.write(data_f2)
|
| 87 |
+
fig = go.Figure()
|
| 88 |
+
for i in list(data_f2.index):
|
| 89 |
+
fig.add_trace(go.Scatter(
|
| 90 |
+
x=list(data_f2.columns), y=list(data_f2.loc[i,:]),
|
| 91 |
+
mode='lines',
|
| 92 |
+
line=dict(width=0.5),
|
| 93 |
+
stackgroup='one',
|
| 94 |
+
groupnorm='percent' # sets the normalization for the sum of the stackgroup
|
| 95 |
+
))
|
| 96 |
+
|
| 97 |
+
fig.update_layout(
|
| 98 |
+
showlegend=True,
|
| 99 |
+
xaxis_type='category',
|
| 100 |
+
yaxis=dict(
|
| 101 |
+
type='linear',
|
| 102 |
+
range=[1, 100],
|
| 103 |
+
ticksuffix='%'))
|
| 104 |
+
|
| 105 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
# pr = data_f2.profile_report()
|
| 109 |
+
|
| 110 |
+
# st_profile_report(data_f2)
|
| 111 |
+
|
| 112 |
+
def transform_df(scraping_df):
|
| 113 |
+
# Extract numbers from string
|
| 114 |
+
# Change datatype
|
| 115 |
+
# Add 'Comuna' and 'Región'
|
| 116 |
+
scraping_df[["Comuna"]] = scraping_df[[
|
| 117 |
+
"direccion"]].applymap(lambda x: get_comuna(x))
|
| 118 |
+
# Scrap UF value for date
|
| 119 |
+
#scraping_df[["Valor UF"]] = get_UF()
|
| 120 |
+
return scraping_df
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def get_table_excel_link(df, name):
|
| 124 |
+
towrite = io.BytesIO()
|
| 125 |
+
downloaded_file = df.to_excel(towrite, encoding='utf-8', index=False,
|
| 126 |
+
header=True)
|
| 127 |
+
towrite.seek(0) # reset pointer
|
| 128 |
+
file_name = 'Data' + name + '.xlsx'
|
| 129 |
+
style = 'style="color:black;text-decoration: none; font-size:18px;"'
|
| 130 |
+
name_mark = "Descargar " + name + ".xlsx"
|
| 131 |
+
b64 = base64.b64encode(towrite.read()).decode() # some strings
|
| 132 |
+
linko = f'<center><a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" ' + \
|
| 133 |
+
style+'download="'+file_name+'"><button>'+name_mark+'</button></a></center>'
|
| 134 |
+
return linko
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def get_comuna(direction):
|
| 138 |
+
values = direction.split(',')
|
| 139 |
+
return values[-2]
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def formatnum(numero):
|
| 143 |
+
'''
|
| 144 |
+
Esta función permite dar formato a los montos de saldo y valor cuota en
|
| 145 |
+
las cartolas.
|
| 146 |
+
'''
|
| 147 |
+
return '{:,.0f}'.format(numero).replace(",", "@").replace(".", ",").replace("@", ".")
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def sim_norm():
|
| 151 |
+
with st.form(key='my_form'):
|
| 152 |
+
col1, col2 = st.beta_columns(2)
|
| 153 |
+
sim = col1.number_input("Nº Simulaciones", min_value=1, value=100)
|
| 154 |
+
vc = col2.number_input("Cuota inicial", min_value=100)
|
| 155 |
+
col1, col2, col3 = st.beta_columns(3)
|
| 156 |
+
mu = col1.number_input("µ Fondo Arriesgado", value=0.1)
|
| 157 |
+
sigma = col1.number_input("σ Fondo Arriesgado", value=0.1)
|
| 158 |
+
mu2 = col2.number_input("µ Fondo Intermedio ", value=0.05)
|
| 159 |
+
sigma2 = col2.number_input("σ Fondo Intermedio", value=0.05)
|
| 160 |
+
mu3 = col3.number_input("µ Fondo Conservador", value=-0.01)
|
| 161 |
+
sigma3 = col3.number_input("σ Fondo Conservador", value=0.03)
|
| 162 |
+
# t= col1.number_input("Periodo", value=288)
|
| 163 |
+
# t2 = col2.number_input("Periodo ", value=120)
|
| 164 |
+
# t3 = col3.number_input("Periodo ", value=72)
|
| 165 |
+
values = st.slider(
|
| 166 |
+
'Seleccione los años de cambio de fondo', 0, 40, (33, 38))
|
| 167 |
+
with st.beta_expander("Ajustar parámetros de distribucion de permanencia del cliente (gamma)"):
|
| 168 |
+
col1, col2 = st.beta_columns(2)
|
| 169 |
+
alpha = col1.number_input("alpha", value=1.5)
|
| 170 |
+
beta = col2.number_input("lambda", value=71.1)
|
| 171 |
+
submit_button = st.form_submit_button(label='Actualizar')
|
| 172 |
+
if submit_button:
|
| 173 |
+
t = values[0]*12
|
| 174 |
+
t2 = values[1]*12-t
|
| 175 |
+
t3 = 480-t2-t
|
| 176 |
+
mu = mu / 12
|
| 177 |
+
mu2 = mu2 / 12
|
| 178 |
+
mu3 = mu3 / 12
|
| 179 |
+
sigma = sigma / (12**(1/2))
|
| 180 |
+
sigma2 = sigma2 / (12**(1/2))
|
| 181 |
+
sigma3 = sigma3 / (12**(1/2))
|
| 182 |
+
var_al = np.random.normal(mu, sigma, size=(t, sim))
|
| 183 |
+
var_al2 = np.random.normal(mu2, sigma2, size=(t2, sim))
|
| 184 |
+
var_al3 = np.random.normal(mu3, sigma3, size=(t3, sim))
|
| 185 |
+
simulacion = np.zeros((t + t2 + t3, sim))
|
| 186 |
+
simulacion[0, :] = vc
|
| 187 |
+
dist_gamma = stats.gamma.rvs(alpha, scale=beta, size=sim).astype(int)+1
|
| 188 |
+
for i in range(1, t):
|
| 189 |
+
simulacion[i, :] = simulacion[i - 1, :] * (1 + var_al[i-1, :])
|
| 190 |
+
for i in range(t, t+t2):
|
| 191 |
+
simulacion[i, :] = simulacion[i - 1, :] * (1 + var_al2[t-i-1, :])
|
| 192 |
+
for i in range(t+t2, t+t2+t3):
|
| 193 |
+
simulacion[i, :] = simulacion[i - 1, :] * \
|
| 194 |
+
(1 + var_al3[t2+t-i-1, :])
|
| 195 |
+
retornos = np.zeros(sim)
|
| 196 |
+
for j in range(sim):
|
| 197 |
+
ingreso = 480-dist_gamma[j]
|
| 198 |
+
simulacion[0:ingreso, j] = None
|
| 199 |
+
simulacion[ingreso:480, j] = simulacion[ingreso:480, j] * \
|
| 200 |
+
vc/simulacion[ingreso, j]
|
| 201 |
+
retorno = (simulacion[-1, j]/simulacion[ingreso, j]
|
| 202 |
+
)**(1/(dist_gamma[j]/12))-1
|
| 203 |
+
retornos[j] = retorno
|
| 204 |
+
df = pd.DataFrame(simulacion)
|
| 205 |
+
df["meses"] = list(df.index)
|
| 206 |
+
fig = px.line(df, x="meses", y=df.columns,
|
| 207 |
+
title='Simulaciones')
|
| 208 |
+
fig.layout.update(xaxis_rangeslider_visible=True)
|
| 209 |
+
fig.add_vline(x=t, line_width=3, line_dash="dash", line_color="grey")
|
| 210 |
+
fig.add_vline(x=t+t2, line_width=3,
|
| 211 |
+
line_dash="dash", line_color="grey")
|
| 212 |
+
fig.add_vrect(x0=0, x1=t, annotation_text="Arries",
|
| 213 |
+
annotation_position="top",
|
| 214 |
+
fillcolor="red", opacity=0.15, line_width=0)
|
| 215 |
+
fig.add_vrect(x0=t, x1=t+t2,
|
| 216 |
+
annotation_text="Inter", annotation_position="top",
|
| 217 |
+
fillcolor="midnightblue", opacity=0.15, line_width=0)
|
| 218 |
+
fig.add_vrect(x0=t + t2, x1=t + t2 + t3,
|
| 219 |
+
annotation_text="Cons", annotation_position="top",
|
| 220 |
+
fillcolor="seagreen", opacity=0.15, line_width=0)
|
| 221 |
+
fig.update_layout(height=600, width=950)
|
| 222 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 223 |
+
st.subheader("Distribución de duracion de clientes")
|
| 224 |
+
df_in = pd.DataFrame(dist_gamma//12, columns=["ingreso"])
|
| 225 |
+
fig = px.histogram(df_in, x="ingreso", nbins=40)
|
| 226 |
+
fig.add_vline(x=(dist_gamma//12).mean(), line_width=3,
|
| 227 |
+
line_dash="dash", line_color="midnightblue")
|
| 228 |
+
col1, col2 = st.beta_columns((3, 1))
|
| 229 |
+
col1.plotly_chart(fig, use_container_width=True)
|
| 230 |
+
col2.title(" ")
|
| 231 |
+
col2.header("µ = "+str((dist_gamma//12).mean())[0:4] + " años")
|
| 232 |
+
col2.subheader("σ = "+str((dist_gamma//12).std())[0:4] + " años")
|
| 233 |
+
st.subheader("Distribución de retorno anual")
|
| 234 |
+
col1, col2 = st.beta_columns((3, 1))
|
| 235 |
+
df_ret = pd.DataFrame(retornos, columns=["retornos"])
|
| 236 |
+
col2.title(" ")
|
| 237 |
+
col2.header("µ = "+str((retornos.mean()*100))[0:4] + "%")
|
| 238 |
+
col2.subheader("σ = "+str((retornos.std())*100)[0:4] + "%")
|
| 239 |
+
fig2 = px.histogram(df_ret, x="retornos", nbins=50)
|
| 240 |
+
retorno_fc = (1.053)*(1.0312)-1
|
| 241 |
+
if retornos.mean() > 0.0312:
|
| 242 |
+
posicion1 = "top right"
|
| 243 |
+
posicion2 = "top left"
|
| 244 |
+
else:
|
| 245 |
+
posicion2 = "top right"
|
| 246 |
+
posicion1 = "top left"
|
| 247 |
+
fig2.add_vline(x=retornos.mean(), line_width=3, line_dash="dash",
|
| 248 |
+
line_color="midnightblue", annotation_font_color="midnightblue",
|
| 249 |
+
annotation_position=posicion1,
|
| 250 |
+
annotation_text=str(round(retornos.mean()*100, 1))+"%")
|
| 251 |
+
fig2.add_vline(x=0.0312, line_width=3, line_dash="dash",
|
| 252 |
+
annotation_font_color="red",
|
| 253 |
+
annotation_position=posicion2,
|
| 254 |
+
line_color="red", annotation_text="3,12%")
|
| 255 |
+
fig2.add_vline(x=retorno_fc, line_width=3, line_dash="dash",
|
| 256 |
+
annotation_font_color="green",
|
| 257 |
+
annotation_position=posicion2,
|
| 258 |
+
line_color="green", annotation_text=str(round(retorno_fc, 2)*100)+"%")
|
| 259 |
+
fig2.add_vline(x=0.00, line_width=3, line_dash="dash",
|
| 260 |
+
line_color="yellow")
|
| 261 |
+
col1.plotly_chart(fig2, use_container_width=True)
|
| 262 |
+
col1, col2 = st.beta_columns((1, 8))
|
| 263 |
+
col2.write(str(round(sum(df_ret["retornos"] > 0.00)/len(df_ret)*100, 0)) +
|
| 264 |
+
"%: Probabilidad de que un clientes tenga retorno mayor a 0%")
|
| 265 |
+
col2.write(str(round(sum(df_ret["retornos"] > 0.0312)/len(df_ret)*100, 0)) +
|
| 266 |
+
"%: Probabilidad de que un clientes tenga un retorno mayor a 3,12% (Inflación)")
|
| 267 |
+
col2.write(str(round(sum(df_ret["retornos"] > retorno_fc)/len(df_ret)*100, 0)) +
|
| 268 |
+
"%: Probabilidad de que un clientes tenga retorno mayor a "+str(round(retorno_fc, 2)*100)+"% (Fondo C)")
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
def sim_2():
|
| 272 |
+
with st.form(key='my_form'):
|
| 273 |
+
col1, col2 = st.beta_columns(2)
|
| 274 |
+
sim = col1.number_input("Nº Simulaciones", min_value=1, value=100)
|
| 275 |
+
vc = col2.number_input("Cuota inicial", min_value=100)
|
| 276 |
+
col1, col2, col3 = st.beta_columns(3)
|
| 277 |
+
mu = col1.number_input("µ Fondo Arriesgado", value=0.1)
|
| 278 |
+
sigma = col1.number_input("σ Fondo Arriesgado", value=0.1)
|
| 279 |
+
mu2 = col2.number_input("µ Fondo Intermedio ", value=0.05)
|
| 280 |
+
sigma2 = col2.number_input("σ Fondo Intermedio", value=0.05)
|
| 281 |
+
mu3 = col3.number_input("µ Fondo Conservador", value=-0.01)
|
| 282 |
+
sigma3 = col3.number_input("σ Fondo Conservador", value=0.03)
|
| 283 |
+
values = st.slider('Seleccione los años de cambio de fondo', 0, 40,
|
| 284 |
+
(33, 38))
|
| 285 |
+
with st.beta_expander("Ajustar parámetros de distribucion de permanencia del cliente (gamma)"):
|
| 286 |
+
col1, col2 = st.beta_columns(2)
|
| 287 |
+
alpha = col1.number_input("alpha", value=1.5)
|
| 288 |
+
beta = col2.number_input("lambda", value=71.1)
|
| 289 |
+
submit_button = st.form_submit_button(label='Actualizar')
|
| 290 |
+
if submit_button:
|
| 291 |
+
t = values[0]*12
|
| 292 |
+
t2 = values[1]*12-t
|
| 293 |
+
t3 = 480-t2-t
|
| 294 |
+
mu = mu / 12
|
| 295 |
+
mu2 = mu2 / 12
|
| 296 |
+
mu3 = mu3 / 12
|
| 297 |
+
sigma = sigma / (12 ** (1/2))
|
| 298 |
+
sigma2 = sigma2 / (12 ** (1/2))
|
| 299 |
+
sigma3 = sigma3 / (12 ** (1/2))
|
| 300 |
+
var_al = np.random.normal(mu, sigma, size=(t, sim))
|
| 301 |
+
var_al2 = np.random.normal(mu2, sigma2, size=(t2, sim))
|
| 302 |
+
var_al3 = np.random.normal(mu3, sigma3, size=(t3, sim))
|
| 303 |
+
simulacion = np.zeros((t + t2 + t3, sim))
|
| 304 |
+
simulacion[0, :] = vc
|
| 305 |
+
dist_gamma = stats.gamma.rvs(alpha, scale=beta, size=sim).astype(int)+1
|
| 306 |
+
for i in range(1, t):
|
| 307 |
+
simulacion[i, :] = simulacion[i - 1, :] * (1 + var_al[i-1, :])
|
| 308 |
+
for i in range(t, t+t2):
|
| 309 |
+
simulacion[i, :] = simulacion[i - 1, :] * (1 + var_al2[t-i-1, :])
|
| 310 |
+
for i in range(t+t2, t+t2+t3):
|
| 311 |
+
simulacion[i, :] = simulacion[i - 1, :] * \
|
| 312 |
+
(1 + var_al3[t2+t-i-1, :])
|
| 313 |
+
retornos = np.zeros(sim)
|
| 314 |
+
for j in range(sim):
|
| 315 |
+
ingreso = 480-dist_gamma[j]
|
| 316 |
+
simulacion[0:ingreso, j] = None
|
| 317 |
+
simulacion[ingreso:480, j] = simulacion[ingreso:480, j] * \
|
| 318 |
+
vc/simulacion[ingreso, j]
|
| 319 |
+
retorno = (simulacion[-1, j]/simulacion[ingreso, j]
|
| 320 |
+
)**(1/(dist_gamma[j]/12))-1
|
| 321 |
+
retornos[j] = retorno
|
| 322 |
+
df = pd.DataFrame(simulacion)
|
| 323 |
+
df["meses"] = list(df.index)
|
| 324 |
+
fig = px.line(df, x="meses", y=df.columns,
|
| 325 |
+
title='Simulaciones')
|
| 326 |
+
fig.layout.update(xaxis_rangeslider_visible=True)
|
| 327 |
+
fig.add_vline(x=t, line_width=3, line_dash="dash", line_color="grey")
|
| 328 |
+
fig.add_vline(x=t+t2, line_width=3, line_dash="dash",
|
| 329 |
+
line_color="grey")
|
| 330 |
+
fig.add_vrect(x0=0, x1=t, annotation_text="Arries",
|
| 331 |
+
annotation_position="top",
|
| 332 |
+
fillcolor="red", opacity=0.15, line_width=0)
|
| 333 |
+
fig.add_vrect(x0=t, x1=t+t2,
|
| 334 |
+
annotation_text="Inter", annotation_position="top",
|
| 335 |
+
fillcolor="midnightblue", opacity=0.15, line_width=0)
|
| 336 |
+
fig.add_vrect(x0=t + t2, x1=t + t2 + t3,
|
| 337 |
+
annotation_text="Cons", annotation_position="top",
|
| 338 |
+
fillcolor="seagreen", opacity=0.15, line_width=0)
|
| 339 |
+
fig.update_layout(height=600, width=950)
|
| 340 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 341 |
+
sigma_sim1 = np.random.normal(sigma, 0.009, size=480)
|
| 342 |
+
sigma_sim2 = np.random.normal(sigma2, 0.004, size=480)
|
| 343 |
+
sigma_sim3 = np.random.normal(sigma3, 0.001, size=480)
|
| 344 |
+
sigma_comb = np.zeros(480)
|
| 345 |
+
sigma_comb[0:t] = sigma_sim1[0:t]
|
| 346 |
+
sigma_comb[t:t+t2] = sigma_sim2[t:t+t2]
|
| 347 |
+
sigma_comb[t+t2:480] = sigma_sim3[t+t2:480]
|
| 348 |
+
sigma_comb2 = np.zeros(480)
|
| 349 |
+
retorno_comb = np.zeros(480)
|
| 350 |
+
for i in range(t):
|
| 351 |
+
sigma_comb2[i] = sigma_sim1[i] * (1-i/t) + sigma_sim2[i] * i/t
|
| 352 |
+
retorno_comb[i] = mu * (1-i/t) + mu2 * i/t
|
| 353 |
+
for j in range(480-t):
|
| 354 |
+
sigma_comb2[t + j] = sigma_sim2[t + j] * \
|
| 355 |
+
(1-j/(480-t)) + sigma_sim3[t + j] * j/(480-t)
|
| 356 |
+
retorno_comb[i] = mu2 * (1-j/(480-t)) + mu3 * j/(480-t)
|
| 357 |
+
dfsig = pd.DataFrame(sigma_sim1, columns=["sig"])
|
| 358 |
+
dfsig["mes"] = list(dfsig.index)
|
| 359 |
+
dfsig["sigma inter"] = sigma_sim2
|
| 360 |
+
dfsig["sigma cons"] = sigma_sim3
|
| 361 |
+
dfsig["sigma por periodos"] = sigma_comb
|
| 362 |
+
dfsig["sigma combinacion lineal"] = sigma_comb2
|
| 363 |
+
dfsig["sigma combinacion lineal"] = dfsig["sigma combinacion lineal"].abs()
|
| 364 |
+
var_al_comb = np.zeros(480)
|
| 365 |
+
patr_al_comb = np.zeros(480)
|
| 366 |
+
patr_al_comb[0] = vc
|
| 367 |
+
for i in range(1, 480):
|
| 368 |
+
var_al_comb[i] = np.random.normal(
|
| 369 |
+
retorno_comb[i],
|
| 370 |
+
dfsig["sigma combinacion lineal"].iloc[i],
|
| 371 |
+
size=1)
|
| 372 |
+
patr_al_comb[i] = patr_al_comb[i-1]*(1 + var_al_comb[i-1])
|
| 373 |
+
ingreso = 480-dist_gamma[0]
|
| 374 |
+
|
| 375 |
+
data_comb = pd.DataFrame(patr_al_comb, columns=["Precio"])
|
| 376 |
+
data_comb["mes"] = list(data_comb.index)
|
| 377 |
+
data_comb = data_comb[data_comb["mes"] >= ingreso]
|
| 378 |
+
data_comb["Precio"] = data_comb["Precio"]/data_comb.iloc[0]["Precio"]
|
| 379 |
+
fig2 = px.line(dfsig, x='mes', y=dfsig.columns,
|
| 380 |
+
title='Simulaciones')
|
| 381 |
+
st.plotly_chart(fig2)
|
| 382 |
+
fig3 = px.line(data_comb, x='mes', y=data_comb.columns,
|
| 383 |
+
title='Simulaciones')
|
| 384 |
+
st.plotly_chart(fig3)
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
def sim_inmob():
|
| 388 |
+
url = """postgresql://tbgxsndupdarfp:5578576bc884e31a4f7e117a66a9dad8b13917e6a5262d85ff20f1f69cb4bf49@ec2-52-205-45-219.compute-1.amazonaws.com:5432/db5ktai215krcv"""
|
| 389 |
+
engine = create_engine(url, echo=False)
|
| 390 |
+
data = pd.read_sql_query("SELECT * FROM Scraping_inmob", con=engine)
|
| 391 |
+
data = transform_df(data)
|
| 392 |
+
col1, col2 = st.beta_columns((0.65, 1))
|
| 393 |
+
placeholder = st.empty()
|
| 394 |
+
placeholder2 = st.empty()
|
| 395 |
+
placeholder3 = st.empty()
|
| 396 |
+
placeholder4 = st.empty()
|
| 397 |
+
dist_gamma = stats.gamma.rvs(1, scale=250000, size=2965)
|
| 398 |
+
dist_norm = np.random.normal(734874, 1250, size=2965)
|
| 399 |
+
data_hist = data[data["mercado"] == "venta"]
|
| 400 |
+
data_hist = data_hist[data_hist["valor_peso"]
|
| 401 |
+
< 400000000]["valor_peso"] * 0.2
|
| 402 |
+
fig2 = go.Figure()
|
| 403 |
+
fig3 = go.Figure()
|
| 404 |
+
fig4 = go.Figure()
|
| 405 |
+
fig2.add_trace(go.Histogram(x=dist_norm, name='Dist Ingreso'))
|
| 406 |
+
# fig2.add_vline(x=data_hist.mean(), line_width=3, line_dash="dash", line_color="darkred")
|
| 407 |
+
# fig2.add_vline(x=dist_gamma.mean(), line_width=3, line_dash="dash", line_color="darkblue")
|
| 408 |
+
fig3.add_trace(go.Histogram(x=data_hist, name='Data real'))
|
| 409 |
+
a = sorted(data_hist)
|
| 410 |
+
b = sorted(dist_norm)
|
| 411 |
+
dist_periodo = [(x)/y for x, y in zip(a, b)]
|
| 412 |
+
dist_periodo = [i for i in dist_periodo if i < 480]
|
| 413 |
+
fig4.add_trace(go.Histogram(x=dist_periodo, name='Dist periodo'))
|
| 414 |
+
# Overlay both histograms
|
| 415 |
+
# fig2.update_layout(barmode='overlay')
|
| 416 |
+
# Reduce opacity to see both histograms
|
| 417 |
+
fig2.update_traces(opacity=0.75)
|
| 418 |
+
#fig2 = px.histogram((data_hist), x='valor_peso', color_discrete_sequence=['indianred'])
|
| 419 |
+
placeholder2.plotly_chart(fig2, use_container_width=True)
|
| 420 |
+
placeholder.subheader("µ Capacidad de ahorro: $" +
|
| 421 |
+
formatnum(dist_norm.mean()))
|
| 422 |
+
placeholder4.plotly_chart(fig3, use_container_width=True)
|
| 423 |
+
placeholder3.subheader("µ Pie vivienda: $" + formatnum(data_hist.mean()))
|
| 424 |
+
st.plotly_chart(fig4, use_container_width=True)
|
| 425 |
+
st.subheader("µ Period: " + formatnum(np.array(dist_periodo).mean()))
|
| 426 |
+
df = pd.DataFrame([a, b, dist_periodo])
|
| 427 |
+
df2 = df.T
|
| 428 |
+
st.markdown(get_table_excel_link(df2[df2[2] < 480], "Distribucion"),
|
| 429 |
+
unsafe_allow_html=True)
|
| 430 |
+
data_hist = data[data["mercado"] == "venta"]
|
| 431 |
+
data_hist = data_hist[data_hist["valor_peso"] > 40000000]
|
| 432 |
+
data_hist = data_hist[data_hist["valor_peso"]
|
| 433 |
+
< 1000000000]["valor_peso"] * 0.2
|
| 434 |
+
fig2 = px.histogram((data_hist), x='valor_peso')
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
def sim_ingreso_clientes():
|
| 438 |
+
with st.form(key='my_form'):
|
| 439 |
+
col1, col2 = st.beta_columns(2)
|
| 440 |
+
clientes1 = col1.number_input("Clientes nuevos año 1", value=1250)
|
| 441 |
+
clientes2 = col2.number_input("Clientes nuevos año 2", value=6750)
|
| 442 |
+
clientes3 = col1.number_input("Clientes nuevos año 3", value=17000)
|
| 443 |
+
clientes4 = col2.number_input("Clientes nuevos año 4", value=17000)
|
| 444 |
+
clientes5 = col1.number_input("Clientes nuevos año 5", value=8000)
|
| 445 |
+
col1, col2 = st.beta_columns(2)
|
| 446 |
+
cap_ahorro = col1.number_input("Capacidad de ahorro", 735000)
|
| 447 |
+
de_cap = col2.number_input("Desviacion estandar C.A.", 1250)
|
| 448 |
+
submit_button = st.form_submit_button(label='Actualizar')
|
| 449 |
+
if submit_button:
|
| 450 |
+
clientesm1 = clientes1/12
|
| 451 |
+
clientesm2 = clientes2/12
|
| 452 |
+
clientesm3 = clientes3/12
|
| 453 |
+
clientesm4 = clientes4/12
|
| 454 |
+
clientesm5 = clientes5/12
|
| 455 |
+
porc_mult = 0.46
|
| 456 |
+
porc_cp = 0.19
|
| 457 |
+
porc_lp = 0.35
|
| 458 |
+
inmob = np.zeros(60)
|
| 459 |
+
a = np.zeros(60)
|
| 460 |
+
b = np.zeros(60)
|
| 461 |
+
c = np.zeros(60)
|
| 462 |
+
cp = np.zeros(60)
|
| 463 |
+
lp = np.zeros(60)
|
| 464 |
+
inmob[0] = int(clientesm1 * porc_mult)
|
| 465 |
+
cp[0] = int(clientesm1 * porc_cp)
|
| 466 |
+
lp[0] = int(clientesm1 * porc_lp)
|
| 467 |
+
for i in range(1, 60):
|
| 468 |
+
if i < 12:
|
| 469 |
+
inmob[i] =int( clientesm1 * porc_mult + inmob[i-1])
|
| 470 |
+
cp[i] = int(clientesm1 * porc_cp + cp[i-1])
|
| 471 |
+
lp[i] = int(clientesm1 * porc_lp + lp[i-1])
|
| 472 |
+
a[i] = cp[i]
|
| 473 |
+
b[i] = lp[i]
|
| 474 |
+
c[i] = inmob[i]
|
| 475 |
+
elif i < 24:
|
| 476 |
+
inmob[i] = int(clientesm2 * porc_mult + inmob[i-1])
|
| 477 |
+
cp[i] = int(clientesm2 * porc_cp + cp[i-1]) + clientesm1 * porc_cp*0.8
|
| 478 |
+
lp[i] = int(clientesm2 * porc_lp + lp[i-1])
|
| 479 |
+
a[i] = cp[i]
|
| 480 |
+
b[i] = lp[i] + c[i-12]
|
| 481 |
+
c[i] = inmob[i] - c[i-12]
|
| 482 |
+
elif i < 36:
|
| 483 |
+
inmob[i] = int(clientesm3 * porc_mult + inmob[i-1])
|
| 484 |
+
cp[i] = int(clientesm3 * porc_cp + cp[i-1]) + clientesm2 * porc_cp*0.8
|
| 485 |
+
lp[i] = int(clientesm3 * porc_lp + lp[i-1])
|
| 486 |
+
a[i] = cp[i]
|
| 487 |
+
b[i] = lp[i] + c[i-24] + c[i-12]
|
| 488 |
+
c[i] = inmob[i] - c[i-24] - c[i-12]
|
| 489 |
+
elif i < 48:
|
| 490 |
+
inmob[i] = int(clientesm4 * porc_mult + inmob[i-1])
|
| 491 |
+
cp[i] = int(clientesm4 * porc_cp + cp[i-1]) - clientesm3 * porc_cp*0.8
|
| 492 |
+
lp[i] = int(clientesm4 * porc_lp + lp[i-1])
|
| 493 |
+
a[i] = cp[i] + c[i-36]
|
| 494 |
+
b[i] = lp[i] + c[i-24] + c[i-12]
|
| 495 |
+
c[i] = inmob[i] - c[i-24] - c[i-12] - c[i-36]
|
| 496 |
+
elif i < 60:
|
| 497 |
+
inmob[i] = int(clientesm5 * porc_mult + inmob[i-1])
|
| 498 |
+
cp[i] = int(clientesm5 * porc_cp + cp[i-1]) + clientesm4 * porc_cp*0.8
|
| 499 |
+
lp[i] = int(clientesm5 * porc_lp + lp[i-1])
|
| 500 |
+
a[i] = cp[i] + c[i-36]
|
| 501 |
+
b[i] = lp[i] + c[i-24] + c[i-12]
|
| 502 |
+
c[i] = inmob[i] - c[i-24] - c[i-12] - c[i-36] - c[i-48]
|
| 503 |
+
|
| 504 |
+
inmob_res = np.zeros(60)
|
| 505 |
+
cp_res = np.zeros(60)
|
| 506 |
+
lp_res = np.zeros(60)
|
| 507 |
+
a_res = np.zeros(60)
|
| 508 |
+
b_res = np.zeros(60)
|
| 509 |
+
c_res = np.zeros(60)
|
| 510 |
+
for i in range(1, 60):
|
| 511 |
+
if i<12:
|
| 512 |
+
pass
|
| 513 |
+
elif i < 24:
|
| 514 |
+
cp_res[i] = - clientes1 * porc_cp*0.2
|
| 515 |
+
b_res[i] = clientes1 * porc_mult
|
| 516 |
+
c_res[i] = -clientes1 * porc_mult
|
| 517 |
+
elif i < 36:
|
| 518 |
+
cp_res[i] = - clientes2 * porc_cp * 0.2
|
| 519 |
+
b_res[i] = clientes2 * porc_mult
|
| 520 |
+
c_res[i] = -clientes2 * porc_mult
|
| 521 |
+
elif i < 48:
|
| 522 |
+
cp_res[i] = - clientes3 * porc_cp * 0.2
|
| 523 |
+
a_res[i] = clientes1 * porc_mult * 3
|
| 524 |
+
b_res[i] = clientes3 * porc_mult - clientes1 * 3 * porc_mult
|
| 525 |
+
c_res[i] = -clientes3 * porc_mult
|
| 526 |
+
elif i < 60:
|
| 527 |
+
cp_res[i] = - clientes4 * porc_mult * 0.2
|
| 528 |
+
a_res[i] = clientes2 * 3 *porc_mult
|
| 529 |
+
b_res[i] = clientes3 * porc_mult - clientes2 * 3 *porc_mult
|
| 530 |
+
c_res[i] = -clientes3 * porc_mult
|
| 531 |
+
st.write(cp-cp_res)
|
| 532 |
+
inmob[0] = int(clientesm1 * porc_mult)
|
| 533 |
+
cp[0] = int(clientesm1 * porc_cp)
|
| 534 |
+
lp[0] = int(clientesm1 * porc_lp)
|
| 535 |
+
anual = np.zeros((5,4))
|
| 536 |
+
anual_aum = np.zeros((5,4))
|
| 537 |
+
for i in range(5):
|
| 538 |
+
anual[i, 0] = int(sum(a[i*12:(i+1)*12]))
|
| 539 |
+
anual[i, 1] = int(sum(b[i*12:(i+1)*12]))
|
| 540 |
+
anual[i, 2] = int((sum(c[i*12:(i+1)*12])))
|
| 541 |
+
anual[:,3] = anual[:,0] + anual[:,1] + anual[:,2]
|
| 542 |
+
for i in range(5):
|
| 543 |
+
anual_aum[i, 0] = sum(((a - a_res)*cap_ahorro)[0:(i+1)*12])
|
| 544 |
+
anual_aum[i, 1] = sum(((b - b_res)*cap_ahorro)[0:(i+1)*12])
|
| 545 |
+
anual_aum[i, 2] = sum(((c - c_res)*cap_ahorro)[0:(i+1)*12])
|
| 546 |
+
anual_aum[:,3] = anual_aum[:,0] + anual_aum[:,1] + anual_aum[:,2]
|
| 547 |
+
data = pd.DataFrame([cp, lp, inmob, (cp - cp_res)*cap_ahorro, lp*cap_ahorro,
|
| 548 |
+
(inmob - inmob_res)*cap_ahorro])
|
| 549 |
+
|
| 550 |
+
anual[:,3] = anual[:,0] + anual[:,1] + anual[:,2]
|
| 551 |
+
cambios = np.zeros(5)
|
| 552 |
+
cambios[0] = 0
|
| 553 |
+
cambios[1] = int(clientes1 * porc_mult)
|
| 554 |
+
cambios[2] = int(clientes2* porc_mult)
|
| 555 |
+
cambios[3] = int((clientes3 + clientes1)* porc_mult)
|
| 556 |
+
cambios[4] = int((clientes2 + clientes4) * porc_mult)
|
| 557 |
+
retiros = np.zeros(5)
|
| 558 |
+
retiros[0] = 0
|
| 559 |
+
retiros[1] = int(clientes1 * porc_cp)
|
| 560 |
+
retiros[2] = int(clientes2 * porc_cp)
|
| 561 |
+
retiros[3] = int(clientes3 * porc_cp)
|
| 562 |
+
retiros[4] = int(clientes4 * porc_cp +clientes1 * porc_cp*porc_mult)
|
| 563 |
+
clientes_a = np.zeros(5)
|
| 564 |
+
clientes_b = np.zeros(5)
|
| 565 |
+
clientes_c = np.zeros(5)
|
| 566 |
+
clientes_a[0] = int(clientes1 * porc_cp)
|
| 567 |
+
clientes_b[0] = int(clientes1 * porc_lp)
|
| 568 |
+
clientes_c[0] = int(clientes1 * porc_mult)
|
| 569 |
+
|
| 570 |
+
clientes_a[1] = int(clientes2 * porc_cp + clientes1 * porc_cp * 0.8)
|
| 571 |
+
clientes_b[1] = int(clientes1 * porc_lp + clientes2 * porc_lp + clientes1 * porc_mult)
|
| 572 |
+
clientes_c[1] = int(clientes2 * porc_mult)
|
| 573 |
+
|
| 574 |
+
clientes_a[2] = int(clientes3 * porc_cp + clientes2 * porc_cp * 0.8 + clientes1 * porc_cp * 0.8)
|
| 575 |
+
clientes_b[2] = int(clientes_b[1] + clientes2 * porc_mult + clientes3 * porc_lp )
|
| 576 |
+
clientes_c[2] = int(clientes3 * porc_mult)
|
| 577 |
+
|
| 578 |
+
clientes_a[3] = int(clientes4 * porc_cp + clientes1 * porc_mult + clientes2 * porc_cp * 0.8 + clientes1 * porc_cp * 0.8 + clientes3 * porc_cp * 0.8)
|
| 579 |
+
clientes_b[3] = int(clientes_b[2] - clientes1 * porc_mult + clientes3 * porc_mult + clientes4 * porc_lp)
|
| 580 |
+
clientes_c[3] = int(clientes4 * porc_mult)
|
| 581 |
+
|
| 582 |
+
clientes_a[4] = int(clientes5 * porc_cp + clientes1 * porc_mult + clientes2 * porc_mult + clientes4 *0.8* porc_cp + clientes2 * porc_cp * 0.8 + clientes1 * porc_cp * 0.8 + clientes3 * porc_cp * 0.8)
|
| 583 |
+
clientes_b[4] = int(clientes_b[3] - clientes2 * porc_mult + clientes4 * porc_mult + clientes5 * porc_lp )
|
| 584 |
+
clientes_c[4] = int(clientes5 * porc_mult)
|
| 585 |
+
|
| 586 |
+
|
| 587 |
+
|
| 588 |
+
data2 = pd.DataFrame(anual, columns = ["Depositos a", "Depositos b", "Depositos c", "Dep Total"])
|
| 589 |
+
data3 = pd.DataFrame(anual_aum, columns = ["a AUM", "b AUM", "c Aum", "Aum Total"])
|
| 590 |
+
data4 = pd.DataFrame([a,b,c])
|
| 591 |
+
st.write(data4)
|
| 592 |
+
data = data.T
|
| 593 |
+
data4 = data4.T
|
| 594 |
+
data4.columns = ["Fondo A", "Fondo B", "Fondo C"]
|
| 595 |
+
data3["Cambios"] = cambios
|
| 596 |
+
data3["Retiros"] = retiros
|
| 597 |
+
data3["Clientes a"] = clientes_a
|
| 598 |
+
data3["Clientes b"] = clientes_b
|
| 599 |
+
data3["Clientes c"] = clientes_c
|
| 600 |
+
data3["Dep totales"] = data2["Dep Total"]
|
| 601 |
+
fig = px.line(data4, x=data4.index, y=data4._)
|
| 602 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 603 |
+
st.write(data3.T)
|
| 604 |
+
st.markdown(get_table_excel_link(data3.T, "Estimación demanda"),
|
| 605 |
+
unsafe_allow_html=True)
|
| 606 |
+
|
| 607 |
+
|
| 608 |
+
import matplotlib.pyplot as plt
|
| 609 |
+
import numpy as np
|
| 610 |
+
import streamlit as st
|
| 611 |
+
import time
|
| 612 |
+
import statistics
|
| 613 |
+
def simulacion_final():
|
| 614 |
+
import altair as alt
|
| 615 |
+
from altair import datum
|
| 616 |
+
with st.form("Form"):
|
| 617 |
+
cols = st.columns(3)
|
| 618 |
+
capital_inicial = cols[0].number_input("Capital inicial", value=1000000, format="%d")
|
| 619 |
+
cap_ahorro = cols[1].number_input("Capacidad de ahorro", value=750000, format='%d')
|
| 620 |
+
objetivo = cols[2].number_input("Objetivo", value=40000000, format="%u")
|
| 621 |
+
|
| 622 |
+
button_2 = st.form_submit_button("Comenzar simulacion")
|
| 623 |
+
my_bar = st.sidebar.progress(0)
|
| 624 |
+
progress = 0
|
| 625 |
+
periodo = int(objetivo/cap_ahorro)+1
|
| 626 |
+
periodo_cambio = int(periodo*3/5)
|
| 627 |
+
periodo_cambio = int(periodo*3/5)
|
| 628 |
+
periodo_cambio2 = int(periodo*4/5)
|
| 629 |
+
l_1=[capital_inicial]
|
| 630 |
+
l_2=[0]
|
| 631 |
+
l_3 = []
|
| 632 |
+
l_4 = []
|
| 633 |
+
l_5 = []
|
| 634 |
+
l_6 = []
|
| 635 |
+
volatilidad = []
|
| 636 |
+
drawdown = False
|
| 637 |
+
corte_antes = False
|
| 638 |
+
cambio = 0
|
| 639 |
+
lista2=l_1+l_2+l_3
|
| 640 |
+
chart_row = st.empty()
|
| 641 |
+
if button_2:
|
| 642 |
+
|
| 643 |
+
|
| 644 |
+
for j in range(1,periodo+4):
|
| 645 |
+
lista =np.array(l_1+l_3+l_5)
|
| 646 |
+
if lista[-1] > objetivo:
|
| 647 |
+
corte_antes = True
|
| 648 |
+
corte = j
|
| 649 |
+
periodo = j
|
| 650 |
+
break
|
| 651 |
+
else:
|
| 652 |
+
if j <= 12:
|
| 653 |
+
volatilidad.append(0)
|
| 654 |
+
# elif j < 12 and j >3:
|
| 655 |
+
|
| 656 |
+
# volatilidad.append(statistics.stdev((lista[1:j]/lista[0:j-1])))
|
| 657 |
+
else:
|
| 658 |
+
retornos = ((lista[j-11:j]-cap_ahorro)/lista[j-12:j-1])
|
| 659 |
+
volatilidad.append(statistics.stdev(retornos))
|
| 660 |
+
if statistics.stdev(retornos) > 0.13 and j==periodo_cambio:
|
| 661 |
+
drawdown=True
|
| 662 |
+
cambio =+ 6
|
| 663 |
+
|
| 664 |
+
if j < periodo_cambio:
|
| 665 |
+
sig = abs(np.random.normal(0.04,0.1))
|
| 666 |
+
a = np.random.normal(0.018,sig)
|
| 667 |
+
|
| 668 |
+
elif j < periodo_cambio2 and not drawdown:
|
| 669 |
+
sig = abs(np.random.normal(0.03,0.04))
|
| 670 |
+
a = np.random.normal(0.01,sig)
|
| 671 |
+
|
| 672 |
+
|
| 673 |
+
elif j < periodo_cambio2 and drawdown:
|
| 674 |
+
sig = abs(np.random.normal(0.04,0.1))
|
| 675 |
+
a = np.random.normal(0.018,sig)
|
| 676 |
+
|
| 677 |
+
drawdown=False
|
| 678 |
+
else:
|
| 679 |
+
sig = abs(np.random.normal(0.005,0.01))
|
| 680 |
+
a = np.random.normal(0,sig)
|
| 681 |
+
|
| 682 |
+
|
| 683 |
+
if j < (periodo_cambio + cambio):
|
| 684 |
+
l_1.append(l_1[j-1]*(1+a) + cap_ahorro )
|
| 685 |
+
l_2.append(j)
|
| 686 |
+
|
| 687 |
+
if j >= (periodo_cambio + cambio) and j <periodo_cambio2:
|
| 688 |
+
if (periodo_cambio + cambio) == j:
|
| 689 |
+
l_3.append(l_1[j-1])
|
| 690 |
+
l_4.append(j-1)
|
| 691 |
+
l_3.append(l_3[j- periodo_cambio- cambio]*(1+a) + cap_ahorro )
|
| 692 |
+
l_4.append(j)
|
| 693 |
+
|
| 694 |
+
if j >= periodo_cambio2:
|
| 695 |
+
if periodo_cambio2 == j:
|
| 696 |
+
l_5.append(l_3[j - periodo_cambio - cambio])
|
| 697 |
+
l_6.append(j-1)
|
| 698 |
+
l_5.append(l_5[j- periodo_cambio2]*(1+a) + cap_ahorro )
|
| 699 |
+
l_6.append(j)
|
| 700 |
+
|
| 701 |
+
vol =pd.DataFrame(volatilidad)
|
| 702 |
+
cols = st.columns(3)
|
| 703 |
+
col1, col2 = st.columns(2)
|
| 704 |
+
#st.line_chart(vol)
|
| 705 |
+
mas_tmpo = False
|
| 706 |
+
if lista[-1] < objetivo:
|
| 707 |
+
delta = objetivo-l_5[-1]
|
| 708 |
+
t_extra = int(delta/cap_ahorro)+1
|
| 709 |
+
periodo_ant=periodo
|
| 710 |
+
mas_tmpo=True
|
| 711 |
+
periodo = periodo + t_extra
|
| 712 |
+
for i in range(t_extra):
|
| 713 |
+
l_5.append(l_5[-1]+ cap_ahorro)
|
| 714 |
+
l_6.append(l_6[-1]+ 1)
|
| 715 |
+
lista =np.array(l_1+l_3+l_5)
|
| 716 |
+
col1.subheader("Analista")
|
| 717 |
+
col2.subheader("Cliente")
|
| 718 |
+
|
| 719 |
+
|
| 720 |
+
for i in range(periodo+2):
|
| 721 |
+
time.sleep(0.01)
|
| 722 |
+
if mas_tmpo==True and i == periodo_ant:
|
| 723 |
+
st.write(t_extra)
|
| 724 |
+
col2.error("Mes " + str(i) +": Te faltan " + str(t_extra) + " meses para la meta")
|
| 725 |
+
time.sleep(3)
|
| 726 |
+
if corte_antes==True and i == corte:
|
| 727 |
+
col2.success("Mes " + str(i) +": Felcidiades llegaste antes a la meta")
|
| 728 |
+
time.sleep(3)
|
| 729 |
+
if cambio == 6 and i==(periodo_cambio):
|
| 730 |
+
col1.error("Mes " + str(i) +": Estas en drawdown se recomienda esperar 6 meses más")
|
| 731 |
+
col2.warning("Mes " + str(i) +": Debes esperar 6 mes mas para cambiarte")
|
| 732 |
+
time.sleep(3)
|
| 733 |
+
df = pd.DataFrame()
|
| 734 |
+
df2 = pd.DataFrame()
|
| 735 |
+
df3 = pd.DataFrame()
|
| 736 |
+
df["Mes"]=l_2[0:i+1]
|
| 737 |
+
df["Valor"]=l_1[0:i+1]
|
| 738 |
+
|
| 739 |
+
if i >= (periodo_cambio+cambio):
|
| 740 |
+
|
| 741 |
+
df2["Mes"]=l_4[0:i-periodo_cambio - cambio+1]
|
| 742 |
+
df2["Valor"] =l_3[0:i-periodo_cambio - cambio+1]
|
| 743 |
+
if i >= periodo_cambio2:
|
| 744 |
+
df3["Mes"]=l_6[0:i-periodo_cambio2+2]
|
| 745 |
+
df3["Valor"] =l_5[0:i-periodo_cambio2+2]
|
| 746 |
+
df["Fondo"] = ["Fondo Arriesgado"]*len(df)
|
| 747 |
+
df2["Fondo"] = ["Fondo Intermedio"]*len(df2)
|
| 748 |
+
df3["Fondo"] = ["Fondo Conservador"]*len(df3)
|
| 749 |
+
|
| 750 |
+
df_f = pd.concat([df,df2, df3])
|
| 751 |
+
|
| 752 |
+
df_f["Ahorro"] = df_f["Mes"]*cap_ahorro + capital_inicial
|
| 753 |
+
if i == (periodo_cambio+cambio):
|
| 754 |
+
col2.success("Mes " + str(i) +": Debes cambiarte al Fondo Intermedio")
|
| 755 |
+
time.sleep(3)
|
| 756 |
+
if i == periodo_cambio2:
|
| 757 |
+
col2.success("Mes " + str(i) +": Debes cambiarte al Fondo Conservador")
|
| 758 |
+
time.sleep(3)
|
| 759 |
+
fig = alt.Chart(df_f).mark_area(opacity=0.6).encode(
|
| 760 |
+
x=alt.X('Mes',
|
| 761 |
+
scale=alt.Scale(domain=(0, periodo - 1))
|
| 762 |
+
),
|
| 763 |
+
y=alt.X('Valor',
|
| 764 |
+
scale=alt.Scale(domain=(0, max(lista)*1.1))
|
| 765 |
+
),
|
| 766 |
+
color=alt.Color("Fondo", scale=alt.Scale(scheme='pastel1'))
|
| 767 |
+
)
|
| 768 |
+
bar = fig.mark_bar().encode(y='Ahorro')
|
| 769 |
+
|
| 770 |
+
|
| 771 |
+
chart_row.altair_chart(bar + fig, use_container_width=True)
|
| 772 |
+
|
| 773 |
+
my_bar.empty()
|
| 774 |
+
# from st_card import st_card
|
| 775 |
+
# with cols[0]:
|
| 776 |
+
# st_card('Capital proyectado', value=df_f.iloc[-1]["Valor"], show_progress=True)
|
| 777 |
+
# with cols[1]:
|
| 778 |
+
# st_card('Ganancia proyectada', value = df_f.iloc[-1]["Valor"] - df_f.iloc[-1]["Ahorro"],
|
| 779 |
+
# delta=round((df_f.iloc[-1]["Valor"]/df_f.iloc[-1]["Ahorro"]-1)*100,0) ,
|
| 780 |
+
# use_percentage_delta=True, delta_description='de retorno')
|
| 781 |
+
# with cols[2]:
|
| 782 |
+
# st_card('Meses', value=int(df_f.iloc[-1]["Mes"]), delta=periodo_cambio, delta_description='En el Fondo Arriesgado')
|
| 783 |
+
# st.write(df_f)
|
| 784 |
+
import streamlit.components.v1 as components
|
| 785 |
+
def candidatos():
|
| 786 |
+
html_str ="""
|
| 787 |
+
<!DOCTYPE html>
|
| 788 |
+
<html lang="es">
|
| 789 |
+
<head>
|
| 790 |
+
<title>D3.js - Mapas</title>
|
| 791 |
+
<meta charset="utf-8"/>
|
| 792 |
+
<!-- d3 😍-->
|
| 793 |
+
<script src="https://d3js.org/d3.v7.min.js"></script>
|
| 794 |
+
<!--nuestro estilo -->
|
| 795 |
+
<link type="text/css" rel="stylesheet" href="style.css"/>
|
| 796 |
+
</head>
|
| 797 |
+
<body>
|
| 798 |
+
<h1>
|
| 799 |
+
Mapa por región de votos a Gabriel Boric
|
| 800 |
+
</h1>
|
| 801 |
+
<p>
|
| 802 |
+
<u>Fuente: https://www.futuro.cl/2021/11/elecciones-presidenciales-chile-2021-resultados-region-por-region-en-vivo/</u>
|
| 803 |
+
</p>
|
| 804 |
+
<div>
|
| 805 |
+
<div id="viz1", style = "width:50%">
|
| 806 |
+
<svg id="geoOrthographic1"></svg>
|
| 807 |
+
</div>
|
| 808 |
+
<script>
|
| 809 |
+
//Nos sirve para poder cargar los archivos y luego ejecutar createMap
|
| 810 |
+
Promise
|
| 811 |
+
.all([
|
| 812 |
+
d3.json('chile.geojson'),
|
| 813 |
+
d3.json('chile.geojson')
|
| 814 |
+
])
|
| 815 |
+
.then(resolve => {
|
| 816 |
+
createMap1(resolve[1]);
|
| 817 |
+
createMap2(resolve[0]);
|
| 818 |
+
});
|
| 819 |
+
//creamos el mapa2
|
| 820 |
+
function createMap1(countries) {
|
| 821 |
+
const viz1 = d3.select("#viz1");
|
| 822 |
+
const ancho = viz1.style("width").substring(0, viz1.style("width").length - 2) - 10;
|
| 823 |
+
console.log("Ancho: " + ancho);
|
| 824 |
+
//como proyectamos lo que vamos a dibujar
|
| 825 |
+
//https://github.com/d3/d3-geo/blob/master/README.md#d3-geo
|
| 826 |
+
//https://github.com/d3/d3-geo-projection#geoConicEqualArea
|
| 827 |
+
const projection = d3.geoMercator()
|
| 828 |
+
//que tan cercano
|
| 829 |
+
.scale(550)
|
| 830 |
+
// .translate([ancho / 2, 250])
|
| 831 |
+
//desde el centro, lo podemos mover
|
| 832 |
+
.center([-55.6, -40]);
|
| 833 |
+
//definimos nuestro geoPath, lo que queremos dibujar
|
| 834 |
+
const geoPath = d3.geoPath().projection(projection);
|
| 835 |
+
//solo datos
|
| 836 |
+
const poblacion = [
|
| 837 |
+
{comuna: "Puente Alto", cantidad: 31.07},
|
| 838 |
+
{comuna: "Río Ibáñez", cantidad: 25},
|
| 839 |
+
{comuna: "Tocopilla", cantidad: 20.67},
|
| 840 |
+
{comuna: "Juan Fernández", cantidad: 28.12},
|
| 841 |
+
{comuna: "Caldera", cantidad: 19.24},
|
| 842 |
+
{comuna: "Castro", cantidad: 20.43},
|
| 843 |
+
{comuna: "Cañete", cantidad: 19.09},
|
| 844 |
+
{comuna: "La Unión", cantidad: 23.05},
|
| 845 |
+
{comuna: "Iquique", cantidad: 18.27},
|
| 846 |
+
{comuna: "San Esteban", cantidad: 28.12},
|
| 847 |
+
{comuna: "Putre", cantidad: 17.79},
|
| 848 |
+
{comuna: "Río Hurtado", cantidad: 25.92},
|
| 849 |
+
{comuna: "Torres del Paine", cantidad: 30.64},
|
| 850 |
+
{comuna: "Carahue", cantidad: 16.58},
|
| 851 |
+
{comuna: "Pelluhue", cantidad: 19.58},
|
| 852 |
+
{comuna: "Malloa", cantidad: 24.14},
|
| 853 |
+
];
|
| 854 |
+
//geoArea nos da el area dado un GeoJson
|
| 855 |
+
//extent nos devuelve el minimo y maximo valor
|
| 856 |
+
const realFeatureSize = d3.extent(poblacion, function (d) {
|
| 857 |
+
return +d.cantidad
|
| 858 |
+
});
|
| 859 |
+
console.log("Mínimo y Máximo: ");
|
| 860 |
+
console.log(realFeatureSize);
|
| 861 |
+
//hacemos un escala para los colores
|
| 862 |
+
//veamos cual es el rango
|
| 863 |
+
//https://github.com/d3/d3-scale#scaleQuantize
|
| 864 |
+
const newFeatureColor = d3.scaleQuantize()
|
| 865 |
+
.domain(realFeatureSize)
|
| 866 |
+
.range(['#fee0d2','#fc9272','#de2d26']);
|
| 867 |
+
//Nada nuevo, aqui hacemos el dibujo
|
| 868 |
+
d3.select("#geoOrthographic1").selectAll("path")
|
| 869 |
+
.data(countries.features).enter()
|
| 870 |
+
.append("path")
|
| 871 |
+
.attr("d", geoPath)
|
| 872 |
+
.attr("id", d => d.id)
|
| 873 |
+
.attr("class", "countries")
|
| 874 |
+
.style("fill", d => {
|
| 875 |
+
//comentar la linea de abajo para ver que hace el resto
|
| 876 |
+
//return "grey"
|
| 877 |
+
console.log(d.properties.NOM_COM);
|
| 878 |
+
let poblacionEncontrada;
|
| 879 |
+
poblacion.forEach(function (e) {
|
| 880 |
+
console.log(d.properties.NOM_COM);
|
| 881 |
+
console.log(e.comuna);
|
| 882 |
+
if (e.comuna === d.properties.NOM_COM) {
|
| 883 |
+
poblacionEncontrada = e.cantidad;
|
| 884 |
+
}
|
| 885 |
+
});
|
| 886 |
+
return newFeatureColor(poblacionEncontrada)
|
| 887 |
+
})
|
| 888 |
+
.style("stroke", d => d3.rgb(newFeatureColor(d3.geoArea(d))).darker());
|
| 889 |
+
// //generamos la "grilla"
|
| 890 |
+
// const graticule = d3.geoGraticule();
|
| 891 |
+
//
|
| 892 |
+
// //dibujamos la grilla
|
| 893 |
+
// d3.select("#geoOrthographic1").insert("path", "path.countries")
|
| 894 |
+
// .datum(graticule)
|
| 895 |
+
// .attr("class", "graticule line")
|
| 896 |
+
// .attr("d", geoPath);
|
| 897 |
+
const zoom = d3.zoom()
|
| 898 |
+
.scaleExtent([1, 8])
|
| 899 |
+
.on('zoom', function (event) {
|
| 900 |
+
d3.select("#geoOrthographic1").selectAll('path')
|
| 901 |
+
.attr('transform', event.transform);
|
| 902 |
+
});
|
| 903 |
+
d3.select("#geoOrthographic1").call(zoom);
|
| 904 |
+
}
|
| 905 |
+
//creamos el mapa
|
| 906 |
+
//Nos sirve para poder cargar los archivos y luego ejecutar createMap
|
| 907 |
+
//creamos el mapa2
|
| 908 |
+
function createMap2(countries) {
|
| 909 |
+
const viz1 = d3.select("#viz2");
|
| 910 |
+
const ancho = viz1.style("width").substring(0, viz1.style("width").length - 2) - 10;
|
| 911 |
+
console.log("Ancho: " + ancho);
|
| 912 |
+
//como proyectamos lo que vamos a dibujar
|
| 913 |
+
//https://github.com/d3/d3-geo/blob/master/README.md#d3-geo
|
| 914 |
+
//https://github.com/d3/d3-geo-projection#geoConicEqualArea
|
| 915 |
+
const projection = d3.geoMercator()
|
| 916 |
+
//que tan cercano
|
| 917 |
+
.scale(550)
|
| 918 |
+
// .translate([ancho / 2, 250])
|
| 919 |
+
//desde el centro, lo podemos mover
|
| 920 |
+
.center([-55.6, -40]);
|
| 921 |
+
//definimos nuestro geoPath, lo que queremos dibujar
|
| 922 |
+
const geoPath = d3.geoPath().projection(projection);
|
| 923 |
+
//solo datos
|
| 924 |
+
const poblacion = [
|
| 925 |
+
{comuna: "Puente Alto", cantidad: 31.07},
|
| 926 |
+
{comuna: "Río Ibáñez", cantidad: 25},
|
| 927 |
+
{comuna: "Tocopilla", cantidad: 20.67},
|
| 928 |
+
{comuna: "Juan Fernández", cantidad: 28.12},
|
| 929 |
+
{comuna: "Caldera", cantidad: 19.24},
|
| 930 |
+
{comuna: "Castro", cantidad: 20.43},
|
| 931 |
+
{comuna: "Cañete", cantidad: 19.09},
|
| 932 |
+
{comuna: "La Unión", cantidad: 23.05},
|
| 933 |
+
{comuna: "Iquique", cantidad: 18.27},
|
| 934 |
+
{comuna: "San Esteban", cantidad: 28.12},
|
| 935 |
+
{comuna: "Putre", cantidad: 17.79},
|
| 936 |
+
{comuna: "Río Hurtado", cantidad: 25.92},
|
| 937 |
+
{comuna: "Torres del Paine", cantidad: 30.64},
|
| 938 |
+
{comuna: "Carahue", cantidad: 16.58},
|
| 939 |
+
{comuna: "Pelluhue", cantidad: 19.58},
|
| 940 |
+
{comuna: "Malloa", cantidad: 24.14},
|
| 941 |
+
];
|
| 942 |
+
//geoArea nos da el area dado un GeoJson
|
| 943 |
+
//extent nos devuelve el minimo y maximo valor
|
| 944 |
+
const realFeatureSize = d3.extent(poblacion, function (d) {
|
| 945 |
+
return +d.cantidad
|
| 946 |
+
});
|
| 947 |
+
console.log("Mínimo y Máximo: ");
|
| 948 |
+
console.log(realFeatureSize);
|
| 949 |
+
//hacemos un escala para los colores
|
| 950 |
+
//veamos cual es el rango
|
| 951 |
+
//https://github.com/d3/d3-scale#scaleQuantize
|
| 952 |
+
const newFeatureColor = d3.scaleQuantize()
|
| 953 |
+
.domain(realFeatureSize)
|
| 954 |
+
.range(['#fee0d2','#fc9272','#de2d26']);
|
| 955 |
+
//Nada nuevo, aqui hacemos el dibujo
|
| 956 |
+
d3.select("#geoOrthographic2").selectAll("path")
|
| 957 |
+
.data(countries.features).enter()
|
| 958 |
+
.append("path")
|
| 959 |
+
.attr("d", geoPath)
|
| 960 |
+
.attr("id", d => d.id)
|
| 961 |
+
.attr("class", "countries")
|
| 962 |
+
.style("fill", d => {
|
| 963 |
+
//comentar la linea de abajo para ver que hace el resto
|
| 964 |
+
//return "grey"
|
| 965 |
+
console.log(d.properties.NOM_COM);
|
| 966 |
+
let poblacionEncontrada;
|
| 967 |
+
poblacion.forEach(function (e) {
|
| 968 |
+
console.log(d.properties.NOM_COM);
|
| 969 |
+
console.log(e.comuna);
|
| 970 |
+
if (e.comuna === d.properties.NOM_COM) {
|
| 971 |
+
poblacionEncontrada = e.cantidad;
|
| 972 |
+
}
|
| 973 |
+
});
|
| 974 |
+
return newFeatureColor(poblacionEncontrada)
|
| 975 |
+
})
|
| 976 |
+
.style("stroke", d => d3.rgb(newFeatureColor(d3.geoArea(d))).darker());
|
| 977 |
+
// //generamos la "grilla"
|
| 978 |
+
// const graticule = d3.geoGraticule();
|
| 979 |
+
//
|
| 980 |
+
// //dibujamos la grilla
|
| 981 |
+
// d3.select("#geoOrthographic1").insert("path", "path.countries")
|
| 982 |
+
// .datum(graticule)
|
| 983 |
+
// .attr("class", "graticule line")
|
| 984 |
+
// .attr("d", geoPath);
|
| 985 |
+
const zoom = d3.zoom()
|
| 986 |
+
.scaleExtent([1, 8])
|
| 987 |
+
.on('zoom', function (event) {
|
| 988 |
+
d3.select("#geoOrthographic2").selectAll('path')
|
| 989 |
+
.attr('transform', event.transform);
|
| 990 |
+
});
|
| 991 |
+
d3.select("#geoOrthographic2").call(zoom);
|
| 992 |
+
}
|
| 993 |
+
//creamos el mapa1
|
| 994 |
+
</script>
|
| 995 |
+
</div>
|
| 996 |
+
</body>
|
| 997 |
+
</html>
|
| 998 |
+
"""
|
| 999 |
+
components.html(html_str, height=1000)
|
| 1000 |
+
# def simulacion_final():
|
| 1001 |
+
# import altair as alt
|
| 1002 |
+
# from altair import datum
|
| 1003 |
+
# with st.form("Form"):
|
| 1004 |
+
# cols = st.beta_columns(3)
|
| 1005 |
+
# capital_inicial = cols[0].number_input("Objetivo", value=1000000, format="%d")
|
| 1006 |
+
# cap_ahorro = cols[1].number_input("Capacidad de ahorro", value=750000, format='%d')
|
| 1007 |
+
# objetivo = cols[2].number_input("Objetivo", value=40000000, format="%u")
|
| 1008 |
+
|
| 1009 |
+
# button_2 = st.form_submit_button("Comenzar simulacion")
|
| 1010 |
+
# l_1=[capital_inicial]
|
| 1011 |
+
# l_2=[0]
|
| 1012 |
+
# l_3=[np.nan]
|
| 1013 |
+
# l_4=[np.nan]
|
| 1014 |
+
# text=[]
|
| 1015 |
+
|
| 1016 |
+
|
| 1017 |
+
|
| 1018 |
+
# chart_row = st.empty()
|
| 1019 |
+
# if button_2:
|
| 1020 |
+
# my_bar = st.sidebar.progress(0)
|
| 1021 |
+
# progress = 0
|
| 1022 |
+
# periodo = int(objetivo/cap_ahorro)+1
|
| 1023 |
+
# periodo_cambio = int(periodo*3/5)
|
| 1024 |
+
# periodo_cambio2 = int(periodo*4/5)
|
| 1025 |
+
|
| 1026 |
+
# for j in range(1,periodo):
|
| 1027 |
+
|
| 1028 |
+
# a = np.random.normal(0.03,0.10)
|
| 1029 |
+
# if j <periodo_cambio:
|
| 1030 |
+
# l_1.append(l_1[j-1]*(1+a) + cap_ahorro )
|
| 1031 |
+
# l_3.append(np.nan)
|
| 1032 |
+
# l_4.append(np.nan)
|
| 1033 |
+
# text.append("")
|
| 1034 |
+
# elif j ==periodo_cambio:
|
| 1035 |
+
# l_1.append(l_1[j-1]*(1+a) + cap_ahorro )
|
| 1036 |
+
# l_3.append(l_1[j-1]*(1+a) + cap_ahorro )
|
| 1037 |
+
# l_4.append(np.nan)
|
| 1038 |
+
# text.append("")
|
| 1039 |
+
# elif j > periodo_cambio and j < periodo_cambio2 :
|
| 1040 |
+
# a = a/3
|
| 1041 |
+
# l_1.append(np.nan)
|
| 1042 |
+
# l_3.append(l_3[j-1]*(1+a) + cap_ahorro)
|
| 1043 |
+
# l_4.append(np.nan)
|
| 1044 |
+
# text.append("")
|
| 1045 |
+
# elif j == periodo_cambio2:
|
| 1046 |
+
# a = a/3
|
| 1047 |
+
# l_1.append(np.nan)
|
| 1048 |
+
# l_3.append(l_3[j-1]*(1+a) + cap_ahorro)
|
| 1049 |
+
# l_4.append(l_3[j-1]*(1+a) + cap_ahorro)
|
| 1050 |
+
# text.append("")
|
| 1051 |
+
# else:
|
| 1052 |
+
# a = a/5
|
| 1053 |
+
# l_1.append(np.nan)
|
| 1054 |
+
# l_3.append(np.nan)
|
| 1055 |
+
# l_4.append(l_4[j-1]*(1+a) + cap_ahorro)
|
| 1056 |
+
# text.append("")
|
| 1057 |
+
# l_2.append(j)
|
| 1058 |
+
# drawd =[]
|
| 1059 |
+
# for k in range(2,len(l_1)):
|
| 1060 |
+
|
| 1061 |
+
# if (l_1[k] - l_1[k-1])/(l_1[k]) < -0.01:
|
| 1062 |
+
# periodo_cambio1_2 = periodo_cambio + 1
|
| 1063 |
+
# drawd.append(k)
|
| 1064 |
+
# else:
|
| 1065 |
+
# periodo_cambio1_2=periodo_cambio
|
| 1066 |
+
|
| 1067 |
+
# for i in range(periodo):
|
| 1068 |
+
# progress = (i/periodo)
|
| 1069 |
+
# my_bar = my_bar.progress(progress)
|
| 1070 |
+
# time.sleep(0.001)
|
| 1071 |
+
# df = pd.DataFrame()
|
| 1072 |
+
# df["Mes"]=l_2[0:i+1]+l_2[0:i+1] + l_2[0:i+1]
|
| 1073 |
+
# df["Valor"]=l_1[0:i+1]+l_3[0:i+1] + l_4[0:i+1]
|
| 1074 |
+
# if i <= periodo_cambio:
|
| 1075 |
+
# df["Fondo"]=["Fondo Arriesgado"]*len(df)
|
| 1076 |
+
# if i in drawd:
|
| 1077 |
+
# st.warning("Drawdown")
|
| 1078 |
+
# time.sleep(2)
|
| 1079 |
+
# elif i > periodo_cambio and i <= periodo_cambio2:
|
| 1080 |
+
# df["Fondo"]=["Fondo Arriesgado"]*(periodo_cambio+1) + ["Fondo Intermedio"]*(i-periodo_cambio) + ["Fondo Arriesgado"]*(periodo_cambio + 1) + ["Fondo Intermedio"]*(i-periodo_cambio) + ["Fondo Arriesgado"]*(periodo_cambio+1) + ["Fondo Intermedio"]*(i-periodo_cambio)
|
| 1081 |
+
# else:
|
| 1082 |
+
# a = ["Fondo Arriesgado"] * periodo_cambio
|
| 1083 |
+
# b = ["Fondo Intermedio"] * (periodo_cambio2 - periodo_cambio-1)
|
| 1084 |
+
# c = ["Fondo Conservador"] * (i-periodo_cambio2)
|
| 1085 |
+
# d = ["Fondo Arriesgado"] * (periodo_cambio+2)
|
| 1086 |
+
# e = ["Fondo Intermedio"] * (periodo_cambio2 - (periodo_cambio+2))
|
| 1087 |
+
# f = ["Fondo Conservador"]*(i-periodo_cambio2+2)
|
| 1088 |
+
# df["Fondo"]= a + b + c + d + e + f + d + e + f
|
| 1089 |
+
# df = df.dropna()
|
| 1090 |
+
|
| 1091 |
+
|
| 1092 |
+
|
| 1093 |
+
|
| 1094 |
+
# if i == periodo_cambio:
|
| 1095 |
+
# placeholder=st.empty()
|
| 1096 |
+
# placeholder.info("Debes cambiarte al fondo intermedio")
|
| 1097 |
+
# time.sleep(3)
|
| 1098 |
+
# placeholder.empty()
|
| 1099 |
+
# if i == periodo_cambio2:
|
| 1100 |
+
# placeholder=st.empty()
|
| 1101 |
+
# placeholder.info("Debes cambiarte al fondo conservador")
|
| 1102 |
+
# time.sleep(3)
|
| 1103 |
+
# placeholder.empty()
|
| 1104 |
+
# # df=df.dropna()
|
| 1105 |
+
|
| 1106 |
+
# fig = alt.Chart(df).mark_area(opacity=0.6).encode(
|
| 1107 |
+
# x=alt.X('Mes',
|
| 1108 |
+
# scale=alt.Scale(domain=(0, periodo - 1))
|
| 1109 |
+
# ),
|
| 1110 |
+
# y=alt.X('Valor',
|
| 1111 |
+
# scale=alt.Scale(domain=(0, max(l_1+l_3+l_4)*1.1))
|
| 1112 |
+
# ),
|
| 1113 |
+
# color=alt.Color("Fondo", scale=alt.Scale(scheme='category20'))
|
| 1114 |
+
# )
|
| 1115 |
+
# if i > periodo_cambio and i <= periodo_cambio2:
|
| 1116 |
+
# df["Cambio"]="Cambiate al fondo intermedio"
|
| 1117 |
+
# text = (
|
| 1118 |
+
# alt.Chart(df[df["Mes"]==periodo_cambio])
|
| 1119 |
+
# .mark_text(dy=-25, color="black")
|
| 1120 |
+
# .encode(x=alt.X("Mes"), y=alt.Y("Valor"), text="Cambio")
|
| 1121 |
+
# )
|
| 1122 |
+
|
| 1123 |
+
# chart_row.altair_chart(fig + text, use_container_width=True)
|
| 1124 |
+
# if i > periodo_cambio2:
|
| 1125 |
+
# df["Cambio"]="Cambiate al fondo conservador"
|
| 1126 |
+
# text = (
|
| 1127 |
+
# alt.Chart(df[df["Mes"]==periodo_cambio2])
|
| 1128 |
+
# .mark_text(dy=-25, color="black")
|
| 1129 |
+
# .encode(x=alt.X("Mes"), y=alt.Y("Valor"), text="Cambio")
|
| 1130 |
+
# )
|
| 1131 |
+
# chart_row.altair_chart(fig, use_container_width=True)
|
| 1132 |
+
# else:
|
| 1133 |
+
# chart_row.altair_chart(fig, use_container_width=True)
|
| 1134 |
+
# cols = st.columns(3)
|
| 1135 |
+
# ganancia=value=l_3[-1] - cap_ahorro * l_2[-1]
|
| 1136 |
+
# my_bar.empty()
|
| 1137 |
+
# # with cols[0]:
|
| 1138 |
+
# # st_card('Capital proyectado', value=l_3[-1], show_progress=True)
|
| 1139 |
+
# # with cols[1]:
|
| 1140 |
+
# # st_card('Ganancia proyectada', value=ganancia, delta=round(ganancia/(cap_ahorro * l_2[-1])*100,0) ,
|
| 1141 |
+
# # use_percentage_delta=True, delta_description='de retorno')
|
| 1142 |
+
# # with cols[2]:
|
| 1143 |
+
# # st_card('Meses', value=l_2[-1], delta=periodo_cambio, delta_description='En el Fondo Arriesgado')
|
| 1144 |
+
# st.write(df)
|
| 1145 |
+
def prototipo_simulacion():
|
| 1146 |
+
# import streamlit as st
|
| 1147 |
+
# import time
|
| 1148 |
+
# import numpy as np
|
| 1149 |
+
# progress_bar = st.sidebar.progress(0)
|
| 1150 |
+
# status_text = st.sidebar.empty()
|
| 1151 |
+
# last_rows = np.random.randn(1, 1)
|
| 1152 |
+
# chart = st.line_chart(last_rows)
|
| 1153 |
+
# for i in range(1, 101):
|
| 1154 |
+
# new_rows = last_rows[-1, :] + np.random.randn(50, 1).cumsum(axis=0)
|
| 1155 |
+
# status_text.text("%i%% Complete" % i)
|
| 1156 |
+
# chart.add_rows(new_rows)
|
| 1157 |
+
# progress_bar.progress(i)
|
| 1158 |
+
# last_rows = new_rows
|
| 1159 |
+
# time.sleep(0.001)
|
| 1160 |
+
|
| 1161 |
+
# progress_bar.empty()
|
| 1162 |
+
# # Streamlit widgets automatically run the script from top to bottom. Since
|
| 1163 |
+
# # this button is not connected to any other logic, it just causes a plain
|
| 1164 |
+
# # rerun.
|
| 1165 |
+
# st.button("Re-run")
|
| 1166 |
+
# import numpy as np
|
| 1167 |
+
# import matplotlib.pyplot as plt
|
| 1168 |
+
# import matplotlib.animation as animation
|
| 1169 |
+
# import streamlit as st
|
| 1170 |
+
# import streamlit.components.v1 as components
|
| 1171 |
+
|
| 1172 |
+
# def update_line(num, data, line):
|
| 1173 |
+
# line.set_data(data[..., :num])
|
| 1174 |
+
# return line,
|
| 1175 |
+
|
| 1176 |
+
# fig = plt.figure()
|
| 1177 |
+
|
| 1178 |
+
# # Fixing random state for reproducibility
|
| 1179 |
+
# np.random.seed(19680801)
|
| 1180 |
+
|
| 1181 |
+
# data = np.random.rand(2, 25)
|
| 1182 |
+
# l, = plt.plot([], [], 'r-')
|
| 1183 |
+
# plt.xlim(0, 1)
|
| 1184 |
+
# plt.ylim(0, 1)
|
| 1185 |
+
# plt.xlabel('x')
|
| 1186 |
+
# plt.title('test')
|
| 1187 |
+
# line_ani = animation.FuncAnimation(fig, update_line, 25, fargs=(data, l), interval=50, blit=True)
|
| 1188 |
+
|
| 1189 |
+
# st.title("Embed Matplotlib animation in Streamlit")
|
| 1190 |
+
# st.markdown("https://matplotlib.org/gallery/animation/basic_example.html")
|
| 1191 |
+
# components.html(line_ani.to_jshtml(), height=1000)
|
| 1192 |
+
# import matplotlib.pyplot as plt
|
| 1193 |
+
# import numpy as np
|
| 1194 |
+
# import streamlit as st
|
| 1195 |
+
# import time
|
| 1196 |
+
|
| 1197 |
+
# fig, ax = plt.subplots()
|
| 1198 |
+
|
| 1199 |
+
# max_x = 5
|
| 1200 |
+
# max_rand = 10
|
| 1201 |
+
|
| 1202 |
+
# x = np.arange(0, max_x)
|
| 1203 |
+
# ax.set_ylim(0, max_rand)
|
| 1204 |
+
# line, = ax.plot(x, np.random.randint(0, max_rand, max_x))
|
| 1205 |
+
# the_plot = st.pyplot(plt)
|
| 1206 |
+
|
| 1207 |
+
# def init(): # give a clean slate to start
|
| 1208 |
+
# line.set_ydata([np.nan] * len(x))
|
| 1209 |
+
|
| 1210 |
+
# def animate(i): # update the y values (every 1000ms)
|
| 1211 |
+
# line.set_ydata(np.random.randint(0, max_rand, max_x))
|
| 1212 |
+
# the_plot.pyplot(plt)
|
| 1213 |
+
|
| 1214 |
+
# init()
|
| 1215 |
+
# for i in range(100):
|
| 1216 |
+
# animate(i)
|
| 1217 |
+
# time.sleep(0.1)
|
| 1218 |
+
import plotly.express as px
|
| 1219 |
+
from datetime import date
|
| 1220 |
+
from datetime import timedelta
|
| 1221 |
+
import numpy as np
|
| 1222 |
+
df = px.data.gapminder()
|
| 1223 |
+
cap_ahorro = 750000
|
| 1224 |
+
Data = pd.DataFrame()
|
| 1225 |
+
today =date.today()
|
| 1226 |
+
l=[]
|
| 1227 |
+
l2=[]
|
| 1228 |
+
l3=[]
|
| 1229 |
+
l4=[]
|
| 1230 |
+
for i in range(53):
|
| 1231 |
+
|
| 1232 |
+
for j in range(53):
|
| 1233 |
+
l.append(i)
|
| 1234 |
+
l2.append(j)
|
| 1235 |
+
if j<=i:
|
| 1236 |
+
l3.append(cap_ahorro*j)
|
| 1237 |
+
else:
|
| 1238 |
+
l3.append(0)
|
| 1239 |
+
if j<40:
|
| 1240 |
+
l4.append("Arriesgado")
|
| 1241 |
+
elif j<47:
|
| 1242 |
+
l4.append("Intermedio")
|
| 1243 |
+
else:
|
| 1244 |
+
l4.append("Conservador")
|
| 1245 |
+
l5 = []
|
| 1246 |
+
l6 = []
|
| 1247 |
+
Data["Mes"] = l
|
| 1248 |
+
Data["Ahorro"] = l2
|
| 1249 |
+
Data["Total"] = l3
|
| 1250 |
+
Data["Fondo"] = l4
|
| 1251 |
+
fig = px.bar(Data, x="Ahorro", y="Total", color="Fondo",
|
| 1252 |
+
animation_frame="Mes")
|
| 1253 |
+
fig.update_yaxes(range=[0, 50000000])
|
| 1254 |
+
fig.update_xaxes(range=[0, 53])
|
| 1255 |
+
st.plotly_chart(fig)
|
| 1256 |
+
button = st.button("Activar")
|
| 1257 |
+
if button:
|
| 1258 |
+
chart_data = pd.DataFrame()
|
| 1259 |
+
chart = st.area_chart(chart_data)
|
| 1260 |
+
for i in range(100):
|
| 1261 |
+
if i<70:
|
| 1262 |
+
chart.add_rows(pd.DataFrame([[i*cap_ahorro,0, 0]], columns=['Fondo 1', 'Fondo 2', 'Fondo 3']))
|
| 1263 |
+
elif i==70:
|
| 1264 |
+
chart.add_rows(pd.DataFrame([[i*cap_ahorro,i*cap_ahorro,0]], columns=['Fondo 1', 'Fondo 2', 'Fondo 3']))
|
| 1265 |
+
st.success("Debes cambiarte al fondo intermedio")
|
| 1266 |
+
elif i<85:
|
| 1267 |
+
chart.add_rows(pd.DataFrame([[0,i*cap_ahorro,0]], columns=['Fondo 1', 'Fondo 2', 'Fondo 3']))
|
| 1268 |
+
elif i==85:
|
| 1269 |
+
chart.add_rows(pd.DataFrame([[0,i*cap_ahorro,i*cap_ahorro]], columns=['Fondo 1', 'Fondo 2', 'Fondo 3']))
|
| 1270 |
+
st.success("Debes cambiarte al fondo arriesgado")
|
| 1271 |
+
else:
|
| 1272 |
+
chart.add_rows(pd.DataFrame([[0,0, i*cap_ahorro]], columns=['Fondo 1', 'Fondo 2', 'Fondo 3']))
|
| 1273 |
+
time.sleep(0.1)
|
| 1274 |
+
|
| 1275 |
+
cap_ahorro = 750000
|
| 1276 |
+
from plotly.subplots import make_subplots
|
| 1277 |
+
import plotly.graph_objects as go
|
| 1278 |
+
import numpy as np
|
| 1279 |
+
import plotly.graph_objects as go
|
| 1280 |
+
Frames=[]
|
| 1281 |
+
Frames2 =[]
|
| 1282 |
+
|
| 1283 |
+
l_1=[]
|
| 1284 |
+
l_2=[]
|
| 1285 |
+
l_3=[]
|
| 1286 |
+
text=[]
|
| 1287 |
+
fig = make_subplots(rows=1, cols=1, subplot_titles = ('Subplot (1,1)'))
|
| 1288 |
+
for i in range(53):
|
| 1289 |
+
if i <40:
|
| 1290 |
+
l_1.append(cap_ahorro*i)
|
| 1291 |
+
l_3.append(np.nan)
|
| 1292 |
+
text.append("")
|
| 1293 |
+
elif i ==40:
|
| 1294 |
+
l_1.append(cap_ahorro*i)
|
| 1295 |
+
l_3.append(cap_ahorro*i)
|
| 1296 |
+
text.append("")
|
| 1297 |
+
else:
|
| 1298 |
+
l_1.append(np.nan)
|
| 1299 |
+
l_3.append(cap_ahorro*i)
|
| 1300 |
+
text.append("")
|
| 1301 |
+
l_2.append(i)
|
| 1302 |
+
|
| 1303 |
+
Frames.append(go.Scatter(x=l_2, y=l_1,
|
| 1304 |
+
mode="lines+text",
|
| 1305 |
+
text=text,
|
| 1306 |
+
textposition="bottom center",
|
| 1307 |
+
textsrc="bottom center",
|
| 1308 |
+
textfont=dict(
|
| 1309 |
+
family="sans serif",
|
| 1310 |
+
size=10,
|
| 1311 |
+
color="Black"
|
| 1312 |
+
), fill='tozeroy'))
|
| 1313 |
+
Frames2.append(go.Scatter(x=l_2, y=l_3, fill='tozeroy'))
|
| 1314 |
+
go.Annotations
|
| 1315 |
+
Frames_finales=[Frames, Frames2]
|
| 1316 |
+
fig.add_trace(go.Scatter(
|
| 1317 |
+
x= [0],
|
| 1318 |
+
y= [0],
|
| 1319 |
+
mode = 'lines',
|
| 1320 |
+
hoverinfo='name',
|
| 1321 |
+
legendgroup= 'Fondo Arriesgado',
|
| 1322 |
+
line_color= 'rgb(255, 79, 38)',
|
| 1323 |
+
name= 'Fondo Arriesgado',
|
| 1324 |
+
showlegend= True), row=1, col=1)
|
| 1325 |
+
fig.add_trace(go.Scatter(
|
| 1326 |
+
x= [0],
|
| 1327 |
+
y= [0],
|
| 1328 |
+
mode = 'lines',
|
| 1329 |
+
hoverinfo='name',
|
| 1330 |
+
legendgroup= 'Fondo Conservador',
|
| 1331 |
+
line_color= 'rgb(79, 38, 255)',
|
| 1332 |
+
name= 'Fondo Conservador',
|
| 1333 |
+
showlegend= True), row=1, col=1)
|
| 1334 |
+
frames =[dict(name = k,
|
| 1335 |
+
data = [Frames[k],Frames2[k]],
|
| 1336 |
+
traces=[0,1]) for k in range(53)
|
| 1337 |
+
]
|
| 1338 |
+
updatemenus=[dict(
|
| 1339 |
+
type="buttons",
|
| 1340 |
+
buttons=[dict(label="Play",
|
| 1341 |
+
method="animate",
|
| 1342 |
+
args=[None])])]
|
| 1343 |
+
fig.update_yaxes(range=[0, 50000000])
|
| 1344 |
+
fig.update_xaxes(range=[0, 53])
|
| 1345 |
+
annotations1 = [dict(
|
| 1346 |
+
x=40,
|
| 1347 |
+
y=40*cap_ahorro,
|
| 1348 |
+
text=text,
|
| 1349 |
+
xanchor='auto',
|
| 1350 |
+
yanchor='bottom',
|
| 1351 |
+
showarrow=False,
|
| 1352 |
+
)]
|
| 1353 |
+
|
| 1354 |
+
fig.update(frames=frames),
|
| 1355 |
+
fig.update_layout(updatemenus=updatemenus)
|
| 1356 |
+
|
| 1357 |
+
st.plotly_chart(fig)
|
| 1358 |
+
import altair as alt
|
| 1359 |
+
from altair import datum
|
| 1360 |
+
l_1=[]
|
| 1361 |
+
l_2=[]
|
| 1362 |
+
l_3=[]
|
| 1363 |
+
for i in range(51):
|
| 1364 |
+
if i <41:
|
| 1365 |
+
l_1.append(cap_ahorro*i)
|
| 1366 |
+
l_3.append(np.nan)
|
| 1367 |
+
text.append("")
|
| 1368 |
+
elif i ==41:
|
| 1369 |
+
l_1.append(cap_ahorro*i)
|
| 1370 |
+
l_3.append(cap_ahorro*i)
|
| 1371 |
+
text.append("")
|
| 1372 |
+
else:
|
| 1373 |
+
l_1.append(np.nan)
|
| 1374 |
+
l_3.append(cap_ahorro*i)
|
| 1375 |
+
text.append("")
|
| 1376 |
+
l_2.append(i)
|
| 1377 |
+
chart_row = st.empty()
|
| 1378 |
+
button_2 = st.button("Comenzar simulació")
|
| 1379 |
+
if button_2:
|
| 1380 |
+
for i in range(51):
|
| 1381 |
+
time.sleep(0.1)
|
| 1382 |
+
df = pd.DataFrame()
|
| 1383 |
+
|
| 1384 |
+
df["Mes"]=l_2[0:i+1]+l_2[0:i+1]
|
| 1385 |
+
print(df["Mes"])
|
| 1386 |
+
df["Valor"]=l_1[0:i+1]+l_3[0:i+1]
|
| 1387 |
+
if i <= 41:
|
| 1388 |
+
df["Fondo"]=["Fondo Arriesgado"]*len(df)
|
| 1389 |
+
else:
|
| 1390 |
+
df["Fondo"]=["Fondo Arriesgado"]*41 + ["Fondo Conservador"]*(i-41) + ["Fondo Arriesgado"]*43 + ["Fondo Conservador"]*(i-41)
|
| 1391 |
+
if i == 41:
|
| 1392 |
+
st.success("Debes cambiarte al fondo conservador")
|
| 1393 |
+
time.sleep(1)
|
| 1394 |
+
df=df.dropna()
|
| 1395 |
+
fig = alt.Chart(df).mark_area(opacity=0.6).encode(
|
| 1396 |
+
x=alt.X('Mes',
|
| 1397 |
+
scale=alt.Scale(domain=(0, 50))
|
| 1398 |
+
),
|
| 1399 |
+
y=alt.X('Valor',
|
| 1400 |
+
scale=alt.Scale(domain=(0, max(l_1+l_3)*1.1))
|
| 1401 |
+
),
|
| 1402 |
+
color=alt.Color("Fondo", scale=alt.Scale(scheme='category20'))
|
| 1403 |
+
)
|
| 1404 |
+
if i > 41:
|
| 1405 |
+
df["Cambio"]="Cambiate al fondo conservador"
|
| 1406 |
+
text = (
|
| 1407 |
+
alt.Chart(df[df["Mes"]==41])
|
| 1408 |
+
.mark_text(dy=-25, color="black")
|
| 1409 |
+
.encode(x=alt.X("Mes"), y=alt.Y("Valor"), text="Cambio")
|
| 1410 |
+
)
|
| 1411 |
+
|
| 1412 |
+
chart_row.altair_chart(fig + text, use_container_width=True)
|
| 1413 |
+
else:
|
| 1414 |
+
chart_row.altair_chart(fig, use_container_width=True)
|
apps/streamlit_larra.py
CHANGED
|
@@ -1,3 +1,131 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
Created on Tue Nov 2 10:06:46 2021
|
| 5 |
+
|
| 6 |
+
@author: benjaminull
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
import pybase64 as base64
|
| 11 |
+
import io
|
| 12 |
+
import streamlit as st
|
| 13 |
+
from plotly import graph_objs as go
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def formatnum_0(numero):
|
| 17 |
+
'''
|
| 18 |
+
Esta función permite dar formato a los montos de saldo y valor cuota en
|
| 19 |
+
las cartolas.
|
| 20 |
+
'''
|
| 21 |
+
return '{:,.0f}'.format(numero).replace(",", "@").replace(".", ",").replace("@", ".")
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def formatnum_2(numero):
|
| 25 |
+
return '{:,.2f}'.format(numero).replace(",", "@").replace(".", ",").replace("@", ".")
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def macro_plot(col, data, color, prefijo, ancho, largo):
|
| 29 |
+
fig = go.Figure()
|
| 30 |
+
close_ = go.Scatter(x=data.index, y=data['Close'], name="stock_close",
|
| 31 |
+
line=dict(color=color), fill='tonexty')
|
| 32 |
+
fig.add_trace(close_)
|
| 33 |
+
fig.layout.update(title_text="", xaxis_rangeslider_visible=True,
|
| 34 |
+
width=ancho, height=largo, margin_b=0, margin_t=0,
|
| 35 |
+
margin_r=0, margin_l=0)
|
| 36 |
+
fig.update_yaxes(range=[min(data['Close'])/1.05,
|
| 37 |
+
max(data['Close'])*1.05], tickprefix=prefijo)
|
| 38 |
+
col.plotly_chart(fig, use_container_width=True)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def get_table_excel_link(df, name):
|
| 42 |
+
towrite = io.BytesIO()
|
| 43 |
+
downloaded_file = df.to_excel(towrite, encoding='utf-8', index=False,
|
| 44 |
+
header=True)
|
| 45 |
+
towrite.seek(0) # reset pointer
|
| 46 |
+
file_name = 'Data' + name + '.xlsx'
|
| 47 |
+
style = 'style="color:black;text-decoration: none; font-size:18px;"'
|
| 48 |
+
name_mark = "Descargar " + name + ".xlsx"
|
| 49 |
+
b64 = base64.b64encode(towrite.read()).decode() # some strings
|
| 50 |
+
linko= f'<center><a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" '+style+'download="'+file_name+'"><button>'+name_mark+'</button></a></center>'
|
| 51 |
+
return linko
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def selectbox_larra(label, options):
|
| 55 |
+
var = st.selectbox(label, sorted(list(set(options))))
|
| 56 |
+
return var
|
| 57 |
+
|
| 58 |
+
def style_table():
|
| 59 |
+
style_table = """
|
| 60 |
+
<style>
|
| 61 |
+
tbody tr:hover {
|
| 62 |
+
color:#BB1114;}
|
| 63 |
+
thead {
|
| 64 |
+
background-color:#BB1114 ;
|
| 65 |
+
color: #E8E8E8;
|
| 66 |
+
}
|
| 67 |
+
tbody tr:nth-child(odd) {
|
| 68 |
+
background-color: #fff;
|
| 69 |
+
}
|
| 70 |
+
tbody tr:nth-child(even) {
|
| 71 |
+
background-color: #eee;
|
| 72 |
+
}
|
| 73 |
+
tbody tr:nth-child(odd)
|
| 74 |
+
stTable {
|
| 75 |
+
border-collapse: collapse;
|
| 76 |
+
margin: 25px 0;
|
| 77 |
+
font-size: 0.9em;
|
| 78 |
+
min-width: 400px;
|
| 79 |
+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
| 80 |
+
}
|
| 81 |
+
</style>
|
| 82 |
+
"""
|
| 83 |
+
st.markdown(style_table, unsafe_allow_html=True)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def button_style():
|
| 88 |
+
style_button = """
|
| 89 |
+
<style>
|
| 90 |
+
button {
|
| 91 |
+
display: inline-block;
|
| 92 |
+
background-color: #e8e8e8;
|
| 93 |
+
border-radius: 15px;
|
| 94 |
+
border: 4px #cccccc;
|
| 95 |
+
color: #4a4a4a;
|
| 96 |
+
text-align: center;
|
| 97 |
+
font-size: 18px;
|
| 98 |
+
padding: 2px;
|
| 99 |
+
width: 300px;
|
| 100 |
+
transition: all 0.5s;
|
| 101 |
+
cursor: pointer;
|
| 102 |
+
margin: 5px;
|
| 103 |
+
}
|
| 104 |
+
button span {
|
| 105 |
+
cursor: pointer;
|
| 106 |
+
display: inline-block;
|
| 107 |
+
position: relative;
|
| 108 |
+
transition: 0.5s;
|
| 109 |
+
}
|
| 110 |
+
button span:after {
|
| 111 |
+
content: '\00bb';
|
| 112 |
+
position: absolute;
|
| 113 |
+
opacity: 0;
|
| 114 |
+
top: 0;
|
| 115 |
+
right: -20px;
|
| 116 |
+
transition: 0.5s;
|
| 117 |
+
}
|
| 118 |
+
button:hover {
|
| 119 |
+
background-color: #bb1114;
|
| 120 |
+
color:#e8e8e8;
|
| 121 |
+
}
|
| 122 |
+
button:hover span {
|
| 123 |
+
padding-right: 25px;
|
| 124 |
+
}
|
| 125 |
+
button:hover span:after {
|
| 126 |
+
opacity: 1;
|
| 127 |
+
right: 0;
|
| 128 |
+
}
|
| 129 |
+
</style>
|
| 130 |
+
"""
|
| 131 |
+
st.markdown(style_button, unsafe_allow_html=True)
|