IFData

A API IFData do Banco Central do Brasil pode ser acessada pela classe bcb.IFDATA.

Os dados são obtidos a partir do conjunto IFData - Dados selecionados de instituições financeiras do portal de dados abertos do BCB. A documentação oficial informa que o IFData divulga, em formato aberto, relatórios trimestrais de instituições autorizadas a funcionar e em operação normal. As bases de origem citadas pelo BCB são o SCR (Sistema de Informações de Créditos) e o Cosif (Plano Contábil das Instituições do Sistema Financeiro Nacional).

Segundo a metodologia do IFData, os relatórios trimestrais são disponibilizados 60 dias após as datas-bases de março, junho e setembro, e 90 dias após a data-base de dezembro. O portal informa início em março de 2000 e periodicidade trimestral.

Primeiro acesso

O serviço IFData é uma API OData com três FunctionImports. O método describe mostra os nomes dos endpoints, parâmetros e colunas.

Os blocos ipython desta página são executados no build da documentação. Blocos code são exemplos para copiar e adaptar, mas não são executados durante o build.

In [1]: from bcb import IFDATA

In [2]: ifdata = IFDATA(timeout=120)

In [3]: ifdata.describe(full=False)
FunctionImports:
  ListaDeRelatorio
  IfDataCadastro
  IfDataValores

Os endpoints disponíveis são:

ListaDeRelatorio

Lista os relatórios existentes no serviço. Retorna NomeRelatorio e NumeroRelatorio.

IfDataCadastro

Retorna o cadastro de instituições e conglomerados para uma data-base. Recebe o parâmetro AnoMes.

IfDataValores

Retorna os valores de um relatório em formato longo. Recebe os parâmetros AnoMes, TipoInstituicao e Relatorio.

Listando relatórios

O primeiro passo prático é obter o catálogo de relatórios e usar a coluna NumeroRelatorio como parâmetro Relatorio em IfDataValores. Apesar de o parâmetro se chamar Relatorio, o valor esperado é o número retornado em NumeroRelatorio como string.

In [4]: relatorios = (
   ...:     ifdata.get_endpoint("ListaDeRelatorio")
   ...:     .query()
   ...:     .collect()
   ...: )
   ...: 

In [5]: relatorios[["NumeroRelatorio", "NomeRelatorio"]]
Out[5]: 
   NumeroRelatorio                                      NomeRelatorio
0                1                                             Resumo
1                2                                              Ativo
2                3                                            Passivo
3                4                          Demonstração de Resultado
4                5                             Informações de Capital
5                6                                        Segmentação
6                7          Carteira de Crédito Ativa - Por indexador
7                8  Carteira de crédito ativa - por nível de risco...
8                9  Carteira de crédito ativa - por região geográfica
9               10  Carteira de crédito ativa - quantidade de clie...
10              11  Carteira de crédito ativa Pessoa Física - moda...
11              12  Carteira de crédito ativa Pessoa Jurídica -  p...
12              13  Carteira de crédito ativa Pessoa Jurídica - mo...
13              14  Carteira de crédito ativa Pessoa Jurídica - po...
14              15                Movimentação de Câmbio no Trimestre
15              16  Carteira de crédito ativa - por carteiras de i...

Na versão atual do serviço, alguns relatórios relevantes são:

  • "1": Resumo

  • "7": Carteira de Crédito Ativa - Por indexador

  • "8": Carteira de crédito ativa - por nível de risco da operação

  • "9": Carteira de crédito ativa - por região geográfica

  • "10": Carteira de crédito ativa - quantidade de clientes e de operações

  • "11": Carteira de crédito ativa Pessoa Física - modalidade e prazo de vencimento

  • "12": Carteira de crédito ativa Pessoa Jurídica - por atividade econômica (CNAE)

  • "13": Carteira de crédito ativa Pessoa Jurídica - modalidade e prazo de vencimento

  • "14": Carteira de crédito ativa Pessoa Jurídica - por porte do tomador

