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, "", "[email protected]")
|
272 |
+
mail.send_message([#destinatario,
|
273 |
+
"[email protected],",
|
274 |
+
"[email protected]"])
|
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, "", "[email protected]")
|
280 |
+
# mail.send_message(["[email protected],",
|
281 |
+
# "[email protected]"])
|
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, "", "[email protected]")
|
408 |
+
mail.send_message([destinatario,
|
409 |
+
"[email protected],",
|
410 |
+
"[email protected]"])
|
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, "", "[email protected]")
|
416 |
+
mail.send_message(["[email protected],",
|
417 |
+
"[email protected]"])
|
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)
|