OData

Diversas APIs disponíveis no portal de dados abertos do Banco Central implementam o protocolo OData, são centenas de APIs.

O python-bcb tem algumas classes que implementam APIs OData:

Para uma explicação prática das consultas ao IFData, veja IFData.

Estas APIs foram implementadas em classes por serem as mais populares, entretanto, qualquer API OData pode ser acessada através da classe bcb.odata.api.ODataAPI que abstrai o acesso a API a partir da URL da API que está disponível no portal de dados abertos do Banco Central. Veja mais detalhes em Classe ODataAPI.

Timeout por chamada

As APIs OData também aceitam timeout para serviços lentos ou consultas com muitos registros. O timeout informado no construtor é usado na descoberta do serviço, no carregamento dos metadados e como padrão das queries criadas a partir dessa API. Métodos de execução podem receber outro valor para sobrescrever o padrão apenas naquela chamada.

from bcb import Expectativas

em = Expectativas(timeout=120)
ep = em.get_endpoint("ExpectativasMercadoAnuais")

df = ep.get(timeout=60)
raw = ep.query().limit(1000).text(timeout=60)
data = ep.query().limit(1000).collect(timeout=60)

O mesmo parâmetro está disponível nas versões assíncronas async_get, async_text e async_collect.

Segue um exemplo de como acessar a API do PIX.

In [1]: from bcb import SPI

In [2]: pix = SPI()

É necessário importar e criar um objeto da classe que implementa a API, neste caso a classe SPI. Tendo o objeto, executar o método describe para visualizar os endpoints disponíveis na API e suas propriedades. Para obter apenas a listagem curta dos nomes, use describe(full=False).

In [3]: pix.describe()
EntitySets:

EntitySet (Endpoint): PixLiquidadosAtual
EntityType: br.gov.bcb.olinda.servico.SPI.PixLiquidadosAtual
Properties: Data<datetime>, Quantidade<int>, CanalPrimario<int>, CanalSecundario<int>, Total<float>, Media<float>

EntitySet (Endpoint): PixRemuneracaoContaPI
EntityType: br.gov.bcb.olinda.servico.SPI.PixRemuneracaoContaPI
Properties: DataBase<datetime>, BaseRemuneracaoIF<float>, ValorRemuneradoIF<float>, BaseRemuneracaoTotal<float>, ValorRemuneradoTotal<float>, SelicAnual<float>

EntitySet (Endpoint): PixInterrupcaoSPI
EntityType: br.gov.bcb.olinda.servico.SPI.PixInterrupcaoSPI
Properties: DataHoraInicioInt<str>, DataHoraTerminoInt<str>, Interrupcao<str>

EntitySet (Endpoint): PixLiquidadosIntradia
EntityType: br.gov.bcb.olinda.servico.SPI.PixLiquidadosIntradia
Properties: Horario<str>, QuantidadeMedia<int>, TotalMedio<float>

EntitySet (Endpoint): PixDisponibilidadeSPI
EntityType: br.gov.bcb.olinda.servico.SPI.PixDisponibilidadeSPI
Properties: DataBase<datetime>, Indice<float>, MinimoNormativo<float>

Como vemos, a API do PIX tem 4 endpoints (EntitySets). Para restringir a saída a um endpoint, execute o método describe passando como argumento o nome do endpoint.

In [4]: pix.describe("PixLiquidadosAtual")

EntitySet (Endpoint): PixLiquidadosAtual
EntityType: br.gov.bcb.olinda.servico.SPI.PixLiquidadosAtual
Properties: Data<datetime>, Quantidade<int>, CanalPrimario<int>, CanalSecundario<int>, Total<float>, Media<float>

Vemos que o endpoint PixLiquidadosAtual retorna 4 propriedades:

  • Data<datetime>: data das operações

  • Quantidade<int>: quantidade de operações realizadas na data

  • Total<float>: financeiro das operações realizdas na data

  • Media<float>: média das operações realizadas na data

As propriedades são atributos de objetos da classe bcb.odata.api.Endpoint, retornados pelo método get_endpoint.

In [5]: ep = pix.get_endpoint("PixLiquidadosAtual")

In [6]: ep.Data
Out[6]: <Property Data<datetime>>

In [7]: ep.Media
Out[7]: <Property Media<float>>

Para acessar os dados deste endpoint é necessário executar uma query nesse objeto.

In [8]: ep.query().limit(5).collect()
Out[8]: 
        Data  Quantidade  CanalPrimario  CanalSecundario         Total   Media
0 2025-05-15   203155891      202530064           625827  1.051084e+08  517.38
1 2024-04-19   163588000      163124269           463731  7.911428e+07  483.62
2 2024-05-24   156097661      155912971           184690  6.866069e+07  439.86
3 2024-02-10   140720681      140509596           211085  2.550603e+07  181.25
4 2025-11-18   200922887      200484305           438582  9.788716e+07  487.19