Use sempre ListaDeRelatorio quando for construir uma análise nova, pois a disponibilidade de relatórios pode mudar ao longo do tempo.

Parâmetros principais

AnoMes

Data-base no formato AAAAMM, por exemplo 202403 para março de 2024. O IFData é trimestral; na prática, use meses 03, 06, 09 e 12.

TipoInstituicao

Nível de consolidação usado no relatório. No endpoint OData, os códigos práticos são:

  • 1: Conglomerados Prudenciais e Instituições Independentes.

  • 2: Conglomerados Financeiros e Instituições Independentes.

  • 3: Instituições Individuais.

A interface web do IFData usa ids internos diferentes nos seus arquivos, como 1009, 1005 e 1006. Esses ids não são os códigos esperados por IfDataValores no python-bcb.

Relatorio

Código do relatório, como string, retornado por ListaDeRelatorio. Exemplo: "1" para Resumo e "11" para o relatório de carteira de crédito ativa de pessoa física por modalidade e prazo.

Consultando cadastro

O cadastro ajuda a interpretar CodInst e a distinguir instituições individuais de conglomerados. A coluna Data é convertida para datetime64 pelo python-bcb.

In [6]: cadastro_ep = ifdata.get_endpoint("IfDataCadastro")

In [7]: cadastro = (
   ...:     cadastro_ep.query()
   ...:     .parameters(AnoMes=202403)
   ...:     .limit(10)
   ...:     .collect()
   ...: )
   ...: 

In [8]: cadastro[
   ...:     [
   ...:         "Data",
   ...:         "CodInst",
   ...:         "NomeInstituicao",
   ...:         "Td",
   ...:         "CodConglomeradoFinanceiro",
   ...:         "CodConglomeradoPrudencial",
   ...:     ]
   ...: ]
   ...: 
Out[8]: 
        Data   CodInst  ... CodConglomeradoFinanceiro CodConglomeradoPrudencial
0 2024-03-01  C0041856  ...                  C0041856                  C0080312
1 2024-03-01  C0080312  ...                  C0041856                  C0080312
2 2024-03-01  C0052302  ...                  C0052302                  C0081579
3 2024-03-01  C0051956  ...                  C0051956                  C0083694
4 2024-03-01  C0083694  ...                  C0051956                  C0083694
5 2024-03-01  01542356  ...                       NaN                       NaN
6 2024-03-01  C0051949  ...                  C0051949                  C0081256
7 2024-03-01  C0081256  ...                  C0051949                  C0081256
8 2024-03-01  09978168  ...                       NaN                       NaN
9 2024-03-01  28195667  ...                  C0041856                  C0080312

[10 rows x 6 columns]

Na versão atual do pacote, se você usar select em IfDataCadastro, mantenha a coluna Data na seleção. A conversão automática de datas desse endpoint espera essa coluna no resultado.

Consultando valores

IfDataValores retorna os dados em formato longo: cada linha identifica instituição, relatório, conta/coluna e valor em Saldo. Para montar uma tabela analítica, normalmente é necessário filtrar NomeColuna ou Conta e depois fazer pivot ou merge com o cadastro.

O exemplo abaixo obtém a métrica Carteira de Crédito Classificada do relatório Resumo para conglomerados prudenciais e instituições independentes na data-base de março de 2024.

In [9]: valores_ep = ifdata.get_endpoint("IfDataValores")

In [10]: credito_resumo = (
   ....:     valores_ep.query()
   ....:     .parameters(AnoMes=202403, TipoInstituicao=1, Relatorio="1")
   ....:     .filter(valores_ep.NomeColuna == "Carteira de Crédito Classificada")
   ....:     .orderby(valores_ep.Saldo.desc())
   ....:     .limit(10)
   ....:     .collect()
   ....: )
   ....: 

In [11]: cadastro_completo = cadastro_ep.query().parameters(AnoMes=202403).collect(timeout=120)

In [12]: credito_resumo = credito_resumo.merge(
   ....:     cadastro_completo[["CodInst", "NomeInstituicao"]],
   ....:     on="CodInst",
   ....:     how="left",
   ....: )
   ....: 

