Acceso a los reportes de la SIBOIF Nicaragua con Python: Indicadores Financieros¶
En una entrada anterior publiqué un procedimiento de cómo acceder a los datos de la SIBOIF, sin embargo, en esa ocasión el ejercicio se realizó con R. En esta ocasión se realizará con Python.
import pandas as pd
import urllib.request, json
import numpy as np
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
Al igual que hice con el ejercicio en R, tengo que crear bloques de consultas anuales debido a un error que se produce en el despacho de la información desde el sitio de la SIBOIF. Así, los bloques de consultas anuales quedarían de la siguiente manera:
url_2019 = "https://www.siboif.gob.ni/rest/estadisticas?intendencia=Bancos&fecha[min]=2019-01-01&fecha[max]=2019-12-31&tipo_reporte=Indicadores%20Financieros"
url_2020 = "https://www.siboif.gob.ni/rest/estadisticas?intendencia=Bancos&fecha[min]=2020-01-01&fecha[max]=2020-12-31&tipo_reporte=Indicadores%20Financieros"
url_2021 = "https://www.siboif.gob.ni/rest/estadisticas?intendencia=Bancos&fecha[min]=2021-01-01&fecha[max]=2021-10-31&tipo_reporte=Indicadores%20Financieros"
Una vez establecidas las urls sobre las que vamos a a extraer la información, sólo haría falta iterar sobre cada una de ellas, leer la información, convertir las listas a dataframes e ir añadiendo nuevo dataframe al anterior, esto se hace con la siguiente instrucción:
for consulta in [url_2019, url_2020, url_2021]:
with urllib.request.urlopen(consulta) as url:
df0 = json.loads(url.read().decode())
df0 = pd.DataFrame(df0)
df = df.append(df0, ignore_index=True)
Así, una vez descargado los datos, podemos confirmar lo que hemos descargado usando la función head()
df.head()
intendencia | tipo_institucion | institucion | tipo_reporte | fecha | orden | grupo | variable_1 | variable_2 | variable_3 | valor_1 | valor_2 | anio | mes | key | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Bancos | Bancos | AVANZ | Indicadores Financieros | 2021-10-31 | 20 | Cuota de Mercado | 1.- Captaciones del Publico | 4310503916.03 | 0.0000 | 2021 | Octubre | 1113-11101.0-20211031-20 | ||
1 | Bancos | Bancos | AVANZ | Indicadores Financieros | 2021-10-31 | 30 | Cuota de Mercado | 2.- Cuota de Mercado en Captaciones del Público | 0.0261 | 0.0000 | 2021 | Octubre | 1113-11101.0-20211031-30 | ||
2 | Bancos | Bancos | AVANZ | Indicadores Financieros | 2021-10-31 | 40 | Cuota de Mercado | 3.- Cartera de Créditos Bruta | 4930074747.52 | 0.0000 | 2021 | Octubre | 1113-11101.0-20211031-40 | ||
3 | Bancos | Bancos | AVANZ | Indicadores Financieros | 2021-10-31 | 50 | Cuota de Mercado | 4.- Cuota de Mercado de Cartera de Créditos Bruta | 0.0384 | 0.0000 | 2021 | Octubre | 1113-11101.0-20211031-50 | ||
4 | Bancos | Bancos | AVANZ | Indicadores Financieros | 2021-10-31 | 70 | Calidad del Activo | 1.- Total Activos Improductivos netos | 1601442356.06 | 0.0000 | 2021 | Octubre | 1113-11101.0-20211031-70 |
Como se puede apreciar se han descargado correctamente los datos y, pese a que noviembre ya finalizó, descargué el mismo conjunto de datos que en el post anterior, para que los resultados sean comparables.
Note que la SIBOIF reporta los números en formatos de miles usando la coma como separador de miles y el punto como separador de decimales, esto genera que nuestro programaa lea esto como texto y no como un número, para lo cual debemos convertir, las variables de interés, a su versión numérica.
df['valor_1'] = pd.to_numeric(df.valor_1.str.replace(',', ''))
Hasta aquí se ha mostrado cómo es que se pueden extraer los datos de la SIBOIF a través de su sitio. Pero podríamos replicar ciertos ejemplos del post anterior, para lo cual, en lugar de importar un nuevo módulo, definimos la función gini
tal cual se define en este sitio https://stackoverflow.com/a/39513799).
def gini(x):
x = x.to_numpy(x)
mad = np.abs(np.subtract.outer(x, x)).mean()
rmad = mad/np.mean(x)
g = 0.5 * rmad
return g
tabla=(df
.query('tipo_institucion == "Bancos" and institucion != "SFB" and variable_1 in ["1.- Captaciones del Publico","3.- Cartera de Créditos Bruta"] and mes == "Octubre" ')
.dropna()
.groupby(['variable_1', 'anio'], as_index=False)
.agg(
Gini = ('valor_1', gini)
)
.sort_values(by='variable_1')
)
tabla['Gini'] = tabla['Gini'].round(2)
tabla
variable_1 | anio | Gini | |
---|---|---|---|
0 | 1.- Captaciones del Publico | 2019 | 0.46 |
1 | 1.- Captaciones del Publico | 2020 | 0.52 |
2 | 1.- Captaciones del Publico | 2021 | 0.53 |
3 | 3.- Cartera de Créditos Bruta | 2019 | 0.42 |
4 | 3.- Cartera de Créditos Bruta | 2020 | 0.50 |
5 | 3.- Cartera de Créditos Bruta | 2021 | 0.49 |
plt.figure(figsize=(10, 5))
sns.lineplot(data=tabla, x='anio', y='Gini', hue="variable_1").set(title='Coeficiente de Gini octubre cada año.')
plt.show()
Pese a que el gráfico anterior indica una tendencia al incrementar el nivel de concentración del mercado bancario nicaragüense, estos datos son cortes anuales a octubre. Para, realmente observar la evolución con mayor precisión, deberíamos graficar los datos con mayor granualidad temporal, es decir, en lugar de anual, hagámoslo mensual.
df['fecha2'] = pd.to_datetime(df.fecha, format='%Y-%m-%d')
tabla2=(df
.query('tipo_institucion == "Bancos" and institucion != "SFB" and variable_1 in ["1.- Captaciones del Publico","3.- Cartera de Créditos Bruta"]')
.dropna()
.groupby(['variable_1', 'fecha2'], as_index=False)
.agg(
Gini = ('valor_1', gini)
)
.sort_values(by='variable_1')
)
tabla2.head()
variable_1 | fecha2 | Gini | |
---|---|---|---|
0 | 1.- Captaciones del Publico | 2019-01-31 | 0.449462 |
19 | 1.- Captaciones del Publico | 2020-08-31 | 0.527816 |
20 | 1.- Captaciones del Publico | 2020-09-30 | 0.521342 |
21 | 1.- Captaciones del Publico | 2020-10-31 | 0.522182 |
22 | 1.- Captaciones del Publico | 2020-11-30 | 0.526249 |
fig, ax = plt.subplots(figsize=(10, 5))
sns.lineplot(data=tabla2, x='fecha2', y='Gini', hue="variable_1")
ax.set_title('Evolución mensual del coeficiente de Gini, Ene 2019- Oct 2021.')
plt.show()
Un gráfico que realmente fue informativo es el que muestra la concentración del sector bancario comparando, año tras año, la cuota de mercado de cada banco:
tabla3=(df
.query('tipo_institucion == "Bancos" and institucion != "SFB" and variable_1 == "4.- Cuota de Mercado de Cartera de Créditos Bruta" and mes == "Octubre"')
.dropna()
.sort_values(by='variable_1')
)
tabla3['anio2'] = pd.to_numeric(tabla3.anio)
p1 = sns.catplot(
data = tabla3.sort_values(by='valor_1', ascending = False),
kind = "bar",
x = "valor_1", y = "institucion", col = "anio2" , aspect = 0.8)
p1.set_axis_labels("Cuota de mercado", "")
sns.despine(offset=10, trim=True)
p1.fig.subplots_adjust(top=0.83) # adjust the Figure in rp
p1.fig.suptitle('Cuota de mercado de cartera de créditos bruta, corte a octubre de cada año')
plt.show()