Ao realizar a query no endpoint limitamos a consulta a retornar 10 elementos, apenas para visualizar os dados da consulta. A consulta retorna um DataFrame pandas onde as colunas são as propriedades do endpoint.

Veremos abaixo, com mais detalhes, como realizar consultas nas APIs e quais os tipos de endpoints disponíveis (EntitySets e FunctionImports).

Como Realizar Consultas em APIs OData

As consultas são realizadas através do método query da classe bcb.odata.api.Endpoint. Este método retorna um objeto bcb.odata.framework.ODataQuery que abstrai a consulta e permite executar algumas firulas como: filtros e ordenação. A classe bcb.odata.framework.ODataQuery tem os seguintes métodos:

  • bcb.odata.framework.ODataQuery.filter(): define filtros na consulta, com uma clausula where no SQL.

  • bcb.odata.framework.ODataQuery.select(): seleciona as propriedades retornadas pela consulta.

  • bcb.odata.framework.ODataQuery.orderby(): ordena a consulta pelas propriedades.

  • bcb.odata.framework.ODataQuery.limit(): limita os resultados a n registros.

  • bcb.odata.framework.ODataQuery.parameters(): endpoints do tipo FunctionImports possuem parâmetros que são definidos por este método.

  • bcb.odata.framework.ODataQuery.collect(): o framework tem uma abordagem lazy, dessa forma, este método realiza a consulta trazendo os dados e retornando um DataFrame.

  • bcb.odata.framework.ODataQuery.text(): este método retorna o texto (formato json) retornado pela API.

  • bcb.odata.framework.ODataQuery.show(): imprime a estrutura da consulta.

Os métodos filter, select, orderby, limit e parameters retornam o objeto bcb.odata.framework.ODataQuery, e isso permite a realização de chamadas aninhadas que compõem a consulta.

Por exemplo, na consulta do PIX, as datas não estão ordenadas, temos dias de 2021, 2022 e 2023 nos 10 registros retornados. Vamos ordernar pela propriedade Data de forma decrescente.

In [9]: ep.query().orderby(ep.Data.desc()).limit(5).collect()
Out[9]: 
        Data  Quantidade  CanalPrimario  CanalSecundario         Total   Media
0 2026-06-14   175592940      175171310           421630  2.242838e+07  127.73
1 2026-06-13   235796306      235292263           504043  3.499939e+07  148.43
2 2026-06-12   254528967      253751905           777062  1.209410e+08  475.16
3 2026-06-11   239210494      238471195           739299  1.149050e+08  480.35
4 2026-06-10   258814871      257440361          1374510  1.546446e+08  597.51

Veja que a consulta retorna as datas mais recentes primeiro.

Gosto de estruturar as consultas como uma query SQL. Sigamos com um exemplo:

select Data, Media
from PIX
where Data >= "2023-01-01"
order by Media desc
limit 10

Quero obter os 10 dias em 2023 que apresentam as maiores médias transacionadas no PIX.

Para executar essa query utilizo o método select passando as propriedades Data e Media, encadeio o método filter filtrando a propriedade Data maiores que 2023-01-01, e note que aqui utilizo um objeto date; objetos datetime também são aceitos. Na descrição do endpoint PixLiquidadosAtual, a propriedade Data aparece como datetime porque representa um campo OData Edm.Date. Sigo com o método orderby passando a propriedade média e indicando que a ordenação é decrescente e concluo com o método limit para obter os 10 primeiros registros. Na última linha executo o método collect que executa a consulta e retorna um DataFrame com os resultados.

In [10]: from datetime import date

In [11]: (ep.query()
   ....:     .select(ep.Data, ep.Media)
   ....:     .filter(ep.Data >= date(2023, 1, 1))
   ....:     .orderby(ep.Media.desc())
   ....:     .limit(5)
   ....:     .collect())
   ....: 
Out[11]: 
        Data   Media
0 2025-06-30  745.06
1 2026-02-18  712.83
2 2025-12-15  707.89
3 2026-03-30  701.97
4 2026-05-04  689.97

Visualizando a Consulta

Algumas consultas podem ficar bastante complicadas, dependendo da quantidade de elementos que compõem a consulta. Para ajudar na construção e na depuração da query, criamos o método show imprime a query na tela, mas não a executa.

In [12]: (ep.query()
   ....:     .select(ep.Data, ep.Media)
   ....:     .filter(ep.Data >= date(2023, 1, 1))
   ....:     .orderby(ep.Media.desc())
   ....:     .limit(5)
   ....:     .show())
   ....: 
URL:
  https://olinda.bcb.gov.br/olinda/servico/SPI/versao/v1/odata/PixLiquidadosAtual