In [13]: credito_resumo[["NomeInstituicao", "AnoMes", "NomeColuna", "Saldo"]]
Out[13]: 
                        NomeInstituicao  ...         Saldo
0  CAIXA ECONÔMICA FEDERAL - PRUDENCIAL  ...  1.145327e+12
1                       BB - PRUDENCIAL  ...  1.002459e+12
2                     ITAU - PRUDENCIAL  ...  9.035385e+11
3                 BRADESCO - PRUDENCIAL  ...  6.367062e+11
4                SANTANDER - PRUDENCIAL  ...  5.280337e+11
5                    BNDES - PRUDENCIAL  ...  3.158338e+11
6              BTG PACTUAL - PRUDENCIAL  ...  1.326218e+11
7                    SAFRA - PRUDENCIAL  ...  1.199716e+11
8            NU PAGAMENTOS - PRUDENCIAL  ...  9.427453e+10
9               VOTORANTIM - PRUDENCIAL  ...  7.469943e+10

[10 rows x 4 columns]

Diferenças entre datasets

O resultado de IfDataValores muda conforme a combinação de AnoMes, TipoInstituicao e Relatorio. A lista de relatórios é um catálogo geral; ela não garante que toda combinação de tipo de instituição e data-base terá dados.

Por exemplo, para AnoMes=202403 a chamada abaixo retornava dados para TipoInstituicao=2 no relatório "11", mas retornava DataFrame vazio para TipoInstituicao=1 e TipoInstituicao=3. Isso não indica necessariamente erro de rede; normalmente indica que aquela combinação de parâmetros não existe no conjunto divulgado.

In [14]: pf_tipo_2 = (
   ....:     valores_ep.query()
   ....:     .parameters(AnoMes=202403, TipoInstituicao=2, Relatorio="11")
   ....:     .filter(valores_ep.NomeColuna == "Total da Carteira de Pessoa Física")
   ....:     .limit(10)
   ....:     .collect()
   ....:     .merge(
   ....:         cadastro_completo[["CodInst", "NomeInstituicao"]],
   ....:         on="CodInst",
   ....:         how="left",
   ....:     )
   ....: )
   ....: 

In [15]: pf_tipo_2[
   ....:     ["TipoInstituicao", "NomeInstituicao", "NomeRelatorio", "NomeColuna", "Saldo"]
   ....: ]
   ....: 
Out[15]: 
   TipoInstituicao  ...         Saldo
0                2  ...  2.712441e+08
1                2  ...  6.148027e+08
2                2  ...  0.000000e+00
3                2  ...  2.496343e+08
4                2  ...  8.293921e+05
5                2  ...  2.427435e+06
6                2  ...  0.000000e+00
7                2  ...  7.439081e+07
8                2  ...  0.000000e+00
9                2  ...  7.978122e+07

[10 rows x 5 columns]

Ao explorar um relatório novo, comece com limit e filtros seletivos. Depois verifique NomeRelatorio, NumeroRelatorio, NomeColuna e DescricaoColuna antes de agregar valores.

Comparando instituições com dados de crédito

O exemplo abaixo compara as maiores carteiras de crédito classificadas entre instituições individuais em março de 2024. Usamos TipoInstituicao=3 para evitar misturar CNPJs individuais com conglomerados.

In [16]: import pandas as pd

In [17]: ANO_MES = 202403

In [18]: TIPO_INSTITUICAO = 3

In [19]: RELATORIO_RESUMO = "1"

In [20]: valores_ep = ifdata.get_endpoint("IfDataValores")

In [21]: cadastro_ep = ifdata.get_endpoint("IfDataCadastro")

In [22]: credito = (
   ....:     valores_ep.query()
   ....:     .parameters(
   ....:         AnoMes=ANO_MES,
   ....:         TipoInstituicao=TIPO_INSTITUICAO,
   ....:         Relatorio=RELATORIO_RESUMO,
   ....:     )
   ....:     .filter(valores_ep.NomeColuna == "Carteira de Crédito Classificada")
   ....:     .orderby(valores_ep.Saldo.desc())
   ....:     .limit(10)
   ....:     .collect()
   ....: )
   ....: 