Query Parameters:
  $format = json
  $filter = Data ge 2023-01-01
  $orderby = Media desc
  $select = Data,Media
  $top = 5
Return: Data<datetime>, Quantidade<int>, CanalPrimario<int>, CanalSecundario<int>, Total<float>, Media<float>

Filtrando Dados

Os filtros são criados com o método filter e aplicados às propriedades do endpoint, por isso é necessário conhecê-lo, o que deve ser feito com o método describe.

In [13]: from bcb import Expectativas

In [14]: em = Expectativas()

In [15]: em.describe('ExpectativasMercadoTop5Anuais')

EntitySet (Endpoint): ExpectativasMercadoTop5Anuais
EntityType: br.gov.bcb.olinda.servico.Expectativas.ExpectativasMercadoTop5Anual
Properties: Indicador<str>, Data<str>, DataReferencia<str>, tipoCalculo<str>, Media<float>, Mediana<float>, DesvioPadrao<float>, Minimo<float>, Maximo<float>

O endpoint ExpectativasMercadoTop5Anuais da API de Expectativas possui a propriedade Indicador, do tipo str. Vamos filtrar os dados com a propriedade Indicador igual a IPCA. Como o tipo dessa propriedade é str, utilizamos uma string no filtro e o operador ==, que representa igualdade.

In [16]: ep = em.get_endpoint('ExpectativasMercadoTop5Anuais')

In [17]: query = ep.query().filter(ep.Indicador == 'IPCA').limit(5)

In [18]: query.show()
URL:
  https://olinda.bcb.gov.br/olinda/servico/Expectativas/versao/v1/odata/ExpectativasMercadoTop5Anuais
Query Parameters:
  $format = json
  $filter = Indicador eq 'IPCA'
  $top = 5
Return: Indicador<str>, Data<str>, DataReferencia<str>, tipoCalculo<str>, Media<float>, Mediana<float>, DesvioPadrao<float>, Minimo<float>, Maximo<float>

O método show apresenta os parâmetros da query formatados, com isso podemos visualizar como os parâmetros da consulta serão enviados à API. Note que o operador == foi convertido para eq. Podemos utilizar todos os operadores de comparação nos filtros.

In [19]: query.collect()
Out[19]: 
  Indicador       Data DataReferencia  ... DesvioPadrao  Minimo  Maximo
0      IPCA 2018-01-18           2019  ...         0.13    4.00    4.25
1      IPCA 2018-01-18           2020  ...         0.00    4.00    4.00
2      IPCA 2018-01-18           2021  ...         0.11    3.75    4.00
3      IPCA 2018-01-18           2018  ...         0.26    3.27    3.95
4      IPCA 2018-01-19           2019  ...         0.25    3.70    4.30

[5 rows x 9 columns]

Mais filtros podem ser adicionados ao método filter, e também podemos aninhar chamadas do método filter.

In [20]: query = (ep.query()
   ....:            .filter(ep.Indicador == 'IPCA', ep.DataReferencia == 2023)
   ....:            .filter(ep.Data >= date(2022, 1, 1))
   ....:            .filter(ep.tipoCalculo == 'C')
   ....:            .limit(5))
   ....: 

In [21]: query.show()
URL:
  https://olinda.bcb.gov.br/olinda/servico/Expectativas/versao/v1/odata/ExpectativasMercadoTop5Anuais
Query Parameters:
  $format = json
  $filter = Indicador eq 'IPCA' and DataReferencia eq '2023' and Data ge '2022-01-01' and tipoCalculo eq 'C'
  $top = 5
Return: Indicador<str>, Data<str>, DataReferencia<str>, tipoCalculo<str>, Media<float>, Mediana<float>, DesvioPadrao<float>, Minimo<float>, Maximo<float>

In [22]: query.collect()
Out[22]: 
  Indicador       Data DataReferencia  ... DesvioPadrao  Minimo  Maximo
0      IPCA 2022-01-03           2023  ...       0.4385     2.5  3.8000
1      IPCA 2022-01-04           2023  ...       0.4385     2.5  3.8000
2      IPCA 2022-01-05           2023  ...       0.4385     2.5  3.8000
3      IPCA 2022-01-06           2023  ...       0.4385     2.5  3.8000
4      IPCA 2022-01-07           2023  ...       0.5711     2.5  4.2693

[5 rows x 9 columns]

Todos os filtros estão no atributo $filter da consulta e são concatenados com o operador booleano and.

Para combinar condições com or, use o operador | entre filtros. Use parênteses em cada comparação, pois | tem precedência diferente dos operadores de comparação do Python.

In [23]: query = (ep.query()
   ....:            .filter((ep.Indicador == 'IPCA') | (ep.Indicador == 'IGP-M'))
   ....:            .filter(ep.DataReferencia == 2023)
   ....:            .limit(5))
   ....: 