In [23]: comparativo = (
   ....:     credito.merge(
   ....:         cadastro_completo[["CodInst", "NomeInstituicao", "Tcb", "Td", "Sr"]],
   ....:         on="CodInst",
   ....:         how="left",
   ....:     )
   ....:     .assign(
   ....:         Saldo_bilhoes=lambda df: df["Saldo"] / 1e9,
   ....:         Participacao_top10=lambda df: df["Saldo"] / df["Saldo"].sum(),
   ....:     )
   ....:     [
   ....:         [
   ....:             "NomeInstituicao",
   ....:             "Saldo_bilhoes",
   ....:             "Participacao_top10",
   ....:             "Tcb",
   ....:             "Td",
   ....:             "Sr",
   ....:         ]
   ....:     ]
   ....: )
   ....: 

In [24]: comparativo
Out[24]: 
                                     NomeInstituicao  Saldo_bilhoes  ...  Td  Sr
0                            CAIXA ECONOMICA FEDERAL    1144.247533  ...   I  S1
1                               BANCO DO BRASIL S.A.     962.121150  ...   I  S1
2                                BANCO BRADESCO S.A.     524.134927  ...   I  S1
3                                 ITAÚ UNIBANCO S.A.     424.029001  ...   I  S1
4                      BANCO SANTANDER (BRASIL) S.A.     364.386374  ...   I  S1
5  BANCO NACIONAL DE DESENVOLVIMENTO ECONOMICO E ...     281.124087  ...   I  S2
6                         ITAÚ UNIBANCO HOLDING S.A.     154.194902  ...   I  S1
7                                   BANCO SAFRA S.A.      71.531846  ...   I  S2
8                              BANCO VOTORANTIM S.A.      68.560584  ...   I  S2
9  AYMORÉ CRÉDITO, FINANCIAMENTO E INVESTIMENTO S.A.      62.504463  ...   I  S1

[10 rows x 6 columns]
In [25]: ax = comparativo.sort_values("Saldo_bilhoes").plot.barh(x="NomeInstituicao", y="Saldo_bilhoes", legend=False, figsize=(13, 7), xlabel="Saldo / 1e9", ylabel="", title="Carteira de crédito classificada - instituições individuais")

In [26]: ax.figure.subplots_adjust(left=0.42)

In [27]: ax;
_images/ifdata_credito_comparativo.png

O campo Saldo é o valor numérico retornado pela API. A unidade e a forma de apresentação podem variar por relatório; antes de publicar valores monetários, confira DescricaoColuna e a composição/nota do relatório na interface IF.data.

Evolução temporal

Para analisar evolução temporal, consulte poucas datas-bases e mantenha o mesmo TipoInstituicao e o mesmo NomeColuna ao longo da série. O exemplo abaixo acompanha cinco instituições individuais em cinco trimestres.

In [28]: import pandas as pd

In [29]: from bcb import IFDATA

In [30]: ifdata = IFDATA(timeout=120)

In [31]: valores_ep = ifdata.get_endpoint("IfDataValores")

In [32]: cadastro_ep = ifdata.get_endpoint("IfDataCadastro")

In [33]: filtro_codigos = ((valores_ep.CodInst == "00360305") | (valores_ep.CodInst == "00000000") | (valores_ep.CodInst == "60701190") | (valores_ep.CodInst == "60746948") | (valores_ep.CodInst == "90400888"))

In [34]: credito_202303 = valores_ep.query().parameters(AnoMes=202303, TipoInstituicao=3, Relatorio="1").filter(valores_ep.NomeColuna == "Carteira de Crédito Classificada", filtro_codigos).collect().assign(AnoMes=202303)