In [24]: query.show()
URL:
  https://olinda.bcb.gov.br/olinda/servico/Expectativas/versao/v1/odata/ExpectativasMercadoTop5Anuais
Query Parameters:
  $format = json
  $filter = (Indicador eq 'IPCA' or Indicador eq 'IGP-M') and DataReferencia eq '2023'
  $top = 5
Return: Indicador<str>, Data<str>, DataReferencia<str>, tipoCalculo<str>, Media<float>, Mediana<float>, DesvioPadrao<float>, Minimo<float>, Maximo<float>

Também é possível combinar filtros explicitamente com &. O operador nativo or do Python não deve ser usado, porque ele avalia objetos em contexto booleano em vez de construir uma expressão OData.

É necessário conhecer o tipo da propriedade para saber como passar o objeto para a consulta. Os tipos de propriedade podem ser: str, float, int e datetime. Para propriedades OData Edm.Date, passe um objeto datetime.date ou datetime.datetime para o método filter; strings de data não são convertidas automaticamente pelo construtor de filtros.

In [25]: ep = pix.get_endpoint("PixLiquidadosAtual")

In [26]: (ep.query()
   ....:    .filter(ep.Data >= date(2023, 1, 1))
   ....:    .limit(5)
   ....:    .show())
   ....: 
URL:
  https://olinda.bcb.gov.br/olinda/servico/SPI/versao/v1/odata/PixLiquidadosAtual
Query Parameters:
  $format = json
  $filter = Data ge 2023-01-01
  $top = 5
Return: Data<datetime>, Quantidade<int>, CanalPrimario<int>, CanalSecundario<int>, Total<float>, Media<float>

O objeto date ou datetime é formatado como data na consulta; note que não há aspas na definição da data no filtro.

Ordenando os Dados

A ordenação é definida no método orderby passando um objeto da classe bcb.odata.framework.ODataPropertyOrderBy que é obtida dos métodos asc e desc da propriedade.

In [27]: ep = pix.get_endpoint("PixLiquidadosAtual")

In [28]: ep.Data.asc()
Out[28]: <Data asc>

Este objeto é passado para o método orderby na tripa na qual a query é construída.

In [29]: query = (ep.query()
   ....:            .orderby(ep.Data.asc())
   ....:            .limit(5))
   ....: 

In [30]: query.show()
URL:
  https://olinda.bcb.gov.br/olinda/servico/SPI/versao/v1/odata/PixLiquidadosAtual
Query Parameters:
  $format = json
  $orderby = Data asc
  $top = 5
Return: Data<datetime>, Quantidade<int>, CanalPrimario<int>, CanalSecundario<int>, Total<float>, Media<float>

In [31]: query.collect()
Out[31]: 
        Data  Quantidade CanalPrimario CanalSecundario     Total   Media
0 2020-11-03        2345          None            None    210.24   89.65
1 2020-11-04        2629          None            None    336.37  127.94
2 2020-11-05       16669          None            None   2685.84  161.13
3 2020-11-06       57936          None            None  21133.81  364.78
4 2020-11-07       11089          None            None   2333.89  210.47

O método orderby pode receber diversas propriedades para a definição da ordenação.

In [32]: ep = em.get_endpoint('ExpectativasMercadoTop5Anuais')

In [33]: query = (ep.query()
   ....:            .orderby(ep.Data.desc(), ep.Indicador.desc())
   ....:            .limit(5))
   ....: 

In [34]: query.show()
URL:
  https://olinda.bcb.gov.br/olinda/servico/Expectativas/versao/v1/odata/ExpectativasMercadoTop5Anuais
Query Parameters:
  $format = json
  $orderby = Data desc,Indicador desc
  $top = 5
Return: Indicador<str>, Data<str>, DataReferencia<str>, tipoCalculo<str>, Media<float>, Mediana<float>, DesvioPadrao<float>, Minimo<float>, Maximo<float>

Também podem ser realizadas chamadas aninhadas do método orderby.

In [35]: query = (ep.query()
   ....:            .orderby(ep.Data.desc())
   ....:            .orderby(ep.Indicador.desc())
   ....:            .limit(5))
   ....: 

In [36]: query.show()
URL:
  https://olinda.bcb.gov.br/olinda/servico/Expectativas/versao/v1/odata/ExpectativasMercadoTop5Anuais
Query Parameters:
  $format = json
  $orderby = Data desc,Indicador desc
  $top = 5
Return: Indicador<str>, Data<str>, DataReferencia<str>, tipoCalculo<str>, Media<float>, Mediana<float>, DesvioPadrao<float>, Minimo<float>, Maximo<float>

Vejam que a consulta é exatamente a mesma.

Selecionando as Propriedades