In [35]: credito_202306 = valores_ep.query().parameters(AnoMes=202306, TipoInstituicao=3, Relatorio="1").filter(valores_ep.NomeColuna == "Carteira de Crédito Classificada", filtro_codigos).collect().assign(AnoMes=202306)

In [36]: credito_202309 = valores_ep.query().parameters(AnoMes=202309, TipoInstituicao=3, Relatorio="1").filter(valores_ep.NomeColuna == "Carteira de Crédito Classificada", filtro_codigos).collect().assign(AnoMes=202309)

In [37]: credito_202312 = valores_ep.query().parameters(AnoMes=202312, TipoInstituicao=3, Relatorio="1").filter(valores_ep.NomeColuna == "Carteira de Crédito Classificada", filtro_codigos).collect().assign(AnoMes=202312)

In [38]: credito_202403 = valores_ep.query().parameters(AnoMes=202403, TipoInstituicao=3, Relatorio="1").filter(valores_ep.NomeColuna == "Carteira de Crédito Classificada", filtro_codigos).collect().assign(AnoMes=202403)

In [39]: historico = pd.concat([credito_202303, credito_202306, credito_202309, credito_202312, credito_202403], ignore_index=True)

In [40]: cadastro_202403 = cadastro_completo

In [41]: historico = historico.merge(cadastro_202403[["CodInst", "NomeInstituicao"]], on="CodInst", how="left")

In [42]: tabela = historico.pivot_table(index="AnoMes", columns="NomeInstituicao", values="Saldo", aggfunc="first")

In [43]: tabela_bilhoes = tabela / 1e9

In [44]: tabela_bilhoes.index = pd.to_datetime(tabela_bilhoes.index.astype(str), format="%Y%m").strftime("%Y-%m")

In [45]: tabela_bilhoes
Out[45]: 
NomeInstituicao  BANCO BRADESCO S.A.  ...  ITAÚ UNIBANCO S.A.
AnoMes                                ...                    
2023-03                   531.398829  ...          409.533176
2023-06                   520.427360  ...          412.609323
2023-09                   517.835113  ...          419.777465
2023-12                   520.499627  ...          423.015925
2024-03                   524.134927  ...          424.029001

[5 rows x 5 columns]
In [46]: ax = tabela_bilhoes.plot(figsize=(13, 6), marker="o", xlabel="Data-base", ylabel="Saldo / 1e9", title="Evolução da carteira de crédito classificada")

In [47]: ax.legend(loc="center left", bbox_to_anchor=(1.0, 0.5), fontsize=8)
Out[47]: <matplotlib.legend.Legend at 0x7f5c87975580>

In [48]: ax.figure.subplots_adjust(right=0.62)

In [49]: ax;
_images/ifdata_credito_evolucao.png

Cuidados de interpretação

  • Não some resultados de TipoInstituicao diferentes. Eles representam níveis de consolidação distintos e podem conter sobreposição.

  • CodInst muda de significado conforme o nível de consolidação. Em conglomerados, códigos como C008... representam entidades consolidadas; em instituições individuais, os códigos são de instituições separadas por personalidade jurídica.

  • Instituições individuais são apresentadas em nível não consolidado. A metodologia do BCB informa que participações societárias e agências no exterior são registradas como investimento nesse formato.

  • Conglomerados financeiros consolidam entidades financeiras vinculadas. Conglomerados prudenciais são mais amplos e podem incluir, conforme a metodologia, administradoras de consórcio, instituições de pagamento e outras entidades relevantes para risco prudencial.

  • Um DataFrame vazio pode significar combinação inexistente de AnoMes, TipoInstituicao e Relatorio. Confirme trocando um parâmetro por vez e consultando primeiro ListaDeRelatorio.

  • As notas dos relatórios do IFData podem trazer regras específicas como NI para informações não prestadas até a publicação, NA para não aplicável e republicação de informações quando há reapresentação.

  • O BCB informa que não há informações sobre administradores de consórcios na metodologia geral do IFData.

  • Consultas amplas podem ser lentas. Prefira filtros, limit e poucos períodos por chamada quando estiver explorando em notebook.

Fontes oficiais