O médoto select funciona de forma muito semelhante ao select de uma query SQL.

In [37]: ep = em.get_endpoint('ExpectativasMercadoTop5Anuais')

In [38]: (ep.query()
   ....:    .select(ep.Indicador, ep.Data, ep.DataReferencia, ep.tipoCalculo, ep.Media)
   ....:    .orderby(ep.Data.desc())
   ....:    .limit(5)
   ....:    .collect())
   ....: 
Out[38]: 
  Indicador       Data DataReferencia tipoCalculo   Media
0    Câmbio 2026-06-05           2026           M  5.0400
1    Câmbio 2026-06-05           2027           M  5.0090
2    Câmbio 2026-06-05           2028           M  5.0750
3    Câmbio 2026-06-05           2029           M  5.1753
4    Câmbio 2026-06-05           2030           M  5.2878

Selecionar as colunas é importante para reduzir o volume de dados trafegado, pois a API do BCB não tem um bom desempenho, logo, essas configurações aceleram as consultas.

Método limit

O método limit define a quantidade de linhas que será retornada pela consulta. Esse método é importante para investigar as consultas na API de forma rápida.

In [39]: ep = pix.get_endpoint("PixLiquidadosAtual")

In [40]: (ep.query()
   ....:    .filter(ep.Data >= date(2023, 1, 1))
   ....:    .limit(5)
   ....:    .collect())
   ....: 
Out[40]: 
        Data  Quantidade  CanalPrimario  CanalSecundario         Total   Media
0 2025-05-15   203155891      202530064           625827  1.051084e+08  517.38
1 2024-04-19   163588000      163124269           463731  7.911428e+07  483.62
2 2024-05-24   156097661      155912971           184690  6.866069e+07  439.86
3 2024-02-10   140720681      140509596           211085  2.550603e+07  181.25
4 2025-11-18   200922887      200484305           438582  9.788716e+07  487.19

Tipos de endpoints

Como foi visto anteriormente, a API do PIX (SPI) possui 4 EntitySets e estes são os endpoints dessa API. Entretanto, há APIs que têm um outro tipo de endpoint, os FunctionImports. A API do PTAX, por exemplo

In [41]: from bcb import PTAX

In [42]: ptax = PTAX()

In [43]: ptax.describe()
EntitySets:

EntitySet (Endpoint): Moedas
EntityType: br.gov.bcb.olinda.servico.PTAX.TipoMoeda
Properties: simbolo<str>, nomeFormatado<str>, tipoMoeda<str>
FunctionImports:

Function: CotacaoMoedaPeriodoFechamento
Parameters: codigoMoeda <str>, dataInicialCotacao <str>, dataFinalCotacao <str>
EntitySet: _CotacaoMoedaPeriodoFechamento
EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoDolarAberturaOuIntermediario
Properties: cotacaoCompra <float>, cotacaoVenda <float>, dataHoraCotacao <str>, tipoBoletim <str>

Function: CotacaoMoedaAberturaOuIntermediario
Parameters: codigoMoeda <str>, dataCotacao <str>
EntitySet: _CotacaoMoedaAberturaOuIntermediario
EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoDolarAberturaOuIntermediario
Properties: cotacaoCompra <float>, cotacaoVenda <float>, dataHoraCotacao <str>, tipoBoletim <str>

Function: CotacaoMoedaDia
Parameters: moeda <str>, dataCotacao <str>
EntitySet: _CotacaoMoedaDia
EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoMoeda
Properties: paridadeCompra <float>, paridadeVenda <float>, cotacaoCompra <float>, cotacaoVenda <float>, dataHoraCotacao <str>, tipoBoletim <str>

Function: CotacaoMoedaPeriodo
Parameters: moeda <str>, dataInicial <str>, dataFinalCotacao <str>
EntitySet: _CotacaoMoedaPeriodo
EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoMoeda
Properties: paridadeCompra <float>, paridadeVenda <float>, cotacaoCompra <float>, cotacaoVenda <float>, dataHoraCotacao <str>, tipoBoletim <str>

Function: CotacaoDolarDia
Parameters: dataCotacao <str>
EntitySet: _CotacaoDolarDia
EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoDolar
Properties: cotacaoCompra <float>, cotacaoVenda <float>, dataHoraCotacao <str>

Function: CotacaoDolarPeriodo
Parameters: dataInicial <str>, dataFinalCotacao <str>
EntitySet: _CotacaoDolarPeriodo
EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoDolar
Properties: cotacaoCompra <float>, cotacaoVenda <float>, dataHoraCotacao <str>

Esta API tem 1 EntitySet e 6 FunctionImports. Assim como os EntitySets, os FunctionImports também retornam dados em formato tabular. A principal diferença entre os EntitySets e FunctionImports é que estes possuem parâmetros, como uma função, e estes parâmetros devem ser definidos para que a consulta seja realizada.

Vamos ver o endpoint CotacaoMoedaPeriodo

In [44]: ptax.describe("CotacaoMoedaPeriodo")

Function: CotacaoMoedaPeriodo
Parameters: moeda <str>, dataInicial <str>, dataFinalCotacao <str>
EntitySet: _CotacaoMoedaPeriodo
EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoMoeda
Properties: paridadeCompra <float>, paridadeVenda <float>, cotacaoCompra <float>, cotacaoVenda <float>, dataHoraCotacao <str>, tipoBoletim <str>

Este endpoint tem 3 parâmetros:

  • codigoMoeda <str>

  • dataInicial <str>

  • dataFinalCotacao <str>

Para conhecer como os parâmetros devem ser definidos é necessário ler a documentação da API. Eventualmente a definição dos parâmetros não é óbvia. Os parâmetros de data da PTAX aceitam strings ISO (YYYY-MM-DD), datetime.date, datetime.datetime e pandas.Timestamp. Strings já no formato PTAX também continuam aceitas. A biblioteca converte os valores generalizados para o formato aceito pelo serviço PTAX: M/D/YYYY (mês/dia/ano, sem zero à esquerda).

Vamos realizar uma consulta para obter as cotações de dólar americano entre 2022-01-01 e 2022-01-05.

In [45]: ep = ptax.get_endpoint("CotacaoMoedaPeriodo")

In [46]: (ep.query()
   ....:    .parameters(moeda="USD",
   ....:                dataInicial="2022-01-01",
   ....:                dataFinalCotacao="2022-01-05")
   ....:    .collect())
   ....: 
Out[46]: 
    paridadeCompra  paridadeVenda  ...         dataHoraCotacao    tipoBoletim
0              1.0            1.0  ... 2022-01-03 10:04:22.186       Abertura
1              1.0            1.0  ... 2022-01-03 11:11:42.883  Intermediário
2              1.0            1.0  ... 2022-01-03 12:09:19.760  Intermediário
3              1.0            1.0  ... 2022-01-03 13:11:50.353  Intermediário
4              1.0            1.0  ... 2022-01-03 13:11:50.357     Fechamento
5              1.0            1.0  ... 2022-01-04 10:05:22.015       Abertura
6              1.0            1.0  ... 2022-01-04 11:05:20.148  Intermediário
7              1.0            1.0  ... 2022-01-04 12:10:19.466  Intermediário
8              1.0            1.0  ... 2022-01-04 13:08:59.118  Intermediário
9              1.0            1.0  ... 2022-01-04 13:08:59.123     Fechamento
10             1.0            1.0  ... 2022-01-05 10:06:19.404       Abertura
11             1.0            1.0  ... 2022-01-05 11:06:19.009  Intermediário
12             1.0            1.0  ... 2022-01-05 12:03:19.428  Intermediário
13             1.0            1.0  ... 2022-01-05 13:07:53.088  Intermediário
14             1.0            1.0  ... 2022-01-05 13:07:53.094     Fechamento

[15 rows x 6 columns]

Note que a primeira data é 2022-01-03, pois os primeiros dias do ano não são úteis. Podemos aplicar filtros nessa consulta utilizando o método filter, da mesma forma que realizamos na consulta ao EntitySet.

In [47]: (ep.query()
   ....:    .parameters(moeda="USD",
   ....:                dataInicial="2022-01-01",
   ....:                dataFinalCotacao="2022-01-05")
   ....:    .filter(ep.tipoBoletim == "Fechamento")
   ....:    .collect())
   ....: 
Out[47]: 
   paridadeCompra  paridadeVenda  ...         dataHoraCotacao  tipoBoletim
0             1.0            1.0  ... 2022-01-03 13:11:50.357   Fechamento
1             1.0            1.0  ... 2022-01-04 13:08:59.123   Fechamento
2             1.0            1.0  ... 2022-01-05 13:07:53.094   Fechamento

[3 rows x 6 columns]

Obtendo o Texto da API

Uma alternativa ao DataFrame retornado pela consulta, via o método collect, é obter o texto, em formato JSON (padrão) ou XML, retornado pela consulta.

O método collect faz o parsing do texto retornado na consulta e cria um DataFrame, o método text retorna esse texto bruto.

Isso é útil para fazer o armazenamento de dados da API para a construção de bancos de dados ou data lakes.

Para obter o conteúdo bruto, basta executar o método text ao invés do collect, ao fim da cadeia da consulta.

In [48]: ep = em.get_endpoint('ExpectativasMercadoTop5Anuais')

In [49]: (ep.query()
   ....:    .select(ep.Indicador, ep.Data, ep.DataReferencia, ep.tipoCalculo, ep.Media)
   ....:    .orderby(ep.Data.desc())
   ....:    .limit(5)
   ....:    .text())
   ....: 
Out[49]: '{"@odata.context":"https://was-p.bcnet.bcb.gov.br/olinda/servico/Expectativas/versao/v1/odata$metadata#ExpectativasMercadoTop5Anuais(Indicador,Data,DataReferencia,tipoCalculo,Media)","value":[{"Indicador":"Câmbio","Data":"2026-06-05","DataReferencia":"2026","tipoCalculo":"M","Media":5.0400},{"Indicador":"Câmbio","Data":"2026-06-05","DataReferencia":"2027","tipoCalculo":"M","Media":5.0090},{"Indicador":"Câmbio","Data":"2026-06-05","DataReferencia":"2028","tipoCalculo":"M","Media":5.0750},{"Indicador":"Câmbio","Data":"2026-06-05","DataReferencia":"2029","tipoCalculo":"M","Media":5.1753},{"Indicador":"Câmbio","Data":"2026-06-05","DataReferencia":"2030","tipoCalculo":"M","Media":5.2878}]}'

O texto retornado está no formato JSON. Contudo, as APIs OData também retornam conteúdo em XML. Para isso incluímos o método format na cadeia da consulta e passamos como parâmetro o tipo desejado.

In [50]: ep = em.get_endpoint('ExpectativasMercadoTop5Anuais')

In [51]: (ep.query()
   ....:    .select(ep.Indicador, ep.Data, ep.DataReferencia, ep.tipoCalculo, ep.Media)
   ....:    .orderby(ep.Data.desc())
   ....:    .format("xml")
   ....:    .limit(5)
   ....:    .text())
   ....: 
Out[51]: '<?xml version=\'1.0\' encoding=\'UTF-8\'?><a:feed xmlns:a="http://www.w3.org/2005/Atom" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" xmlns:d="http://docs.oasis-open.org/odata/ns/data" m:context="https://was-p.bcnet.bcb.gov.br/olinda/servico/Expectativas/versao/v1/odata$metadata#ExpectativasMercadoTop5Anuais(Indicador,Data,DataReferencia,tipoCalculo,Media)"><a:entry><a:title/><a:summary/><a:updated>2026-06-15T07:22:25Z</a:updated><a:author><a:name/></a:author><a:category scheme="http://docs.oasis-open.org/odata/ns/scheme" term="#br.gov.bcb.olinda.servico.Expectativas.ExpectativasMercadoTop5Anual"/><a:content type="application/xml"><m:properties><d:Indicador>Câmbio</d:Indicador><d:Data>2026-06-05</d:Data><d:DataReferencia>2026</d:DataReferencia><d:tipoCalculo>M</d:tipoCalculo><d:Media m:type="Decimal">5.0400</d:Media></m:properties></a:content></a:entry><a:entry><a:title/><a:summary/><a:updated>2026-06-15T07:22:25Z</a:updated><a:author><a:name/></a:author><a:category scheme="http://docs.oasis-open.org/odata/ns/scheme" term="#br.gov.bcb.olinda.servico.Expectativas.ExpectativasMercadoTop5Anual"/><a:content type="application/xml"><m:properties><d:Indicador>Câmbio</d:Indicador><d:Data>2026-06-05</d:Data><d:DataReferencia>2027</d:DataReferencia><d:tipoCalculo>M</d:tipoCalculo><d:Media m:type="Decimal">5.0090</d:Media></m:properties></a:content></a:entry><a:entry><a:title/><a:summary/><a:updated>2026-06-15T07:22:25Z</a:updated><a:author><a:name/></a:author><a:category scheme="http://docs.oasis-open.org/odata/ns/scheme" term="#br.gov.bcb.olinda.servico.Expectativas.ExpectativasMercadoTop5Anual"/><a:content type="application/xml"><m:properties><d:Indicador>Câmbio</d:Indicador><d:Data>2026-06-05</d:Data><d:DataReferencia>2028</d:DataReferencia><d:tipoCalculo>M</d:tipoCalculo><d:Media m:type="Decimal">5.0750</d:Media></m:properties></a:content></a:entry><a:entry><a:title/><a:summary/><a:updated>2026-06-15T07:22:25Z</a:updated><a:author><a:name/></a:author><a:category scheme="http://docs.oasis-open.org/odata/ns/scheme" term="#br.gov.bcb.olinda.servico.Expectativas.ExpectativasMercadoTop5Anual"/><a:content type="application/xml"><m:properties><d:Indicador>Câmbio</d:Indicador><d:Data>2026-06-05</d:Data><d:DataReferencia>2029</d:DataReferencia><d:tipoCalculo>M</d:tipoCalculo><d:Media m:type="Decimal">5.1753</d:Media></m:properties></a:content></a:entry><a:entry><a:title/><a:summary/><a:updated>2026-06-15T07:22:25Z</a:updated><a:author><a:name/></a:author><a:category scheme="http://docs.oasis-open.org/odata/ns/scheme" term="#br.gov.bcb.olinda.servico.Expectativas.ExpectativasMercadoTop5Anual"/><a:content type="application/xml"><m:properties><d:Indicador>Câmbio</d:Indicador><d:Data>2026-06-05</d:Data><d:DataReferencia>2030</d:DataReferencia><d:tipoCalculo>M</d:tipoCalculo><d:Media m:type="Decimal">5.2878</d:Media></m:properties></a:content></a:entry></a:feed>'

O parâmetro output='text'

Para pipelines de dados onde é necessário persistir o dado bruto antes de qualquer transformação (camada SOR/SOT), o parâmetro output='text' pode ser passado diretamente ao método collect ou ao método get do endpoint. Isso evita serializar um DataFrame de volta para texto, o que pode ser uma operação com perda de informação.

ep = em.get_endpoint('ExpectativasMercadoTop5Anuais')

# via query chain
raw = (ep.query()
          .filter(ep.Indicador == 'IPCA')
          .limit(100)
          .collect(output='text'))

# via atalho get()
raw = ep.get(ep.Indicador == 'IPCA', limit=100, output='text')

# salvar em disco
with open('expectativas_raw.json', 'w') as f:
    f.write(raw)

O texto retornado é o JSON bruto da resposta OData, incluindo o campo @odata.context e o array value. O comportamento padrão (retorno de DataFrame) é mantido quando o parâmetro não é informado.

Classe ODataAPI

O portal de Dados Abertos do Banco Central apresenta diversas APIs OData, são dezenas de APIs disponíveis. A URL com metadados de cada API pode ser obtida no portal. A classe bcb.odata.api.ODataAPI permite acessar qualquer API OData de posse da sua URL.

Por exemplo, a API de estatísticas de operações registradas no Selic tem a seguinte URL:

https://olinda.bcb.gov.br/olinda/servico/selic_operacoes/versao/v1/odata/

que pode ser obtida no portal de dados abertos no link.

Essa API pode ser diretamente acessada através da classe bcb.odata.api.ODataAPI.

In [52]: from bcb import ODataAPI

In [53]: url = "https://olinda.bcb.gov.br/olinda/servico/selic_operacoes/versao/v1/odata/"

In [54]: service = ODataAPI(url)

In [55]: service.describe()
EntitySets:

EntitySet (Endpoint): DatasOperacoesSelic
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.DataMov
Properties: DataMovimento<str>

EntitySet (Endpoint): OperacoesDisponiveis
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.OperacoesDisponiveis
Properties: Codigo<str>, Categoria<str>, Descricao<str>

EntitySet (Endpoint): DataMesAnoUltimoMovimentoSelic
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.DataUltimoMovimentoSelic
Properties: DataUltimoMovimento<str>, MesUltimoMovimento<str>, AnoUltimoMovimento<str>

EntitySet (Endpoint): OperacoesRegistradas
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.OperacoesRegistradas
Properties: Codigo<str>, Categoria<str>
FunctionImports:

Function: OperacoesEmUmAno
Parameters: Ano <str>
EntitySet: _OperacoesEmUmAno
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.OperacoesEmUmAno
Properties: Data <datetime>, Codigo <str>, Categoria <str>, Quantidade <int>, Valor <float>

Function: EvolucaoTipoOperacaoMensal
Parameters: Codigo <str>
EntitySet: _EvolucaoTipoOperacaoMensal
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.EvolucaoTipoOperacaoMensal
Properties: Mes <str>, Codigo <str>, QuantidadeAcumulada <int>, ValorAcumulado <float>, QuantidadeMediaDiaria <int>, ValorMedioDiario <float>

Function: OperacoesEmUmaData
Parameters: Data <str>
EntitySet: _OperacoesEmUmaData
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.OperacoesEmUmaData
Properties: Data <datetime>, Codigo <str>, Categoria <str>, Quantidade <int>, Valor <float>

Function: EvolucaoTipoOperacaoDiaria
Parameters: Codigo <str>, Ano <str>
EntitySet: _EvolucaoTipoOperacaoDiaria
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.EvolucaoTipoOperacaoDiaria
Properties: Data <datetime>, Codigo <str>, Quantidade <int>, Valor <float>

Function: OperacoesEmUmMes
Parameters: Mes <str>
EntitySet: _OperacoesEmUmMes
EntityType: br.gov.bcb.olinda.servico.selic_operacoes.OperacoesEmUmMes
Properties: Mes <str>, Codigo <str>, Categoria <str>, QuantidadeAcumulada <int>, ValorAcumulado <float>, QuantidadeMediaDiaria <int>, ValorMedioDiario <float>