├── .github └── workflows │ └── sphinx.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bcb ├── __init__.py ├── currency.py ├── odata │ ├── __init__.py │ ├── api.py │ └── framework.py ├── sgs │ ├── __init__.py │ └── regional_economy.py └── utils.py ├── docs ├── Makefile ├── _static │ └── images │ │ ├── ipca12m-acumulado.png │ │ ├── savefig │ │ ├── currency1.png │ │ ├── sgs1.png │ │ └── taxajuros1.png │ │ └── selic.png ├── api.rst ├── conf.py ├── currency.rst ├── expectativas.rst ├── index.rst ├── make.bat ├── odata.rst ├── requirements.txt ├── sgs.rst └── taxajuros.rst ├── notebooks ├── SGS Economia Regional - Inadimplência.ipynb ├── bcb_Expectativas_da_SELIC_(nova_API).ipynb ├── currency PTAX.ipynb ├── currency get EUR parity.ipynb ├── currency get strong currencies.ipynb ├── currency get with side.ipynb ├── currency get.ipynb ├── dinheiro em circulação.ipynb ├── expectativas IPCA anual.ipynb ├── odata ODataAPI.ipynb ├── odata examples.ipynb ├── odata taxas de juros cheque especial.ipynb ├── pix.odata ├── sgs get series with join.ipynb ├── sgs get series with period index.ipynb ├── sgs get series.ipynb └── workspace.ipynb ├── poetry.lock ├── pyproject.toml ├── requirements.txt ├── setup.cfg └── tests ├── __init__.py ├── sgs ├── __init__.py ├── test_regional_economy.py └── test_series.py ├── test_currency.py ├── test_expectativas.py └── test_utils.py /.github/workflows/sphinx.yml: -------------------------------------------------------------------------------- 1 | name: Sphinx build 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | 11 | - name: Set up Python 3.10 12 | uses: actions/setup-python@v4 13 | with: 14 | python-version: '3.10' 15 | 16 | - name: Install dependencies 17 | run: | 18 | python -m pip install --upgrade pip 19 | pip install poetry 20 | poetry install --with docs 21 | 22 | - name: Build docs 23 | run: | 24 | cd docs 25 | poetry run sphinx-build -b html . _build/html 26 | 27 | - name: Upload artifacts 28 | uses: actions/upload-artifact@v4 29 | with: 30 | name: html-docs 31 | path: docs/_build/html/ 32 | 33 | - name: Deploy 34 | uses: peaceiris/actions-gh-pages@v4 35 | if: github.ref == 'refs/heads/main' 36 | with: 37 | github_token: ${{ secrets.GITHUB_TOKEN }} 38 | publish_dir: docs/_build/html -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | __pycache__ 3 | *.__pycache__ 4 | .vscode 5 | .pytest_cache 6 | *.code-workspace 7 | *.egg-info 8 | build 9 | dist 10 | *checkpoint.ipynb 11 | docs/_build/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.3.3] - 2025-04-21 4 | - Improved error handling in SGS API 5 | - Added type hints to the bcb.sgs and sgs.currency modules 6 | - Added function sgs.get_json to retrieve raw JSON data returned from SGS API 7 | 8 | ## [0.3.2] - 2025-03-01 9 | - Poetry lock file updated 10 | - Replaced http with https in SGS URL 11 | 12 | ## [0.3.1] - 2024-12-24 13 | - Add Regional economy series support (tks @anapaulagomes) 14 | 15 | ## [0.3.0] - 2024-06-12 16 | - Dependencies updated 17 | 18 | ## [0.2.0] - 2023-07-22 19 | - Date columns of some OData API endpoints are now formatted in the returned Dataframe (Issue #3) 20 | - New methods ODataQuery.raw and ODataQuery.text 21 | 22 | ## [0.1.9] - 2023-06-26 23 | - Created class bcb.ODataAPI to directly wrap OData APIs 24 | - Updated documentation 25 | - Updated pyproject.toml 26 | 27 | ## [0.1.8] - 2022-09-10 28 | - Updated documentation 29 | - Migrated to poetry 30 | 31 | ## [0.1.7] - 2022-01-22 32 | - Added httpx to install_requirements 33 | - Updated docs 34 | - sgs.TaxaJuros upgraded to v2 35 | 36 | ## [0.1.6] - 2022-01-16 37 | - Updated README 38 | - Updated requirements files including `httpx` 39 | - Added `autosummary_generate` to sphinx conf.py 40 | 41 | 42 | ## [0.1.5] - 2022-01-16 43 | - Implemented the definetive wraper for OData APIs. 44 | - A few APIs have been unlocked: Expectativas, PTAX, taxaJuros, MercadoImobiliario, SPI 45 | - Updated documentation 46 | 47 | ## [0.1.4] - 2021-12-27 48 | - Changed arguments start_date and end_date to start and end to bring conformity with commom python data libraries like Quandl and pandas-datareader, for example. 49 | - bcb.currency.get multi argument, which refers to multivariate time series returned (defaults to True) 50 | - bcb.sgs.get groupby argument 51 | - Sphinx docs implemented 52 | 53 | ## [0.1.3] - 2021-04-14 54 | - BUG fix in get_valid_currency_list: recurrent ConnectionError 55 | - Added side and group_by arguments to currency.get function 56 | - New notebooks with examples 57 | - Added join argument to sgs.get function 58 | 59 | ## [0.1.2] - 2021-01-25 60 | - New sgs module downloads time series from SGS BACEN's site 61 | - Notebooks created to show a few examples 62 | - Date class moved to utils module 63 | 64 | ## [0.1.1] - 2021-01-16 65 | 66 | - Bug fixes 67 | 68 | ## [0.1.0] - 2021-01-16 69 | 70 | - First commit 71 | - currency module downloads currency rates quoted in Brazilian Real (BRL) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Wilson Freitas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-bcb 2 | 3 | **python-bcb** é uma interface em Python estruturada para obter informações 4 | da API de dados abertos do [Banco Central do Brasil](https://www.bcb.gov.br). 5 | 6 | [![Downloads](https://img.shields.io/pypi/dm/python-bcb.svg)](https://pypi.python.org/pypi/python-bcb/) 7 | [![image](https://img.shields.io/pypi/v/python-bcb.svg?color=green)](https://pypi.python.org/pypi/python-bcb/) 8 | ![Sphinx workflow](https://github.com/wilsonfreitas/python-bcb/actions/workflows/sphinx.yml/badge.svg) 9 | 10 | 11 | O projeto de [Dados Abertos do Banco Central do Brasil](https://dadosabertos.bcb.gov.br/) 12 | disponibiliza diversas APIs provendo acesso direto a dados de: 13 | 14 | * Moedas 15 | * Taxas de Juros 16 | * Índices de preços 17 | * Informações de Instituições Financeiras 18 | * Expectativas do Mercado (Expectativas do Boletim FOCUS) 19 | * E muito outros ... 20 | 21 | # Instalação 22 | 23 | **python-bcb** está disponível no [Python Package Index](https://pypi.org/project/python-bcb/) e pode ser instalado via `pip` usando. 24 | 25 | ```shell 26 | pip install python-bcb 27 | ``` 28 | 29 | # APIs 30 | 31 | 32 | ## SGS 33 | Utiliza o webservice do SGS 34 | ([Sistema Gerenciador de Séries Temporais](https://www3.bcb.gov.br/sgspub/)) 35 | para obter os dados. 36 | 37 | ## Conversor de Moedas 38 | 39 | Implementado no módulo `currency`, um conjunto de funções que realiza webscraping 40 | no site do [Conversor de Moedas](https://www.bcb.gov.br/conversao) 41 | do Banco Central, possível obter séries temporais de frequência diária 42 | de diversas moedas. 43 | 44 | ## Moedas OData 45 | 46 | O Banco Central disponibiliza diversas informações em APIs que 47 | seguem o padrão [OData](https://odata.org). 48 | A classe `bcb.PTAX` implementa uma API OData que 49 | entrega os boletins diários de taxas de câmbio do Banco Central. 50 | Esta API entrega mais informações do que o que é obtido no 51 | `Conversor de Moedas`. 52 | 53 | ## Expectativas 54 | 55 | A API de Expectativas de Mercado traz todas as estatísticas das variáveis 56 | macroeconômicas fornecidos por um conjuto de instituições do mercado 57 | financeiro. 58 | A classe `bcb.Expectativas` implementa essa interface no 59 | padrão OData. 60 | -------------------------------------------------------------------------------- /bcb/__init__.py: -------------------------------------------------------------------------------- 1 | from .odata.api import ( 2 | ODataAPI, 3 | Expectativas, 4 | PTAX, 5 | IFDATA, 6 | TaxaJuros, 7 | MercadoImobiliario, 8 | SPI, 9 | TarifasBancariasPorInstituicaoFinanceira, 10 | TarifasBancariasPorServico, 11 | PostosAtendimentoEletronicoPorInstituicaoFinanceira, 12 | PostosAtendimentoCorrespondentesPorInstituicaoFinanceira, 13 | EstatisticasSTR, 14 | DinheiroCirculacao, 15 | ) 16 | -------------------------------------------------------------------------------- /bcb/currency.py: -------------------------------------------------------------------------------- 1 | import re 2 | import warnings 3 | from datetime import date, timedelta 4 | from io import BytesIO, StringIO 5 | from typing import List, Union 6 | 7 | import numpy as np 8 | import pandas as pd 9 | import requests 10 | from lxml import html 11 | 12 | from .utils import Date, DateInput 13 | 14 | """ 15 | O módulo :py:mod:`bcb.currency` tem como objetivo fazer consultas no site do conversor de moedas do BCB. 16 | """ 17 | 18 | 19 | def _currency_url(currency_id: str, start_date: DateInput, end_date: DateInput) -> str: 20 | start_date = Date(start_date) 21 | end_date = Date(end_date) 22 | url = ( 23 | "https://ptax.bcb.gov.br/ptax_internet/consultaBoletim.do?" 24 | "method=gerarCSVFechamentoMoedaNoPeriodo&" 25 | "ChkMoeda={}&DATAINI={:%d/%m/%Y}&DATAFIM={:%d/%m/%Y}" 26 | ) 27 | return url.format(currency_id, start_date.date, end_date.date) 28 | 29 | 30 | CACHE = dict() 31 | 32 | 33 | def _currency_id_list() -> pd.DataFrame: 34 | if CACHE.get("TEMP_CURRENCY_ID_LIST") is not None: 35 | return CACHE.get("TEMP_CURRENCY_ID_LIST") 36 | else: 37 | url1 = "https://ptax.bcb.gov.br/ptax_internet/consultaBoletim.do?" "method=exibeFormularioConsultaBoletim" 38 | res = requests.get(url1) 39 | if res.status_code != 200: 40 | msg = f"BCB API Request error, status code = {res.status_code}" 41 | raise Exception(msg) 42 | 43 | doc = html.parse(BytesIO(res.content)).getroot() 44 | xpath = "//select[@name='ChkMoeda']/option" 45 | x = [(elm.text, elm.get("value")) for elm in doc.xpath(xpath)] 46 | df = pd.DataFrame(x, columns=["name", "id"]) 47 | df["id"] = df["id"].astype("int32") 48 | CACHE["TEMP_CURRENCY_ID_LIST"] = df 49 | return df 50 | 51 | 52 | def _get_valid_currency_list(_date: date, n: int = 0) -> requests.models.Response: 53 | url2 = f"http://www4.bcb.gov.br/Download/fechamento/M{_date:%Y%m%d}.csv" 54 | try: 55 | res = requests.get(url2) 56 | except requests.exceptions.ConnectionError as ex: 57 | if n >= 3: 58 | raise ex 59 | return _get_valid_currency_list(_date, n + 1) 60 | if res.status_code == 200: 61 | return res 62 | else: 63 | return _get_valid_currency_list(_date - timedelta(1), 0) 64 | 65 | 66 | def get_currency_list() -> pd.DataFrame: 67 | """ 68 | Listagem com todas as moedas disponíveis na API e suas configurações de paridade. 69 | 70 | Returns 71 | ------- 72 | 73 | DataFrame : 74 | Tabela com a listagem de moedas disponíveis. 75 | """ 76 | if CACHE.get("TEMP_FILE_CURRENCY_LIST") is not None: 77 | return CACHE.get("TEMP_FILE_CURRENCY_LIST") 78 | else: 79 | res = _get_valid_currency_list(date.today()) 80 | df = pd.read_csv(StringIO(res.text), delimiter=";") 81 | df.columns = [ 82 | "code", 83 | "name", 84 | "symbol", 85 | "country_code", 86 | "country_name", 87 | "type", 88 | "exclusion_date", 89 | ] 90 | df = df.loc[~df["country_code"].isna()] 91 | df["exclusion_date"] = pd.to_datetime(df["exclusion_date"], dayfirst=True) 92 | df["country_code"] = df["country_code"].astype("int32") 93 | df["code"] = df["code"].astype("int32") 94 | df["symbol"] = df["symbol"].str.strip() 95 | CACHE["TEMP_FILE_CURRENCY_LIST"] = df 96 | return df 97 | 98 | 99 | def _get_currency_id(symbol: str) -> int: 100 | id_list = _currency_id_list() 101 | all_currencies = get_currency_list() 102 | x = pd.merge(id_list, all_currencies, on=["name"]) 103 | return np.max(x.loc[x["symbol"] == symbol, "id"]) 104 | 105 | 106 | def _get_symbol(symbol: str, start_date: DateInput, end_date: DateInput) -> pd.DataFrame: 107 | cid = _get_currency_id(symbol) 108 | url = _currency_url(cid, start_date, end_date) 109 | res = requests.get(url) 110 | 111 | if res.headers["Content-Type"].startswith("text/html"): 112 | doc = html.parse(BytesIO(res.content)).getroot() 113 | xpath = "//div[@class='msgErro']" 114 | elm = doc.xpath(xpath)[0] 115 | x = elm.text 116 | x = re.sub(r"^\W+", "", x) 117 | x = re.sub(r"\W+$", "", x) 118 | msg = "BCB API returned error: {} - {}".format(x, symbol) 119 | warnings.warn(msg) 120 | return None 121 | 122 | columns = ["Date", "aa", "bb", "cc", "bid", "ask", "dd", "ee"] 123 | df = pd.read_csv(StringIO(res.text), delimiter=";", header=None, names=columns, dtype=str) 124 | df = df.assign( 125 | Date=lambda x: pd.to_datetime(x["Date"], format="%d%m%Y"), 126 | bid=lambda x: x["bid"].str.replace(",", ".").astype(np.float64), 127 | ask=lambda x: x["ask"].str.replace(",", ".").astype(np.float64), 128 | ) 129 | df1 = df.set_index("Date") 130 | n = ["bid", "ask"] 131 | df1 = df1[n] 132 | tuples = list(zip([symbol] * len(n), n)) 133 | df1.columns = pd.MultiIndex.from_tuples(tuples) 134 | return df1 135 | 136 | 137 | def get( 138 | symbols: Union[str, List[str]], start: DateInput, end: DateInput, side: str = "ask", groupby: str = "symbol" 139 | ) -> pd.DataFrame: 140 | """ 141 | Retorna um DataFrame pandas com séries temporais com taxas de câmbio. 142 | 143 | Parameters 144 | ---------- 145 | 146 | symbols : str, List[str] 147 | Códigos das moedas padrão ISO. O código de uma única moeda que 148 | retorna uma série temporal univariada e uma lista de códigos 149 | retorna uma série temporal multivariada. 150 | start : str, int, date, datetime, Timestamp 151 | Data de início da série. 152 | Interpreta diferentes tipos e formatos de datas. 153 | end : string, int, date, datetime, Timestamp 154 | Data de início da série. 155 | Interpreta diferentes tipos e formatos de datas. 156 | side : str 157 | Define se a série retornada vem com os ``ask`` prices, 158 | ``bid`` prices ou ``both`` para ambos. 159 | groupby : str 160 | Define se os índices de coluna são agrupados por ``symbol`` ou 161 | por ``side``. 162 | 163 | Returns 164 | ------- 165 | 166 | DataFrame : 167 | Série temporal com cotações diárias das moedas solicitadas. 168 | """ 169 | if isinstance(symbols, str): 170 | symbols = [symbols] 171 | dss = [] 172 | for symbol in symbols: 173 | df1 = _get_symbol(symbol, start, end) 174 | if df1 is not None: 175 | dss.append(df1) 176 | if len(dss) > 0: 177 | df = pd.concat(dss, axis=1) 178 | if side in ("bid", "ask"): 179 | dx = df.reorder_levels([1, 0], axis=1).sort_index(axis=1) 180 | return dx[side] 181 | elif side == "both": 182 | if groupby == "symbol": 183 | return df 184 | elif groupby == "side": 185 | return df.reorder_levels([1, 0], axis=1).sort_index(axis=1) 186 | else: 187 | raise Exception(f"Unknown side value, use: bid, ask, both") 188 | else: 189 | raise Exception(f"Currency not found: {symbols}") 190 | -------------------------------------------------------------------------------- /bcb/odata/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import ( 2 | ODataAPI, 3 | Expectativas, 4 | PTAX, 5 | IFDATA, 6 | TaxaJuros, 7 | MercadoImobiliario, 8 | SPI, 9 | TarifasBancariasPorInstituicaoFinanceira, 10 | TarifasBancariasPorServico, 11 | PostosAtendimentoEletronicoPorInstituicaoFinanceira, 12 | PostosAtendimentoCorrespondentesPorInstituicaoFinanceira, 13 | EstatisticasSTR, 14 | DinheiroCirculacao, 15 | ) 16 | -------------------------------------------------------------------------------- /bcb/odata/api.py: -------------------------------------------------------------------------------- 1 | from .framework import ( 2 | ODataEntitySet, 3 | ODataFunctionImport, 4 | ODataQuery, 5 | ODataPropertyFilter, 6 | ODataPropertyOrderBy, 7 | ODataProperty, 8 | ODataService, 9 | ) 10 | import pandas as pd 11 | 12 | OLINDA_BASE_URL = "https://olinda.bcb.gov.br/olinda/servico" 13 | 14 | 15 | class EndpointMeta(type): 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | 19 | def __call__(self, *args): 20 | obj = super().__call__(*args) 21 | entity = args[0] 22 | if isinstance(entity, ODataEntitySet): 23 | for name, prop in entity.entity.properties.items(): 24 | setattr(obj, name, prop) 25 | elif isinstance(entity, ODataFunctionImport): 26 | for name, prop in entity.entity_set.entity.properties.items(): 27 | setattr(obj, name, prop) 28 | return obj 29 | 30 | 31 | class EndpointQuery(ODataQuery): 32 | _DATE_COLUMN_NAMES_BY_ENDPOINT = { 33 | "IfDataCadastro": {"Data": "%Y%m"} 34 | } 35 | _DATE_COLUMN_NAMES = { 36 | "Data", 37 | "dataHoraCotacao", 38 | "InicioPeriodo", 39 | "FimPeriodo", 40 | "DataVigencia", 41 | } 42 | 43 | def collect(self): 44 | raw_data = super().collect() 45 | data = pd.DataFrame(raw_data["value"]) 46 | if not self._raw: 47 | for col in self._DATE_COLUMN_NAMES: 48 | if self.entity.name in self._DATE_COLUMN_NAMES_BY_ENDPOINT and col in self._DATE_COLUMN_NAMES_BY_ENDPOINT[self.entity.name]: 49 | data[col] = pd.to_datetime(data[col], format=self._DATE_COLUMN_NAMES_BY_ENDPOINT[self.entity.name][col]) 50 | elif col in data.columns: 51 | data[col] = pd.to_datetime(data[col]) 52 | return data 53 | 54 | 55 | class Endpoint(metaclass=EndpointMeta): 56 | """ 57 | Classe que representa os tipos de *endpoints* de APIs OData. 58 | 59 | As APIs OData têm 2 tipos de *endpoints*: *entity sets* e *functions imports*. 60 | Esta classe provê todos os mecanismos para acessar tanto os *entity sets* quanto os *functions imports* e 61 | realizar consultas em através de suas APIs de maneira transparente. 62 | 63 | Esta classe não deveria ser instanciada diretamente. 64 | Objetos dessa classe são retornados pelo método 65 | :py:meth:`bcb.odata.api.BaseODataAPI.get_endpoint` das classes que herdam 66 | :py:class:`bcb.odata.api.BaseODataAPI`. 67 | """ 68 | def __init__(self, entity, url): 69 | """ 70 | Construtor da classe Endpoint. 71 | 72 | Parameters 73 | ---------- 74 | entity : bcb.odata.api.ODataEntity 75 | Objeto que representa um *entity set* ou um *function import*. 76 | Obtidos da classe ``bcb.odata.framework.ODataService``. 77 | url : str 78 | URL da API OData. 79 | """ 80 | self._entity = entity 81 | self._url = url 82 | 83 | def get(self, *args, **kwargs): 84 | """ 85 | Executa a consulta na API OData e retorna o resultado. 86 | 87 | Parameters 88 | ---------- 89 | *args : argumentos para a consulta 90 | 91 | **kwargs : argumentos para a consulta 92 | 93 | Returns 94 | ------- 95 | pd.DataFrame: resultado da consulta 96 | """ 97 | _query = EndpointQuery(self._entity, self._url) 98 | for arg in args: 99 | if isinstance(arg, ODataPropertyFilter): 100 | _query.filter(arg) 101 | elif isinstance(arg, ODataPropertyOrderBy): 102 | _query.orderby(arg) 103 | elif isinstance(arg, ODataProperty): 104 | _query.select(arg) 105 | verbose = False 106 | for k, val in kwargs.items(): 107 | if k == "limit": 108 | _query.limit(val) 109 | elif k == "skip": 110 | _query.skip(val) 111 | elif k == "verbose": 112 | verbose = val 113 | else: 114 | _query.parameters(**{k: val}) 115 | _query.format("application/json") 116 | 117 | if verbose: 118 | _query.show() 119 | data = _query.collect() 120 | _query.reset() 121 | return data 122 | 123 | def query(self): 124 | """ 125 | Retorna uma instância de EndpointQuery através da qual se construirá a consulta na API OData. 126 | 127 | Returns 128 | ------- 129 | bcb.odata.api.EndpointQuery 130 | """ 131 | return EndpointQuery(self._entity, self._url) 132 | 133 | 134 | class BaseODataAPI: 135 | """ 136 | Classe que abstrai qualquer API OData 137 | 138 | Essa classe não deve ser acessada diretamente. 139 | """ 140 | 141 | def __init__(self): 142 | """ 143 | BaseODataAPI construtor 144 | """ 145 | self.service = ODataService(self.BASE_URL) 146 | 147 | def describe(self, endpoint=None): 148 | """ 149 | Mostra a descrição de uma API ou de um *endpoint* 150 | específico. 151 | 152 | Parameters 153 | ---------- 154 | 155 | endpoint : None (padrão) ou str 156 | nome do *endpoint* 157 | 158 | Returns 159 | ------- 160 | 161 | Não retorna variável e imprime na tela uma descrição da API 162 | ou do *endpoint*. 163 | """ 164 | if endpoint: 165 | self.service[endpoint].describe() 166 | else: 167 | self.service.describe() 168 | 169 | def get_endpoint(self, endpoint): 170 | """ 171 | Obtem o *endpoint* 172 | 173 | Parameters 174 | ---------- 175 | 176 | endpoint : str 177 | nome do endpoint 178 | 179 | Returns 180 | ------- 181 | bcb.odata.api.Endpoint 182 | Retorna o *endpoint* referente ao nome fornecido 183 | 184 | Raises 185 | ------ 186 | ValueError 187 | Se o *endpoint* fornecido é errado. 188 | """ 189 | return Endpoint(self.service[endpoint], self.service.url) 190 | 191 | 192 | class ODataAPI(BaseODataAPI): 193 | """ 194 | Classe que abstrai qualquer API OData 195 | 196 | Essa classe pode ser acessada diretamente passando 197 | uma URL válida para uma API OData. 198 | 199 | Uma boa alternativa para acessar APIs que ainda 200 | não possuem implementação específica. 201 | """ 202 | 203 | def __init__(self, url): 204 | """ 205 | Parameters 206 | ---------- 207 | 208 | url : str 209 | URL de API OData 210 | 211 | Em geral tem o padrão 212 | 213 | ``https://olinda.bcb.gov.br/olinda/servico//versao/v1/odata/`` 214 | 215 | onde é a implementação desejada, por exemplo: 216 | 217 | - Expectativas 218 | - PTAX 219 | """ 220 | self.service = ODataService(url) 221 | 222 | 223 | class Expectativas(BaseODataAPI): 224 | """ 225 | Integração com API OData de Expectativas de Mercado. 226 | 227 | Cerca de 130 228 | instituições do mercado financeiro participantes do 229 | Sistema de Expectativas de Mercado para diversas variáveis 230 | macroeconômicas. 231 | 232 | Os dados são publicados no primeiro dia útil de cada semana. 233 | 234 | Esta interface possibilida a realização de consultas na 235 | API OData utilizando diversas funcionalidades presentes 236 | na especificação. 237 | 238 | Para períodos para os quais não haja estatísticas serão omitidos 239 | na consulta. 240 | 241 | São publicadas as expectativas informadas pelas instituições que 242 | autorizaram a divulgação. 243 | 244 | Essa API tem sete *endpoints* 245 | 246 | - ``ExpectativasMercadoTop5Anuais``: Expectativas de mercado anuais para 247 | os indicadores do Top 5 248 | - ``ExpectativasMercadoInstituicoes``: Expectativas de mercado informadas 249 | pelas instituições credenciadas 250 | - ``ExpectativaMercadoMensais``: Expectativas de Mercado Mensais 251 | - ``ExpectativasMercadoInflacao12Meses``: Expectativas de mercado para 252 | inflação nos próximos 12 meses 253 | - ``ExpectativasMercadoTop5Mensais``: Expectativas de mercado mensais para 254 | os indicadores do Top 5 255 | - ``ExpectativasMercadoTrimestrais``: Expectativas de Mercado Trimestrais 256 | - ``ExpectativasMercadoAnuais``: Expectativas de Mercado Anuais 257 | """ 258 | 259 | BASE_URL = f"{OLINDA_BASE_URL}/Expectativas/versao/v1/odata/" 260 | 261 | 262 | class PTAX(BaseODataAPI): 263 | """ 264 | Integração com API OData de cotações diárias de taxas de câmbio. 265 | 266 | Essa API possui os seguintes *endpoints*: 267 | 268 | - ``Moedas``: Retorna a lista de moedas que podem ser usadas 269 | - ``CotacaoMoedaPeriodoFechamento``: Retorna os boletins diários com a 270 | Paridade de Compra e a Paridade de Venda no Fechamento. 271 | - ``CotacaoMoedaAberturaOuIntermediario``: Retorna os boletins diários 272 | com a Paridade de Compra e a Paridade de Venda na abertura e 273 | para instantes ao longo do dia (intermediários). 274 | - ``CotacaoMoedaDia``: Consulta dos boletins por dia para moeda 275 | especificada. 276 | - ``CotacaoMoedaPeriodo``: Consulta dos boletins por período para 277 | moeda especificada. 278 | - ``CotacaoDolarDia``: Consulta dos boletins de dólar por dia. 279 | - ``CotacaoDolarPeriodo``: Consulta dos boletins de dólar por período. 280 | 281 | Os boletins diários são divulgados diariamente e trazem 5 cotações 282 | para cada data: uma de abertura, três intermediários e uma de fechamento. 283 | 284 | Estes dados estão disponíveis desde 1984-11-28 e são referentes às taxas 285 | administradas, até março de 1990, e às taxas livres, a partir de então 286 | (Resolução 1690, de 18.3.1990). 287 | As taxas administradas são aquelas fixadas pelo Banco Central, 288 | a partir de março de 1992, essa taxa recebeu a denominação de taxa 289 | PTAX (fechamento). 290 | Até 30 de junho de 2011, as taxas livres correspondiam à média das taxas 291 | efetivas de operações no mercado interbancário, ponderada pelo volume de 292 | transações do dia. 293 | A partir de 1 de julho de 2011 (Circular 3506, de 2010-09-23), a Ptax 294 | passou a corresponder à média aritmética das taxas obtidas em quatro 295 | consultas diárias aos dealers de câmbio e refletem a taxa negociada no 296 | momento de abertura da janela de consulta. 297 | O boletim de fechamento PTAX corresponde à média aritmética das taxas dos 298 | boletins do dia. 299 | """ 300 | 301 | BASE_URL = f"{OLINDA_BASE_URL}/PTAX/versao/v1/odata/" 302 | 303 | 304 | class IFDATA(BaseODataAPI): 305 | """ 306 | Integração com API OData para dados selecionados de instituições 307 | financeiras 308 | 309 | Dados selecionados de instituições financeiras dos relatórios do IFData 310 | disponibilizados na página https://www3.bcb.gov.br/ifdata/ em formato de 311 | dados abertos. 312 | No IFData são divulgadas trimestralmente informações das instituições 313 | autorizadas a funcionar e que estejam em operação normal. 314 | Os relatórios trimestrais são disponibilizados 60 dias após o fechamento 315 | das datas-bases março, junho e setembro, e 90 dias após o 316 | fechamento da data-base dezembro. 317 | """ 318 | 319 | BASE_URL = f"{OLINDA_BASE_URL}/IFDATA/versao/v1/odata/" 320 | 321 | 322 | class TaxaJuros(BaseODataAPI): 323 | """ 324 | Taxas de juros de operações de crédito por instituição financeira - Médias 325 | dos últimos 5 dias 326 | 327 | As taxas de juros por instituição financeira apresentadas nesse conjunto de 328 | tabelas representam médias aritméticas das taxas de juros pactuadas nas 329 | operações realizadas nos cinco dias úteis referidos em cada publicação, 330 | ponderadas pelos respectivos valores contratados. 331 | 332 | Essas taxas de juros representam o custo efetivo médio das operações de 333 | crédito para os clientes, composto pelas taxas de juros efetivamente 334 | praticadas pelas instituições financeiras em suas operações de crédito, 335 | acrescidas dos encargos fiscais e operacionais incidentes sobre as 336 | operações. 337 | 338 | As taxas de juros apresentadas correspondem à média das taxas praticadas 339 | nas diversas operações realizadas pelas instituições financeiras em cada 340 | modalidade de crédito. Em uma mesma modalidade, as taxas de juros diferem 341 | entre clientes de uma mesma instituição financeira e variam de acordo com 342 | diversos fatores de risco envolvidos nas operações, tais como o valor e a 343 | qualidade das garantias apresentadas na contratação do crédito, o valor do 344 | pagamento dado como entrada da operação, o histórico e a situação cadastral 345 | de cada cliente, o prazo da operação, entre outros. 346 | 347 | Eventualmente algumas instituições financeiras não aparecem relacionadas 348 | nas tabelas em razão de não terem realizado operações de crédito nas 349 | respectivas modalidades nos períodos referidos ou por não terem prestado 350 | as informações requeridas pelo Banco Central do Brasil no prazo previsto 351 | pela legislação em vigor. 352 | 353 | A partir de abril de 2017, as taxas médias das operações de cartão de 354 | crédito rotativo passaram a ser publicadas de forma desagregada nas 355 | modalidades cartão de crédito rotativo regular - que compreende os 356 | financiamentos dos saldos remanescentes das faturas de cartão de crédito 357 | nos quais os clientes efetuam o pagamento mínimo requerido pela legislação 358 | em vigor - e cartão de crédito não regular , que compreende os 359 | financiamentos dos saldos remanescentes das faturas de cartão de crédito 360 | nos quais os clientes não efetuam o pagamento mínimo, sendo considerados 361 | em atraso. 362 | 363 | O Banco Central do Brasil não assume nenhuma responsabilidade por 364 | defasagem, erro ou outra deficiência em informações prestadas para fins de 365 | apuração das taxas médias apresentadas nesse conjunto de tabelas, cujas 366 | fontes sejam externas a esta instituição, bem como por quaisquer perdas ou 367 | danos decorrentes de seu uso. 368 | """ 369 | 370 | BASE_URL = f"{OLINDA_BASE_URL}/taxaJuros/versao/v2/odata/" 371 | 372 | 373 | class MercadoImobiliario(BaseODataAPI): 374 | """ 375 | Informações do Mercado Imobiliário 376 | 377 | O Banco Central do Brasil divulga mensalmente informações sobre o mercado 378 | imobiliário. Os relatórios são atualizados no último dia útil do mês, 379 | disponibilizando os dados após 60 dias do fechamento de cada período. 380 | A publicação é o resultado da análise das informações recebidas através do 381 | Sistema de Informações de Créditos – SCR, Sistema de Informações 382 | Contábeis – Cosif, Direcionamento dos Depósitos de Poupança - RCO e das 383 | entidades de depósito e registro de ativos. Distribuídas em 6 seções, 384 | possuem informações sobre as fontes de recursos, direcionamento dos 385 | recursos da caderneta de poupança, valores contábeis, operações de crédito, 386 | detalhes dos imóveis financiados e índices relacionados com o setor. 387 | O relatório disponibiliza mais de 4.000 séries mensais em formato de dados 388 | abertos. As seções Crédito e Imóveis possuem detalhamentos por estados. 389 | """ 390 | 391 | BASE_URL = f"{OLINDA_BASE_URL}/MercadoImobiliario/versao/v1/odata/" 392 | 393 | 394 | class SPI(BaseODataAPI): 395 | """ 396 | Estatísticas do SPI - Sistema de Pagamentos Instantâneos 397 | 398 | Estatísticas das movimentações financeiras transitadas no SPI (Sistema de 399 | Pagamentos Instantâneos) processadas por meio de lançamentos nas contas PI 400 | mantidas pelos participantes no Banco Central. 401 | """ 402 | 403 | BASE_URL = f"{OLINDA_BASE_URL}/SPI/versao/v1/odata/" 404 | 405 | 406 | class TarifasBancariasPorInstituicaoFinanceira(BaseODataAPI): 407 | """ 408 | Tarifas Bancárias - por Segmento e por Instituição 409 | 410 | Esta API disponibiliza as informações mais recentes sobre as tarifas 411 | cobradas por instituições financeiras, por Segmento e por Instituição. 412 | """ 413 | 414 | K = "Informes_ListaTarifasPorInstituicaoFinanceira" 415 | BASE_URL = f"{OLINDA_BASE_URL}/{K}/versao/v1/odata/" 416 | 417 | 418 | class TarifasBancariasPorServico(BaseODataAPI): 419 | """ 420 | Tarifas Bancárias - valores mínimos, máximos e médios por serviço 421 | 422 | Esta API disponibiliza as informações mais recentes sobre as tarifas 423 | cobradas por instituições financeiras, valores mínimos, máximos e médios 424 | por serviço. 425 | """ 426 | 427 | K = "Informes_ListaValoresDeServicoBancario" 428 | BASE_URL = f"{OLINDA_BASE_URL}/{K}/versao/v1/odata/" 429 | 430 | 431 | class PostosAtendimentoEletronicoPorInstituicaoFinanceira(BaseODataAPI): 432 | """ 433 | Postos de Atendimento Eletrônico de Instituições Supervisionadas pelo Bacen 434 | 435 | Os arquivos disponíveis para transferência apresentam as informações mais 436 | atuais dos postos de atendimento eletrônico de Instituições Supervisionadas 437 | pelo Banco Central. 438 | """ 439 | 440 | K = "Informes_PostosDeAtendimentoEletronico" 441 | BASE_URL = f"{OLINDA_BASE_URL}/{K}/versao/v1/odata/" 442 | 443 | 444 | class PostosAtendimentoCorrespondentesPorInstituicaoFinanceira(BaseODataAPI): 445 | """ 446 | Correspondentes no país 447 | 448 | O arquivo disponibilizado apresenta os dados mais atuais dos pontos de 449 | atendimento dos correspondentes, por instituição financeira e por 450 | município, com a identificação dos tipos de serviços prestados, conforme 451 | descrito na Resolução 3.954. 452 | """ 453 | 454 | K = "Informes_Correspondentes" 455 | BASE_URL = f"{OLINDA_BASE_URL}/{K}/versao/v1/odata/" 456 | 457 | 458 | class EstatisticasSTR(BaseODataAPI): 459 | """ 460 | Estatísticas do STR - Sistema de Transferência de Reservas 461 | 462 | Estatísticas das movimentações financeiras transitadas no STR (Sistema de 463 | Transferência de Reservas) processadas por meio de lançamentos nas contas 464 | mantidas pelos participantes no Banco Central. 465 | """ 466 | 467 | K = "STR" 468 | BASE_URL = f"{OLINDA_BASE_URL}/{K}/versao/v1/odata/" 469 | 470 | 471 | class DinheiroCirculacao(BaseODataAPI): 472 | """ 473 | Dinheiro em Circulação 474 | 475 | Registros diários das quantidades de cédulas e moedas em circulação (não 476 | estão incluídas as moedas comemorativas). As informações estão separadas 477 | para cada espécie (cédula ou moeda), família (categoria) e denominação do 478 | Real (símbolos : R$, BRL). 479 | """ 480 | 481 | K = "mecir_dinheiro_em_circulacao" 482 | BASE_URL = f"{OLINDA_BASE_URL}/{K}/versao/v1/odata/" 483 | 484 | 485 | # /Informes_Ouvidorias/versao/v1/odata/ 486 | # /RankingOuvidorias/versao/v1/odata/ 487 | # /Informes_ListaTarifasPorInstituicaoFinanceira/versao/v1/odata/ 488 | # /PoliticaMonetaria_TitulosOperacoesConjugadas/versao/v1/odata/ 489 | # /selic_contas/versao/v1/odata/ 490 | # /selic_clientes/versao/v1/odata/ 491 | # /Informes_FiliaisAdministradorasConsorcios/versao/v1/odata/ 492 | # /Informes_Agencias/versao/v1/odata/ 493 | # /SML/versao/v1/odata/ 494 | # /DASFN/versao/v1/odata/ 495 | -------------------------------------------------------------------------------- /bcb/odata/framework.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | import logging 3 | from lxml import etree 4 | import json 5 | import httpx 6 | from urllib.parse import quote 7 | 8 | 9 | # Edm.Boolean 10 | # Edm.Byte 11 | # Edm.Date 12 | # Edm.DateTimeOffset 13 | # Edm.Decimal 14 | # Edm.Duration 15 | # Edm.Guid 16 | # Edm.Int16 17 | # Edm.Int32 18 | # Edm.Int64 19 | # Edm.SByte 20 | # Edm.String 21 | # Edm.TimeOfDay 22 | 23 | 24 | def str_types(type): 25 | if type == "Edm.Decimal": 26 | return "float" 27 | elif type in ("Edm.Int32", "Edm.Int64", "Edm.Int16"): 28 | return "int" 29 | elif type == "Edm.String": 30 | return "str" 31 | elif type == "Edm.Boolean": 32 | return "bool" 33 | elif type in ("Edm.Date", "Edm.TimeOfDay"): 34 | return "datetime" 35 | else: 36 | return type 37 | 38 | 39 | class ODataEndPoint: 40 | def __init__(self, **kwargs): 41 | self.data = kwargs 42 | 43 | def __getitem__(self, item): 44 | return self.data[item] 45 | 46 | def __setitem__(self, key, value): 47 | self.data[key] = value 48 | 49 | def __repr__(self): 50 | url = self.data["url"] 51 | return f"" 52 | 53 | 54 | class ODataEntitySetMeta(type): 55 | def __init__(self, *args, **kwargs): 56 | super().__init__(*args, **kwargs) 57 | 58 | def __call__(self, *args): 59 | obj = super().__call__(*args) 60 | entity = args[2] 61 | for name, prop in entity.properties.items(): 62 | setattr(obj, name, prop) 63 | return obj 64 | 65 | 66 | class ODataEntitySet(metaclass=ODataEntitySetMeta): 67 | def __init__(self, name, entity_type, entity): 68 | self.name = name 69 | self.entity_type = entity_type 70 | self.entity = entity 71 | 72 | def describe(self): 73 | props = ", ".join( 74 | [f"{prop.name}<{prop.ftype}>" for prop in self.entity.properties.values()] 75 | ) 76 | print( 77 | f""" 78 | EntitySet (Endpoint): {self.name} 79 | EntityType: {self.entity_type} 80 | Properties: {props}""" 81 | ) 82 | 83 | def __repr__(self): 84 | return f"" 85 | 86 | 87 | class ODataFunctionImport: 88 | def __init__(self, name, function, entity_set): 89 | self.name = name 90 | self.entity_set = entity_set 91 | self.function = function 92 | 93 | def describe(self): 94 | props = ", ".join( 95 | [ 96 | f"{prop.name} <{prop.ftype}>" 97 | for prop in self.entity_set.entity.properties.values() 98 | ] 99 | ) 100 | params = ", ".join( 101 | [f"{param.name} <{param.ftype}>" for param in self.function.parameters] 102 | ) 103 | s = f""" 104 | Function: {self.function.name} 105 | Parameters: {params} 106 | EntitySet: {self.entity_set.name} 107 | EntityType: {self.entity_set.entity_type} 108 | Properties: {props}""" 109 | print(s) 110 | 111 | def __repr__(self): 112 | return f"" 113 | 114 | 115 | class ODataParameter: 116 | def __init__(self, **kwargs): 117 | self.data = kwargs 118 | 119 | @property 120 | def name(self): 121 | return self.data.get("Name") 122 | 123 | @property 124 | def type(self): 125 | return self.data.get("Type") 126 | 127 | @property 128 | def ftype(self): 129 | return str_types(self.type) 130 | 131 | @property 132 | def required(self): 133 | nullable = self.data.get("Nullable") 134 | if nullable: 135 | return nullable == "false" 136 | else: 137 | return True 138 | 139 | def format(self, value): 140 | if self.type == "Edm.Decimal": 141 | return f"{float(value)}" 142 | elif self.type == "Edm.Int32": 143 | return f"{int(value)}" 144 | elif self.type == "Edm.String": 145 | return f"'{str(value)}'" 146 | else: 147 | return f"'{str(value)}'" 148 | 149 | 150 | class ODataPropertyOrderBy: 151 | def __init__(self, obj, order): 152 | self.obj = obj 153 | self.order = order 154 | 155 | def __str__(self): 156 | return f"{self.obj.name} {self.order}" 157 | 158 | def __repr__(self): 159 | return f"<{str(self)}>" 160 | 161 | 162 | class ODataPropertyFilter: 163 | def __init__(self, obj, oth, operator): 164 | self.obj = obj 165 | self.other = oth 166 | self.operator = operator 167 | 168 | def statement(self): 169 | if self.obj.type == "Edm.Decimal": 170 | return f"{self.obj.name} {self.operator} {float(self.other)}" 171 | elif self.obj.type == "Edm.Int32": 172 | return f"{self.obj.name} {self.operator} {int(self.other)}" 173 | elif self.obj.type == "Edm.String": 174 | return f"{self.obj.name} {self.operator} '{str(self.other)}'" 175 | elif self.obj.type == "Edm.Date": 176 | return f"{self.obj.name} {self.operator} {self.other.strftime('%Y-%m-%d')}" 177 | else: 178 | return f"{self.obj.name} {self.operator} '{self.other}'" 179 | 180 | def __str__(self): 181 | return self.statement() 182 | 183 | def __repr__(self): 184 | return f"" 185 | 186 | 187 | class ODataProperty: 188 | def __init__(self, **kwargs): 189 | self.data = kwargs 190 | 191 | @property 192 | def name(self): 193 | return self.data.get("Name") 194 | 195 | @property 196 | def type(self): 197 | return self.data.get("Type") 198 | 199 | @property 200 | def ftype(self): 201 | return str_types(self.type) 202 | 203 | def asc(self): 204 | return ODataPropertyOrderBy(self, "asc") 205 | 206 | def desc(self): 207 | return ODataPropertyOrderBy(self, "desc") 208 | 209 | def __gt__(self, other): 210 | return ODataPropertyFilter(self, other, "gt") 211 | 212 | def __ge__(self, other): 213 | return ODataPropertyFilter(self, other, "ge") 214 | 215 | def __lt__(self, other): 216 | return ODataPropertyFilter(self, other, "lt") 217 | 218 | def __le__(self, other): 219 | return ODataPropertyFilter(self, other, "le") 220 | 221 | def __eq__(self, other): 222 | return ODataPropertyFilter(self, other, "eq") 223 | 224 | def __repr__(self): 225 | return f">" 226 | 227 | 228 | class ODataFunction: 229 | def __init__(self, **kwargs): 230 | self.name = kwargs["Name"] 231 | self.parameters = kwargs["parameters"] 232 | self.return_type = kwargs["return_type"] 233 | self.fullname = f'{kwargs["namespace"]}.{self.name}' 234 | 235 | def __repr__(self): 236 | return f"" 237 | 238 | 239 | class ODataEntity: 240 | def __init__(self, name, properties, namespace): 241 | self.name = name 242 | self.properties = properties 243 | self.fullname = f"{namespace}.{name}" 244 | 245 | def __repr__(self): 246 | return f"" 247 | 248 | 249 | class ODataMetadata: 250 | namespaces = { 251 | "edm": "http://docs.oasis-open.org/odata/ns/edm", 252 | "edmx": "http://docs.oasis-open.org/odata/ns/edmx", 253 | } 254 | 255 | def __init__(self, url): 256 | self.url = url 257 | self._load_document() 258 | _xpath = "edmx:DataServices/edm:Schema" 259 | schema = self.doc.xpath(_xpath, namespaces=self.namespaces)[0] 260 | self.namespace = schema.attrib["Namespace"] 261 | self._used_elements = [] 262 | self._parse_entities(schema) 263 | self._parse_entity_sets(schema) 264 | self._parse_functions(schema) 265 | self._parse_function_imports(schema) 266 | 267 | def _load_document(self): 268 | res = httpx.get(self.url, timeout=60.0) 269 | self.doc = etree.parse(BytesIO(res.content)) 270 | 271 | def _parse_entity(self, entity_element, namespace): 272 | name = entity_element.attrib["Name"] 273 | props = { 274 | prop.attrib["Name"]: ODataProperty(**prop.attrib) for prop in entity_element 275 | } 276 | return ODataEntity(name, props, namespace) 277 | 278 | def _parse_entities(self, schema): 279 | _xpath = "edm:EntityType" 280 | self.entities = [ 281 | self._parse_entity(e, self.namespace) 282 | for e in schema.xpath(_xpath, namespaces=self.namespaces) 283 | ] 284 | 285 | self._entities_fullnames = {e.fullname: e for e in self.entities} 286 | 287 | def _parse_entity_sets(self, schema): 288 | _xpath = "edm:EntityContainer/edm:EntitySet" 289 | 290 | def _parse_entity_set(e): 291 | entity = self._entities_fullnames[e.attrib["EntityType"]] 292 | return ODataEntitySet(e.attrib["Name"], e.attrib["EntityType"], entity) 293 | 294 | self.entity_sets = { 295 | e.attrib["Name"]: _parse_entity_set(e) 296 | for e in schema.xpath(_xpath, namespaces=self.namespaces) 297 | } 298 | 299 | for n, es in self.entity_sets.items(): 300 | es.fullname = f"{self.namespace}.{n}" 301 | 302 | self._entity_sets_fullnames = { 303 | es.fullname: es for es in self.entity_sets.values() 304 | } 305 | 306 | def _parse_functions(self, schema): 307 | _xpath = "edm:Function" 308 | 309 | def _parse_function(e): 310 | parameters = [] 311 | return_type = None 312 | for element in e: 313 | if element.tag.endswith("Parameter"): 314 | parameters.append(ODataParameter(**element.attrib)) 315 | elif element.tag.endswith("ReturnType"): 316 | return_type = element.attrib["Type"] 317 | kwargs = dict(**e.attrib) 318 | kwargs["parameters"] = parameters 319 | kwargs["return_type"] = return_type 320 | kwargs["namespace"] = self.namespace 321 | return ODataFunction(**kwargs) 322 | 323 | self.functions = { 324 | e.attrib["Name"]: _parse_function(e) 325 | for e in schema.xpath(_xpath, namespaces=self.namespaces) 326 | } 327 | 328 | self._functions_fullnames = {f.fullname: f for f in self.functions.values()} 329 | 330 | def _parse_function_imports(self, schema): 331 | _xpath = "edm:EntityContainer/edm:FunctionImport" 332 | 333 | def _parse_function_import(e): 334 | function = self._functions_fullnames[e.attrib["Function"]] 335 | entity_set = self._entity_sets_fullnames[e.attrib["EntitySet"]] 336 | self._used_elements.append(e.attrib["EntitySet"]) 337 | return ODataFunctionImport(e.attrib["Name"], function, entity_set) 338 | 339 | self.function_imports = { 340 | e.attrib["Name"]: _parse_function_import(e) 341 | for e in schema.xpath(_xpath, namespaces=self.namespaces) 342 | } 343 | 344 | 345 | class ODataService: 346 | def __init__(self, url): 347 | self.url = url 348 | res = httpx.get(self.url, timeout=60.0) 349 | self.api_data = json.loads(res.text) 350 | self.endpoints = [ODataEndPoint(**x) for x in self.api_data["value"]] 351 | self._odata_context_url = self.api_data["@odata.context"] 352 | self.metadata = ODataMetadata(self._odata_context_url) 353 | 354 | def __getitem__(self, item): 355 | es = self.entity_sets.get(item) 356 | if es is None: 357 | fi = self.function_imports.get(item) 358 | if fi is not None: 359 | return fi 360 | else: 361 | raise ValueError("Invalid name: " + item) 362 | else: 363 | return es 364 | 365 | @property 366 | def entities(self): 367 | return self.metadata.entities 368 | 369 | @property 370 | def function_imports(self): 371 | return self.metadata.function_imports 372 | 373 | @property 374 | def entity_sets(self): 375 | return self.metadata.entity_sets 376 | 377 | def describe(self): 378 | es_names = [] 379 | for es in self.entity_sets.keys(): 380 | k = f"{self.metadata.namespace}.{es}" 381 | if k not in self.metadata._used_elements: 382 | es_names.append(es) 383 | if len(es_names): 384 | print("EntitySets:") 385 | for es in es_names: 386 | print(" ", es) 387 | if len(self.function_imports): 388 | print("FunctionImports:") 389 | for es in self.function_imports.keys(): 390 | print(" ", es) 391 | 392 | def query(self, entity_set): 393 | return ODataQuery(entity_set, self.url) 394 | 395 | 396 | class ODataQuery: 397 | def __init__(self, entity, url): 398 | self.entity = entity 399 | self.base_url = url 400 | self._params = {} 401 | self.function_parameters = {} 402 | self._filter = [] 403 | self._select = [] 404 | self._orderby = [] 405 | self._raw = False 406 | self.is_function = isinstance(entity, ODataFunctionImport) 407 | if self.is_function: 408 | self.function_parameters = { 409 | p.name: None for p in self.entity.function.parameters 410 | } 411 | 412 | def odata_url(self): 413 | self._url = ( 414 | f"{self.base_url}{self.entity.name}" 415 | if self.base_url.endswith("/") 416 | else f"{self.base_url}/{self.entity.name}" 417 | ) 418 | if self.is_function: 419 | args = [f"{p.name}=@{p.name}" for p in self.entity.function.parameters] 420 | args = ",".join(args) 421 | return f"{self._url}({args})" 422 | else: 423 | return self._url 424 | 425 | def parameters(self, **kwargs): 426 | for arg in kwargs: 427 | if arg in self.function_parameters: 428 | self.function_parameters[arg] = kwargs[arg] 429 | else: 430 | raise ValueError(f"Unknown parameter: {arg}") 431 | return self 432 | 433 | def filter(self, *args): 434 | if len(args): 435 | self._filter.extend(args) 436 | return self 437 | 438 | def limit(self, limit): 439 | self._params["$top"] = limit 440 | return self 441 | 442 | def skip(self, skip): 443 | self._params["$skip"] = skip 444 | return self 445 | 446 | def format(self, fmt): 447 | self._params["$format"] = fmt 448 | return self 449 | 450 | def orderby(self, *args): 451 | if len(args): 452 | self._orderby.extend(args) 453 | return self 454 | 455 | def select(self, *args): 456 | if len(args): 457 | self._select.extend(args) 458 | return self 459 | 460 | def raw(self): 461 | self._raw = True 462 | return self 463 | 464 | def _build_parameters(self): 465 | params = {"$format": self._params.get("$format", "json")} 466 | if len(self._filter): 467 | _filter = " and ".join(str(f) for f in self._filter) 468 | params["$filter"] = _filter 469 | if len(self._orderby): 470 | _orderby = ",".join(str(f) for f in self._orderby) 471 | params["$orderby"] = _orderby 472 | if len(self._select): 473 | _select = ",".join(str(f.name) for f in self._select) 474 | params["$select"] = _select 475 | params.update(self._params) 476 | return params 477 | 478 | def reset(self): 479 | self._filter = [] 480 | self._orderby = [] 481 | self._params = {} 482 | 483 | def collect(self): 484 | return json.loads(self.text()) 485 | 486 | def text(self): 487 | params = self._build_parameters() 488 | if self.is_function and len(self.function_parameters): 489 | for p in self.entity.function.parameters: 490 | val = self.function_parameters[p.name] 491 | if p.required and val is None: 492 | raise ValueError("Parameter not set: " + p.name) 493 | params["@" + p.name] = p.format(val) 494 | qs = "&".join([f"{quote(k)}={quote(str(v))}" for k, v in params.items()]) 495 | headers = {"OData-Version": "4.0", "OData-MaxVersion": "4.0"} 496 | res = httpx.get(self.odata_url() + "?" + qs, headers=headers, timeout=60.0) 497 | return res.text 498 | 499 | def show(self): 500 | print(f"URL:") 501 | print(f" {self.odata_url()}") 502 | if self.is_function and len(self.function_parameters): 503 | print("Function Parameters:") 504 | for p in self.entity.function.parameters: 505 | v = self.function_parameters[p.name] 506 | req = " (required) " if p.required else " " 507 | print(f" {p.name}<{p.ftype}>{req}= {v}") 508 | params = self._build_parameters() 509 | if len(params): 510 | print("Query Parameters:") 511 | for k, v in params.items(): 512 | print(" ", k, "=", v) 513 | if self.is_function: 514 | names = [ 515 | f"{p.name}<{p.ftype}>" 516 | for p in self.entity.entity_set.entity.properties.values() 517 | ] 518 | names = ", ".join(names) 519 | print("Return:", names) 520 | else: 521 | names = [ 522 | f"{p.name}<{p.ftype}>" for p in self.entity.entity.properties.values() 523 | ] 524 | names = ", ".join(names) 525 | print("Return:", names) 526 | -------------------------------------------------------------------------------- /bcb/sgs/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | from io import StringIO 3 | from typing import Dict, Generator, List, Optional, Tuple, TypeAlias, Union 4 | 5 | import pandas as pd 6 | import requests 7 | 8 | from bcb.utils import Date, DateInput 9 | 10 | """ 11 | Sistema Gerenciador de Séries Temporais (SGS) 12 | 13 | O módulo ``sgs`` obtem os dados do webservice do Banco Central, 14 | interface json do serviço BCData/SGS - 15 | `Sistema Gerenciador de Séries Temporais (SGS) 16 | `_. 17 | """ 18 | 19 | 20 | class SGSCode: 21 | def __init__(self, code: Union[str, int], name: Optional[str] = None) -> None: 22 | if name is None: 23 | if isinstance(code, int) or isinstance(code, str): 24 | self.name = str(code) 25 | self.value = int(code) 26 | else: 27 | self.name = str(name) 28 | self.value = int(code) 29 | 30 | def __repr__(self): 31 | return f"{self.code} - {self.name}" if self.name else f"{self.code}" 32 | 33 | 34 | SGSCodeInput: TypeAlias = Union[ 35 | int, 36 | str, 37 | Tuple[str, Union[int, str]], 38 | List[Union[int, str, Tuple[str, Union[int, str]]]], 39 | Dict[str, Union[int, str]], 40 | ] 41 | 42 | 43 | def _codes(codes: SGSCodeInput) -> Generator[SGSCode, None, None]: 44 | if isinstance(codes, int) or isinstance(codes, str): 45 | yield SGSCode(codes) 46 | elif isinstance(codes, tuple): 47 | yield SGSCode(codes[1], codes[0]) 48 | elif isinstance(codes, list): 49 | for cd in codes: 50 | _ist = isinstance(cd, tuple) 51 | yield SGSCode(cd[1], cd[0]) if _ist else SGSCode(cd) 52 | elif isinstance(codes, dict): 53 | for name, code in codes.items(): 54 | yield SGSCode(code, name) 55 | 56 | 57 | def _get_url_and_payload(code: int, start_date: DateInput, end_date: DateInput, last: int) -> Dict[str, str]: 58 | payload = {"formato": "json"} 59 | if last == 0: 60 | if start_date is not None or end_date is not None: 61 | payload["dataInicial"] = Date(start_date).date.strftime("%d/%m/%Y") 62 | end_date = end_date if end_date else "today" 63 | payload["dataFinal"] = Date(end_date).date.strftime("%d/%m/%Y") 64 | url = "https://api.bcb.gov.br/dados/serie/bcdata.sgs.{}/dados".format(code) 65 | else: 66 | url = ("https://api.bcb.gov.br/dados/serie/bcdata.sgs.{}/dados" "/ultimos/{}").format(code, last) 67 | 68 | return {"payload": payload, "url": url} 69 | 70 | 71 | def _format_df(df: pd.DataFrame, code: SGSCode, freq: str) -> pd.DataFrame: 72 | cns = {"data": "Date", "valor": code.name, "datafim": "enddate"} 73 | df = df.rename(columns=cns) 74 | if "Date" in df: 75 | df["Date"] = pd.to_datetime(df["Date"], format="%d/%m/%Y") 76 | if "enddate" in df: 77 | df["enddate"] = pd.to_datetime(df["enddate"], format="%d/%m/%Y") 78 | df = df.set_index("Date") 79 | if freq: 80 | df.index = df.index.to_period(freq) 81 | return df 82 | 83 | 84 | def get( 85 | codes: SGSCodeInput, 86 | start: Optional[DateInput] = None, 87 | end: Optional[DateInput] = None, 88 | last: int = 0, 89 | multi: bool = True, 90 | freq: Optional[str] = None, 91 | ) -> Union[pd.DataFrame, List[pd.DataFrame]]: 92 | """ 93 | Retorna um DataFrame pandas com séries temporais obtidas do SGS. 94 | 95 | Parameters 96 | ---------- 97 | 98 | codes : {int, List[int], List[str], Dict[str:int]} 99 | Este argumento pode ser uma das opções: 100 | 101 | * ``int`` : código da série temporal 102 | * ``list`` ou ``tuple`` : lista ou tupla com códigos 103 | * ``list`` ou ``tuple`` : lista ou tupla com pares ``('nome', código)`` 104 | * ``dict`` : dicionário com pares ``{'nome': código}`` 105 | 106 | Com códigos numéricos é interessante utilizar os nomes com os códigos 107 | para definir os nomes nas colunas das séries temporais. 108 | start : str, int, date, datetime, Timestamp 109 | Data de início da série. 110 | Interpreta diferentes tipos e formatos de datas. 111 | end : string, int, date, datetime, Timestamp 112 | Data final da série. 113 | Interpreta diferentes tipos e formatos de datas. 114 | last : int 115 | Retorna os últimos ``last`` elementos disponíveis da série temporal 116 | solicitada. Se ``last`` for maior que 0 (zero) os argumentos ``start`` 117 | e ``end`` são ignorados. 118 | multi : bool 119 | Define se, quando mais de 1 série for solicitada, a função retorna uma 120 | série multivariada ou uma lista com séries univariadas. 121 | freq : str 122 | Define a frequência a ser utilizada na série temporal 123 | 124 | Returns 125 | ------- 126 | 127 | ``DataFrame`` : 128 | série temporal univariada ou multivariada, 129 | quando solicitado mais de uma série (parâmetro ``multi=True``). 130 | 131 | ``list`` : 132 | lista com séries temporais univariadas, 133 | quando solicitado mais de uma série (parâmetro ``multi=False``). 134 | """ 135 | dfs = [] 136 | for code in _codes(codes): 137 | text = get_json(code.value, start, end, last) 138 | df = pd.read_json(StringIO(text)) 139 | df = _format_df(df, code, freq) 140 | dfs.append(df) 141 | if len(dfs) == 1: 142 | return dfs[0] 143 | else: 144 | if multi: 145 | return pd.concat(dfs, axis=1) 146 | else: 147 | return dfs 148 | 149 | 150 | def get_json(code: int, start: Optional[DateInput] = None, end: Optional[DateInput] = None, last: int = 0) -> str: 151 | """ 152 | Retorna um JSON com séries temporais obtidas do SGS. 153 | 154 | Parameters 155 | ---------- 156 | 157 | code : int 158 | Código da série temporal 159 | start : str, int, date, datetime, Timestamp 160 | Data de início da série. 161 | Interpreta diferentes tipos e formatos de datas. 162 | end : string, int, date, datetime, Timestamp 163 | Data final da série. 164 | Interpreta diferentes tipos e formatos de datas. 165 | last : int 166 | Retorna os últimos ``last`` elementos disponíveis da série temporal 167 | solicitada. Se ``last`` for maior que 0 (zero) os argumentos ``start`` 168 | e ``end`` são ignorados. 169 | 170 | Returns 171 | ------- 172 | 173 | JSON : 174 | série temporal univariada em formato JSON. 175 | """ 176 | urd = _get_url_and_payload(code, start, end, last) 177 | res = requests.get(urd["url"], params=urd["payload"]) 178 | if res.status_code != 200: 179 | try: 180 | res_json = json.loads(res.text) 181 | except Exception: 182 | res_json = {} 183 | if "error" in res_json: 184 | raise Exception("BCB error: {}".format(res_json["error"])) 185 | elif "erro" in res_json: 186 | raise Exception("BCB error: {}".format(res_json["erro"]["detail"])) 187 | raise Exception("Download error: code = {}".format(code)) 188 | return res.text 189 | -------------------------------------------------------------------------------- /bcb/sgs/regional_economy.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List, Optional, Union 2 | 3 | import pandas as pd 4 | 5 | from bcb.sgs import get 6 | from bcb.utils import DateInput 7 | 8 | """ 9 | Dados da Economia Regional 10 | 11 | Histórico de taxas de inadimplência das operações de crédito do Sistema Financeiro Nacional para 12 | pessoas físicas e pessoas jurídicas. 13 | 14 | Dados disponíveis por região e por estado. 15 | """ 16 | 17 | NON_PERFORMING_LOANS_BY_REGION_PF = { 18 | "N": "15888", 19 | "NE": "15889", 20 | "CO": "15890", 21 | "SE": "15891", 22 | "S": "15892", 23 | } 24 | NON_PERFORMING_LOANS_BY_STATE_PF = { 25 | "AC": "15861", 26 | "AL": "15862", 27 | "AP": "15863", 28 | "AM": "15864", 29 | "BA": "15865", 30 | "CE": "15866", 31 | "DF": "15867", 32 | "ES": "15868", 33 | "GO": "15869", 34 | "MA": "15870", 35 | "MT": "15871", 36 | "MS": "15872", 37 | "MG": "15873", 38 | "PA": "15874", 39 | "PB": "15875", 40 | "PR": "15876", 41 | "PE": "15877", 42 | "PI": "15878", 43 | "RJ": "15879", 44 | "RN": "15880", 45 | "RS": "15881", 46 | "RO": "15882", 47 | "RR": "15883", 48 | "SC": "15884", 49 | "SP": "15885", 50 | "SE": "15886", 51 | "TO": "15887", 52 | } 53 | NON_PERFORMING_LOANS_BY_REGION_PJ = { 54 | "N": "15920", 55 | "NE": "15921", 56 | "CO": "15922", 57 | "SE": "15923", 58 | "S": "15924", 59 | } 60 | NON_PERFORMING_LOANS_BY_STATE_PJ = { 61 | "AC": "15893", 62 | "AL": "15894", 63 | "AP": "15895", 64 | "AM": "15896", 65 | "BA": "15897", 66 | "CE": "15898", 67 | "DF": "15899", 68 | "ES": "15900", 69 | "GO": "15901", 70 | "MA": "15902", 71 | "MT": "15903", 72 | "MS": "15904", 73 | "MG": "15905", 74 | "PA": "15906", 75 | "PB": "15907", 76 | "PR": "15908", 77 | "PE": "15909", 78 | "PI": "15910", 79 | "RJ": "15911", 80 | "RN": "15912", 81 | "RS": "15913", 82 | "RO": "15914", 83 | "RR": "15915", 84 | "SC": "15916", 85 | "SP": "15917", 86 | "SE": "15918", 87 | "TO": "15919", 88 | } 89 | NON_PERFORMING_LOANS_BY_REGION_TOTAL = { 90 | "N": "15952", 91 | "NE": "15953", 92 | "CO": "15954", 93 | "SE": "15955", 94 | "S": "15956", 95 | } 96 | NON_PERFORMING_LOANS_BY_STATE_TOTAL = { 97 | "AC": "15925", 98 | "AL": "15926", 99 | "AP": "15927", 100 | "AM": "15928", 101 | "BA": "15929", 102 | "CE": "15930", 103 | "DF": "15931", 104 | "ES": "15932", 105 | "GO": "15933", 106 | "MA": "15934", 107 | "MT": "15935", 108 | "MS": "15936", 109 | "MG": "15937", 110 | "PA": "15938", 111 | "PB": "15939", 112 | "PR": "15940", 113 | "PE": "15941", 114 | "PI": "15942", 115 | "RJ": "15943", 116 | "RN": "15944", 117 | "RS": "15945", 118 | "RO": "15946", 119 | "RR": "15947", 120 | "SC": "15948", 121 | "SP": "15949", 122 | "SE": "15950", 123 | "TO": "15951", 124 | } 125 | 126 | 127 | def get_non_performing_loans_codes(states_or_region: Union[str, List[str]], mode: str = "total") -> Dict[str, str]: 128 | is_state = False 129 | is_region = False 130 | states_or_region = [states_or_region] if isinstance(states_or_region, str) else states_or_region 131 | states_or_region = [location.upper() for location in states_or_region] 132 | if any(location in list(NON_PERFORMING_LOANS_BY_STATE_TOTAL.keys()) for location in states_or_region): 133 | is_state = True 134 | elif any(location in list(NON_PERFORMING_LOANS_BY_REGION_TOTAL.keys()) for location in states_or_region): 135 | is_region = True 136 | 137 | if not is_state and not is_region: 138 | raise Exception(f"Not a valid state or region: {states_or_region}") 139 | 140 | codes = {} 141 | non_performing_loans_by_location = NON_PERFORMING_LOANS_BY_STATE_TOTAL 142 | if is_state: 143 | if mode.upper() == "PF": 144 | non_performing_loans_by_location = NON_PERFORMING_LOANS_BY_STATE_PF 145 | elif mode.upper() == "PJ": 146 | non_performing_loans_by_location = NON_PERFORMING_LOANS_BY_STATE_PJ 147 | elif is_region: 148 | non_performing_loans_by_location = NON_PERFORMING_LOANS_BY_REGION_TOTAL 149 | if mode.upper() == "PF": 150 | non_performing_loans_by_location = NON_PERFORMING_LOANS_BY_REGION_PF 151 | elif mode.upper() == "PJ": 152 | non_performing_loans_by_location = NON_PERFORMING_LOANS_BY_REGION_PJ 153 | 154 | for location in states_or_region: 155 | codes[location] = non_performing_loans_by_location[location] 156 | return codes 157 | 158 | 159 | def get_non_performing_loans( 160 | states_or_region: Union[str, List[str]], 161 | mode: str = "total", 162 | start: Optional[DateInput] = None, 163 | end: Optional[DateInput] = None, 164 | last: int = 0, 165 | freq: Optional[str] = None, 166 | ) -> pd.DataFrame: 167 | """Dados de inadimplência das operações de crédito. 168 | 169 | Esta função é um *wrapper* para o método para a função ``get`` do módulo ``sgs``, 170 | simplificando o acesso aos dados de inadimplência das operações de crédito. 171 | Nessa função o usuário escolhe o tipo de inadimplência, o(s) estado(s) ou as regiões 172 | que deseja obter os dados. 173 | 174 | >>> from bcb.sgs.regional_economy import get_non_performing_loans 175 | >>> from bcb.utils import BRAZILIAN_REGIONS 176 | >>> series = get_non_performing_loans(["RR"], last=10, mode="all") 177 | >>> northeast_states = BRAZILIAN_REGIONS["NE"] 178 | >>> series_ne = get_non_performing_loans(northeast_states, last=5, mode="pj") 179 | 180 | Parameters 181 | ---------- 182 | 183 | states_or_region (List[str]): Uma lista com estado ou região. 184 | mode (str): O tipo de inadimplência. Pode ser "PF" (pessoas físicas), 185 | "PJ" (pessoas jurídicas) ou "total" (inadimplência total). 186 | start : str, int, date, datetime, Timestamp 187 | Data de início da série. 188 | Interpreta diferentes tipos e formatos de datas. 189 | end : string, int, date, datetime, Timestamp 190 | Data final da série. 191 | Interpreta diferentes tipos e formatos de datas. 192 | last : int 193 | Retorna os últimos ``last`` elementos disponíveis da série temporal 194 | solicitada. Se ``last`` for maior que 0 (zero) os argumentos ``start`` 195 | e ``end`` são ignorados. 196 | freq : str 197 | Define a frequência a ser utilizada na série temporal 198 | 199 | 200 | Returns 201 | ------- 202 | 203 | ``DataFrame`` : 204 | série temporal univariada ou multivariada, 205 | quando solicitado mais de uma série temporal. 206 | """ 207 | codes = get_non_performing_loans_codes(states_or_region, mode=mode) 208 | return get(codes, start=start, end=end, last=last, multi=True, freq=freq) 209 | -------------------------------------------------------------------------------- /bcb/utils.py: -------------------------------------------------------------------------------- 1 | from datetime import date, datetime 2 | from typing import TypeAlias, Union 3 | 4 | BRAZILIAN_REGIONS = { 5 | "N": ["AC", "AP", "AM", "PA", "RO", "RR", "TO"], 6 | "NE": ["AL", "BA", "CE", "MA", "PB", "PE", "PI", "RN", "SE"], 7 | "CO": ["DF", "GO", "MT", "MS"], 8 | "SE": ["ES", "MG", "RJ", "SP"], 9 | "S": ["PR", "RS", "SC"], 10 | } 11 | BRAZILIAN_STATES = [] 12 | for state in BRAZILIAN_REGIONS.values(): 13 | BRAZILIAN_STATES.extend(state) 14 | 15 | DateInput: TypeAlias = Union[str, datetime, "Date", date] 16 | 17 | 18 | class Date: 19 | def __init__(self, d: DateInput, format: str = "%Y-%m-%d") -> None: 20 | if isinstance(d, str): 21 | if d == "now" or d == "today": 22 | d = date.today() 23 | else: 24 | d = datetime.strptime(d, format).date() 25 | elif isinstance(d, datetime): 26 | d = d.date() 27 | elif isinstance(d, Date): 28 | d = d.date 29 | elif isinstance(d, date): 30 | pass 31 | else: 32 | raise ValueError() 33 | self.date: date = d 34 | 35 | def format(self, fmts: str = "%Y-%m-%d") -> str: 36 | return datetime.strftime(self.date, fmts) 37 | 38 | def __gt__(self, other) -> bool: 39 | return self.date > other.date 40 | 41 | def __ge__(self, other) -> bool: 42 | return self.date >= other.date 43 | 44 | def __lt__(self, other) -> bool: 45 | return self.date < other.date 46 | 47 | def __le__(self, other) -> bool: 48 | return self.date <= other.date 49 | 50 | def __eq__(self, other) -> bool: 51 | return self.date == other.date 52 | 53 | def __repr__(self) -> str: 54 | return self.format() 55 | 56 | __str__ = __repr__ 57 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static/images/ipca12m-acumulado.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wilsonfreitas/python-bcb/740551b5a78b50fa72c86a063ddf91c4556fd331/docs/_static/images/ipca12m-acumulado.png -------------------------------------------------------------------------------- /docs/_static/images/savefig/currency1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wilsonfreitas/python-bcb/740551b5a78b50fa72c86a063ddf91c4556fd331/docs/_static/images/savefig/currency1.png -------------------------------------------------------------------------------- /docs/_static/images/savefig/sgs1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wilsonfreitas/python-bcb/740551b5a78b50fa72c86a063ddf91c4556fd331/docs/_static/images/savefig/sgs1.png -------------------------------------------------------------------------------- /docs/_static/images/savefig/taxajuros1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wilsonfreitas/python-bcb/740551b5a78b50fa72c86a063ddf91c4556fd331/docs/_static/images/savefig/taxajuros1.png -------------------------------------------------------------------------------- /docs/_static/images/selic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wilsonfreitas/python-bcb/740551b5a78b50fa72c86a063ddf91c4556fd331/docs/_static/images/selic.png -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | 2 | API 3 | === 4 | 5 | Módulo :py:mod:`bcb.sgs` 6 | ------------------------ 7 | 8 | .. automodule:: bcb.sgs 9 | :members: 10 | 11 | .. automodule:: bcb.sgs.regional_economy 12 | :members: 13 | 14 | Módulo :py:mod:`bcb.currency` 15 | ----------------------------- 16 | 17 | .. automodule:: bcb.currency 18 | :members: 19 | 20 | APIs OData 21 | ---------- 22 | 23 | .. automodule:: bcb.odata.api 24 | :members: 25 | :show-inheritance: 26 | :member-order: bysource 27 | :special-members: __init__ 28 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | 13 | import os 14 | import sys 15 | 16 | sys.path.insert(0, os.path.abspath("..")) 17 | 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = "python-bcb" 22 | copyright = "2021, Wilson Freitas" 23 | author = "Wilson Freitas" 24 | 25 | # The full version, including alpha/beta/rc tags 26 | # release = '0.1.7' 27 | 28 | 29 | # -- General configuration --------------------------------------------------- 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = [ 35 | "sphinx.ext.autodoc", 36 | "sphinx.ext.autosummary", 37 | "sphinx.ext.intersphinx", 38 | "sphinx.ext.napoleon", 39 | "sphinx.ext.autosectionlabel", 40 | "IPython.sphinxext.ipython_directive", 41 | "IPython.sphinxext.ipython_console_highlighting", 42 | "matplotlib.sphinxext.plot_directive", 43 | ] 44 | 45 | # The language for content autogenerated by Sphinx. Refer to documentation 46 | # for a list of supported languages. 47 | # 48 | # This is also used if you do content translation via gettext catalogs. 49 | # Usually you set "language" from the command line for these cases. 50 | language = "pt_br" 51 | 52 | # List of patterns, relative to source directory, that match files and 53 | # directories to ignore when looking for source files. 54 | # This pattern also affects html_static_path and html_extra_path. 55 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 56 | 57 | 58 | # -- Options for HTML output ------------------------------------------------- 59 | 60 | # The theme to use for HTML and HTML Help pages. See the documentation for 61 | # a list of builtin themes. 62 | # 63 | html_theme = "furo" 64 | html_theme_options = { 65 | "source_repository": "https://github.com/wilsonfreitas/python-bcb/", 66 | "source_branch": "main", 67 | "source_directory": "docs/", 68 | } 69 | # html_theme = "alabaster" 70 | # html_theme_options = { 71 | # "description": "Interface em Python para o portal de dados abertos do BCB", 72 | # "github_user": "wilsonfreitas", 73 | # "github_repo": "python-bcb", 74 | # "fixed_sidebar": True, 75 | # } 76 | 77 | 78 | # Add any paths that contain custom static files (such as style sheets) here, 79 | # relative to this directory. They are copied after the builtin static files, 80 | # so a file named "default.css" will overwrite the builtin "default.css". 81 | html_static_path = ["_static"] 82 | 83 | autosummary_generate = True 84 | 85 | ipython_savefig_dir = "_static/images/savefig/" 86 | -------------------------------------------------------------------------------- /docs/currency.rst: -------------------------------------------------------------------------------- 1 | Moedas 2 | ====== 3 | 4 | O pacote tem 2 APIs que dão acesso a informações de moedas. 5 | 6 | 7 | - :ref:`API OData de Moedas` com cotações de taxas de câmbio 8 | - Webscraping no :ref:`Conversor de Moedas` 9 | 10 | API OData de Moedas 11 | ------------------- 12 | 13 | 14 | .. _documentacao: https://olinda.bcb.gov.br/olinda/servico/PTAX/versao/v1/documentacao 15 | 16 | __ documentacao_ 17 | 18 | A classe :py:class:`bcb.PTAX` retorna cotações de moedas os obtidas a partir da `API de Moedas`__ do BCB. 19 | Esta implementação é mais estável que a do :ref:`Conversor de Moedas`. 20 | 21 | .. ipython:: python 22 | 23 | from bcb import PTAX 24 | ptax = PTAX() 25 | ptax.describe() 26 | 27 | 28 | .. ipython:: python 29 | 30 | ptax.describe('Moedas') 31 | 32 | ep = ptax.get_endpoint('Moedas') 33 | ep.query().limit(10).collect() 34 | 35 | .. ipython:: python 36 | 37 | ptax.describe('CotacaoMoedaDia') 38 | 39 | ep = ptax.get_endpoint('CotacaoMoedaDia') 40 | (ep.query() 41 | .parameters(moeda='AUD', dataCotacao='1/31/2022') 42 | .collect()) 43 | 44 | É importante notar que as datas estão no formato mês/dia/ano e os números não 45 | são preenchidos com 0 para ter 2 dígitos. 46 | 47 | .. ipython:: python 48 | 49 | ptax.describe('CotacaoMoedaPeriodo') 50 | 51 | ep = ptax.get_endpoint('CotacaoMoedaPeriodo') 52 | (ep.query() 53 | .parameters(moeda='AUD', 54 | dataInicial='1/1/2022', 55 | dataFinalCotacao='1/5/2022') 56 | .collect()) 57 | 58 | Conversor de Moedas 59 | ------------------- 60 | 61 | O módulo :py:mod:`bcb.currency` obtem dados de moedas do conversor de moedas do Banco Central através de webscraping. 62 | 63 | .. ipython:: python 64 | 65 | from bcb import currency 66 | df = currency.get(['USD', 'EUR'], 67 | start='2000-01-01', 68 | end='2021-01-01', 69 | side='ask') 70 | df.head() 71 | 72 | @savefig currency1.png 73 | df.plot(figsize=(12, 6)); 74 | 75 | 76 | .. ipython:: python 77 | 78 | currency.get_currency_list().head() 79 | 80 | -------------------------------------------------------------------------------- /docs/expectativas.rst: -------------------------------------------------------------------------------- 1 | Expectativas 2 | ############ 3 | 4 | A API de expectativas divulgadas no boletim FOCUS pode ser acessada através da classe 5 | :py:class:`bcb.Expectativas`. 6 | 7 | .. _documentacao: https://olinda.bcb.gov.br/olinda/servico/Expectativas/versao/v1/documentacao 8 | 9 | __ documentacao_ 10 | 11 | Os dados são obtidos a partir da `API de Expectativas`__. 12 | 13 | Integração com API de expectativas de mercado de cerca de 130 14 | instituições do mercado financeiro participantes do 15 | Sistema de Expectativas de Mercado para diversas variáveis 16 | macroeconômicas. 17 | 18 | Os dados são publicados no primeiro dia útil de cada semana. 19 | 20 | Para períodos para os quais não haja estatísticas serão omitidos 21 | na consulta. 22 | 23 | São publicadas as expectativas informadas pelas instituições que 24 | autorizaram a divulgação. As expectativas divulgadas possuem 25 | defasagem de 1 ano. 26 | 27 | Ao instanciar a classe :py:class:`bcb.Expectativas` diversas informações 28 | são obtidas e a melhor maneira de interagir com a API é 29 | através do método :py:meth:`bcb.Expectativas.describe`. 30 | 31 | 32 | .. ipython:: python 33 | 34 | from bcb import Expectativas 35 | em = Expectativas() 36 | em.describe() 37 | 38 | O método :py:meth:`bcb.Expectativas.describe` também recebe o nomes dos 39 | *endpoints* e apresenta uma descrição do *endpoint* trazendo o seu tipo 40 | `EntityType` e as propriedades retornadas `Properties` e os seus respectivos 41 | tipos. 42 | 43 | .. ipython:: python 44 | 45 | em.describe('ExpectativasMercadoTop5Anuais') 46 | 47 | Esse *endpoint* retorna as colunas: 48 | 49 | - Indicador 50 | - Data 51 | - DataReferencia 52 | - tipoCalculo 53 | - Media 54 | - Mediana 55 | - DesvioPadrao 56 | - Minimo 57 | - Maximo 58 | 59 | Para obter os dados de um *endpoint* é necessário obtê-lo através do 60 | método :py:meth:`bcb.Expectativas.get_endpoint` que retorna uma classe 61 | :py:class:`bcb.Endpoint`. 62 | 63 | .. ipython:: python 64 | 65 | ep = em.get_endpoint('ExpectativasMercadoTop5Anuais') 66 | 67 | A partir desse *endpoint* executar uma consulta com o método :py:meth:`bcb.Endpoint.query`. 68 | 69 | .. ipython:: python 70 | 71 | ep.query().limit(10).collect() 72 | 73 | 74 | O método :py:meth:`bcb.Endpoint.query` retorna um objeto da classe 75 | :py:class:`bcb.odata.ODataQuery` que possui diversas características 76 | para a realização de consultas mais elaboradas. 77 | 78 | Note que no exemplo acima foi utilizado o método ``limit`` que limita 79 | a quantidade de resultados retornados, neste caso, em 10. 80 | 81 | É possível realizar consultas mais elaboradas, por exemplo, filtrando pelo 82 | indicador para que traga apenas informações do IPCA. 83 | 84 | .. ipython:: python 85 | 86 | ep.query().filter(ep.Indicador == 'IPCA').limit(10).collect() 87 | 88 | 89 | As consultas podem ficar ainda mais elaboradas, com diversos filtros, 90 | ordenando colunas e selecionando as colunas na saída. 91 | 92 | .. ipython:: python 93 | 94 | (ep.query() 95 | .filter(ep.Indicador == 'IPCA', ep.DataReferencia == 2023) 96 | .filter(ep.Data >= '2022-01-01') 97 | .filter(ep.tipoCalculo == 'C') 98 | .select(ep.Data, ep.Media, ep.Mediana) 99 | .orderby(ep.Data.desc()) 100 | .limit(10) 101 | .collect()) 102 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. python-bcb documentation master file, created by 2 | sphinx-quickstart on Mon Dec 27 10:36:49 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | python-bcb 7 | ========== 8 | 9 | **python-bcb** é uma interface em Python estruturada para obter informações 10 | da API de dados abertos do `Banco Central do Brasil `_. 11 | 12 | .. image:: _static/images/ipca12m-acumulado.png 13 | 14 | O projeto de `Dados Abertos do Banco Central do Brasil `_ 15 | disponibiliza diversas APIs provendo acesso direto a dados de: 16 | 17 | * Moedas 18 | * Taxas de Juros 19 | * Índices de preços 20 | * Informações de Instituições Financeiras 21 | * Expectativas do Mercado (Expectativas do Boletim FOCUS) 22 | * E muito outros ... 23 | 24 | O pacote ``python-bcb`` implementa interfaces para algumas APIs 25 | disponibilizadas pelo Banco Central de forma que o resultado 26 | das consultas, na maioria dos casos, é um ``DataFrame`` pandas 27 | formatado com os dados. 28 | 29 | Instalação 30 | ========== 31 | 32 | **python-bcb** está disponível no `Python Package Index `_ e pode ser instalado via ``pip`` usando. 33 | 34 | .. code-block:: bash 35 | 36 | pip install python-bcb 37 | 38 | 39 | APIs implementadas 40 | ================== 41 | 42 | ``sgs`` 43 | Utiliza o webservice do SGS 44 | (`Sistema Gerenciador de Séries Temporais `_) 45 | para obter os dados. 46 | Diversas séries estão disponíveis no SGS: taxas de juros, índices de preços, 47 | indicadores econômicos, ..., e com um simples chamado da função 48 | :py:func:`bcb.sgs.get` é possível tê-las 49 | em um ``DataFrame`` pandas. 50 | Veja a documentação em :ref:`SGS`. 51 | ``Conversor de Moedas`` 52 | Implementado no módulo ``currency``, um conjunto de funções que realiza webscraping 53 | no site do `Conversor de Moedas `_ 54 | do Banco Central, possível obter séries temporais de frequência diária 55 | de diversas moedas. 56 | Veja a documentação em :ref:`Conversor de Moedas`. 57 | ``Moedas OData`` 58 | O Banco Central disponibiliza diversas informações em APIs que 59 | seguem o padrão `OData `. 60 | A classe :py:class:`bcb.PTAX` implementa uma API OData que 61 | entrega os boletins diários de taxas de câmbio do Banco Central. 62 | Esta API entrega mais informações do que o que é obtido no 63 | ``Conversor de Moedas``. 64 | Veja a documentação em :ref:`Moedas`. 65 | ``Expectativas`` 66 | A API de Expectativas de Mercado traz todas as estatísticas das variáveis 67 | macroeconômicas fornecidos por um conjuto de instituições do mercado 68 | financeiro. 69 | A classe :py:class:`bcb.Expectativas` implementa essa interface no 70 | padrão OData. 71 | Veja a documentação em :ref:`Expectativas`. 72 | ``Taxas de Juros`` 73 | API que retorna as taxas de juros de operações de crédito por instituição financeira (médias dos últimos 5 dias). 74 | A classe :py:class:`bcb.TaxaJuros` implementa essa interface. 75 | Veja a documentação em :ref:`Taxas de Juros`. 76 | ``ODataAPI`` 77 | O BCB disponibiliza diversas APIs que seguem a especificação OData. 78 | Algumas APIs mais utilizadas como as :py:class:`bcb.PTAX` e 79 | :py:class:`bcb.Expectativas` possuem uma classe específica, para as 80 | APIs menos utilizadas, é possível utilizar a classe :py:class:`bcb.ODataAPI` 81 | para acessar a API. 82 | Toda API que segue a especificação OData possui uma URL de acesso, esta URL 83 | é passada para a classe :py:class:`bcb.ODataAPI` e o objeto criado dá 84 | total acesso a API. 85 | Veja a documentação em :ref:`Classe ODataAPI`. 86 | Muito mais 87 | Veja todos os *endpoints* implementados na documentação de nossa :ref:`API`. 88 | 89 | 90 | Uso 91 | === 92 | 93 | .. ipython:: python 94 | 95 | from bcb import sgs 96 | sgs.get(('IPCA', 433), last=12) 97 | 98 | 99 | .. toctree:: 100 | :maxdepth: 1 101 | 102 | sgs 103 | currency 104 | expectativas 105 | taxajuros 106 | odata 107 | api 108 | 109 | Índices e tabelas 110 | ================== 111 | 112 | * :ref:`genindex` 113 | * :ref:`modindex` -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.https://www.sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/odata.rst: -------------------------------------------------------------------------------- 1 | 2 | OData 3 | ===== 4 | 5 | Diversas APIs disponíveis no `portal de dados abertos `_ do Banco Central 6 | implementam o protocolo `OData `_, são centenas de APIs. 7 | 8 | O ``python-bcb`` tem algumas classes que implementam APIs OData: 9 | 10 | - :py:class:`bcb.odata.api.Expectativas`: Expectativas de mercado para os indicadores macroeconômicos da Pesquisa Focus 11 | - :py:class:`bcb.odata.api.PTAX`: Dólar comercial 12 | - :py:class:`bcb.odata.api.TaxaJuros`: Taxas de juros de operações de crédito por instituição financeira 13 | - :py:class:`bcb.odata.api.IFDATA`: Dados selecionados de instituições financeiras 14 | - :py:class:`bcb.odata.api.MercadoImobiliario`: Informações do Mercado Imobiliário 15 | - :py:class:`bcb.odata.api.SPI`: Estatísticas do SPI (Sistema de Pagamentos Instantâneos) 16 | - Veja todas as APIs implementadas em :ref:`APIs OData`. 17 | 18 | Estas APIs foram implementadas em classes por serem as mais populares, entretanto, 19 | qualquer API OData pode ser acessada através da classe :py:class:`bcb.odata.api.ODataAPI` que abstrai o acesso 20 | a API a partir da URL da API que está disponível no `portal de dados abertos `_ 21 | do Banco Central. 22 | Veja mais detalhes em :ref:`Classe ODataAPI`. 23 | 24 | Segue um exemplo de como acessar a API do PIX. 25 | 26 | .. ipython:: python 27 | 28 | from bcb import SPI 29 | pix = SPI() 30 | 31 | É necessário importar e criar um objeto da classe que implementa a API, neste caso a classe ``SPI``. 32 | Tendo o objeto, executar o método ``describe`` para visualizar o *endpoints* disponíveis na API. 33 | 34 | 35 | .. ipython:: python 36 | 37 | pix.describe() 38 | 39 | Como vemos, a API do PIX tem 4 *endpoints* (``EntitySets``). 40 | Para ver as informações retornadas por cada *endpoint* é só executar o método ``describe`` passando como argumento 41 | o nome do *endpoint*. 42 | 43 | .. ipython:: python 44 | 45 | pix.describe("PixLiquidadosAtual") 46 | 47 | Vemos que o *endpoint* ``PixLiquidadosAtual`` retorna 4 propriedades: 48 | 49 | - ``Data``: data das operações 50 | - ``Quantidade``: quantidade de operações realizadas na data 51 | - ``Total``: financeiro das operações realizdas na data 52 | - ``Media``: média das operações realizadas na data 53 | 54 | As propriedades são atributos de objetos da classe :py:class:`bcb.odata.api.Endpoint`, retornados pelo método 55 | ``get_endpoint``. 56 | 57 | .. ipython:: python 58 | 59 | ep = pix.get_endpoint("PixLiquidadosAtual") 60 | ep.Data 61 | ep.Media 62 | 63 | Para acessar os dados deste *endpoint* é necessário executar uma ``query`` nesse objeto. 64 | 65 | .. ipython:: python 66 | 67 | ep.query().limit(5).collect() 68 | 69 | Ao realizar a ``query`` no *endpoint* limitamos a consulta a retornar 10 elementos, apenas para visualizar os dados 70 | da consulta. 71 | A consulta retorna um DataFrame pandas onde as colunas são as propriedades do *endpoint*. 72 | 73 | Veremos abaixo, com mais detalhes, como realizar consultas nas APIs e quais os tipos de *endpoints* disponíveis 74 | (``EntitySets`` e ``FunctionImports``). 75 | 76 | Como Realizar Consultas em APIs OData 77 | ------------------------------------- 78 | 79 | As consultas são realizadas através do método ``query`` da classe :py:class:`bcb.odata.api.Endpoint`. 80 | Este método retorna um objeto :py:class:`bcb.odata.framework.ODataQuery` que abstrai a consulta e permite executar 81 | algumas firulas como: filtros e ordenação. 82 | A classe :py:class:`bcb.odata.framework.ODataQuery` tem os seguintes métodos: 83 | 84 | - :py:meth:`bcb.odata.framework.ODataQuery.filter`: define filtros na consulta, com uma clausula ``where`` no SQL. 85 | - :py:meth:`bcb.odata.framework.ODataQuery.select`: seleciona as propriedades retornadas pela consulta. 86 | - :py:meth:`bcb.odata.framework.ODataQuery.orderby`: ordena a consulta pelas propriedades. 87 | - :py:meth:`bcb.odata.framework.ODataQuery.limit`: limita os resultados a ``n`` registros. 88 | - :py:meth:`bcb.odata.framework.ODataQuery.parameters`: *endpoints* do tipo ``FunctionImports`` possuem parâmetros que são definidos por este método. 89 | - :py:meth:`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. 90 | - :py:meth:`bcb.odata.framework.ODataQuery.text`: este método retorna o texto (formato json) retornado pela API. 91 | - :py:meth:`bcb.odata.framework.ODataQuery.show`: imprime a estrutura da consulta. 92 | 93 | Os métodos ``filter``, ``select``, ``orderby``, ``limit`` e ``parameters`` retornam o objeto 94 | :py:class:`bcb.odata.framework.ODataQuery`, e isso permite a realização de chamadas aninhadas que compõem a consulta. 95 | 96 | Por exemplo, na consulta do PIX, as datas não estão ordenadas, temos dias de 2021, 2022 e 2023 nos 10 registros 97 | retornados. 98 | Vamos ordernar pela propriedade ``Data`` de forma decrescente. 99 | 100 | .. ipython:: python 101 | 102 | ep.query().orderby(ep.Data.desc()).limit(5).collect() 103 | 104 | Veja que a consulta retorna as datas mais recentes primeiro. 105 | 106 | Gosto de estruturar as consultas como uma *query* SQL. 107 | Sigamos com um exemplo: 108 | 109 | .. code:: SQL 110 | 111 | select Data, Media 112 | from PIX 113 | where Data >= "2023-01-01" 114 | order by Media desc 115 | limit 10 116 | 117 | Quero obter os 10 dias em 2023 que apresentam as maiores médias transacionadas no PIX. 118 | 119 | Para executar essa query utilizo o método ``select`` passando as propriedades Data e Media, 120 | encadeio o método ``filter`` filtrando a propriedade Data maiores que 2023-01-01, e note 121 | que aqui utilizo um objeto ``datetime``, pois na descrição do *endpoint* ``PixLiquidadosAtual`` 122 | a propriedade Data é do tipo ``datetime``. 123 | Sigo com o método ``orderby`` passando a propriedade média e indicando que a ordenação é decrescente e concluo com 124 | o método ``limit`` para obter os 10 primeiros registros. 125 | Na última linha executo o método ``collect`` que executa a consulta e retorna um DataFrame com os resultados. 126 | 127 | .. ipython:: python 128 | 129 | from datetime import datetime 130 | (ep.query() 131 | .select(ep.Data, ep.Media) 132 | .filter(ep.Data >= datetime(2023, 1, 1)) 133 | .orderby(ep.Media.desc()) 134 | .limit(5) 135 | .collect()) 136 | 137 | Visualizando a Consulta 138 | ^^^^^^^^^^^^^^^^^^^^^^^ 139 | 140 | Algumas consultas podem ficar bastante complicadas, dependendo da quantidade de elementos que compõem a consulta. 141 | Para ajudar na construção e na depuração da *query*, criamos o método ``show`` imprime a query na tela, 142 | mas não a executa. 143 | 144 | .. ipython:: python 145 | 146 | (ep.query() 147 | .select(ep.Data, ep.Media) 148 | .filter(ep.Data >= datetime(2023, 1, 1)) 149 | .orderby(ep.Media.desc()) 150 | .limit(5) 151 | .show()) 152 | 153 | 154 | Filtrando Dados 155 | ^^^^^^^^^^^^^^^ 156 | 157 | Os filtros são criados com o método ``filter`` e aplicados às propriedades do *endpoint*, por isso é necessário 158 | conhecê-lo, o que deve ser feito com o método ``describe``. 159 | 160 | .. ipython:: python 161 | 162 | from bcb import Expectativas 163 | em = Expectativas() 164 | em.describe('ExpectativasMercadoTop5Anuais') 165 | 166 | O *endpoint* ``ExpectativasMercadoTop5Anuais`` da API de Expectativas possui a propriedade ``Indicador``, do tipo 167 | ``str``. 168 | Vamos filtrar os dados com a propriedade ``Indicador`` igual a ``IPCA``. 169 | Como o tipo dessa propriedade é ``str``, utilizamos uma string no filtro e o operador ``==``, que representa igualdade. 170 | 171 | .. ipython:: python 172 | 173 | ep = em.get_endpoint('ExpectativasMercadoTop5Anuais') 174 | query = ep.query().filter(ep.Indicador == 'IPCA').limit(5) 175 | query.show() 176 | 177 | O método ``show`` apresenta os parâmetros da *query* formatados, com isso podemos visualizar como os parâmetros da 178 | consulta serão enviados à API. 179 | Note que o operador ``==`` foi convertido para ``eq``. 180 | Podemos utilizar todos os operadores de comparação nos filtros. 181 | 182 | .. ipython:: python 183 | 184 | query.collect() 185 | 186 | Mais filtros podem ser adicionados ao método ``filter``, e também podemos aninhar chamadas do método ``filter``. 187 | 188 | .. ipython:: python 189 | 190 | query = (ep.query() 191 | .filter(ep.Indicador == 'IPCA', ep.DataReferencia == 2023) 192 | .filter(ep.Data >= '2022-01-01') 193 | .filter(ep.tipoCalculo == 'C') 194 | .limit(5)) 195 | query.show() 196 | query.collect() 197 | 198 | Todos os filtros estão no atributo ``$filter`` da consulta e são concatenados com o operador booleano ``and``. 199 | 200 | É necessário conhecer o tipo da propriedade para saber como passar o objeto para a consulta. 201 | Os tipos de propriedade podem ser: str, float, int e datetime. 202 | Por exemplo, na API do PIX, a propriedade ``Data`` é do tipo ``datetime`` e por isso é necessário passar um 203 | objeto ``datetime`` para o método ``filter``. 204 | 205 | .. ipython:: python 206 | 207 | ep = pix.get_endpoint("PixLiquidadosAtual") 208 | (ep.query() 209 | .filter(ep.Data >= datetime(2023, 1, 1)) 210 | .limit(5) 211 | .show()) 212 | 213 | O objeto ``datetime`` é formatado como data na consulta, note que não há aspas na definição da data no filtro. 214 | 215 | Ordenando os Dados 216 | ^^^^^^^^^^^^^^^^^^ 217 | 218 | A ordenação é definida no método ``orderby`` passando um objeto da classe 219 | :py:class:`bcb.odata.framework.ODataPropertyOrderBy` que é obtida dos métodos ``asc`` e ``desc`` da propriedade. 220 | 221 | .. ipython:: python 222 | 223 | ep = pix.get_endpoint("PixLiquidadosAtual") 224 | ep.Data.asc() 225 | 226 | Este objeto é passado para o método ``orderby`` na *tripa* na qual a *query* é construída. 227 | 228 | .. ipython:: python 229 | 230 | query = (ep.query() 231 | .orderby(ep.Data.asc()) 232 | .limit(5)) 233 | query.show() 234 | query.collect() 235 | 236 | O método ``orderby`` pode receber diversas propriedades para a definição da ordenação. 237 | 238 | .. ipython:: python 239 | 240 | ep = em.get_endpoint('ExpectativasMercadoTop5Anuais') 241 | query = (ep.query() 242 | .orderby(ep.Data.desc(), ep.Indicador.desc()) 243 | .limit(5)) 244 | query.show() 245 | 246 | Também podem ser realizadas chamadas aninhadas do método ``orderby``. 247 | 248 | .. ipython:: python 249 | 250 | query = (ep.query() 251 | .orderby(ep.Data.desc()) 252 | .orderby(ep.Indicador.desc()) 253 | .limit(5)) 254 | query.show() 255 | 256 | Vejam que a consulta é exatamente a mesma. 257 | 258 | 259 | Selecionando as Propriedades 260 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 261 | 262 | O médoto ``select`` funciona de forma muito semelhante ao *select* de uma *query* SQL. 263 | 264 | .. ipython:: python 265 | 266 | ep = em.get_endpoint('ExpectativasMercadoTop5Anuais') 267 | (ep.query() 268 | .select(ep.Indicador, ep.Data, ep.DataReferencia, ep.tipoCalculo, ep.Media) 269 | .orderby(ep.Data.desc()) 270 | .limit(5) 271 | .collect()) 272 | 273 | Selecionar as colunas é importante para reduzir o volume de dados trafegado, pois a API do BCB não tem um bom 274 | desempenho, logo, essas configurações aceleram as consultas. 275 | 276 | 277 | Método ``limit`` 278 | ^^^^^^^^^^^^^^^^ 279 | 280 | O método ``limit`` define a quantidade de linhas que será retornada pela consulta. 281 | Esse método é importante para investigar as consultas na API de forma rápida. 282 | 283 | .. ipython:: python 284 | 285 | ep = pix.get_endpoint("PixLiquidadosAtual") 286 | (ep.query() 287 | .filter(ep.Data >= datetime(2023, 1, 1)) 288 | .limit(5) 289 | .collect()) 290 | 291 | 292 | 293 | Tipos de *endpoints* 294 | ^^^^^^^^^^^^^^^^^^^^ 295 | 296 | Como foi visto anteriormente, a API do PIX (``SPI``) possui 4 ``EntitySets`` e estes são os *endpoints* dessa API. 297 | Entretanto, há APIs que têm um outro tipo de *endpoint*, os ``FunctionImports``. 298 | A API do PTAX, por exemplo 299 | 300 | .. ipython:: python 301 | 302 | from bcb import PTAX 303 | 304 | ptax = PTAX() 305 | ptax.describe() 306 | 307 | Esta API tem 1 ``EntitySet`` e 6 ``FunctionImports``. 308 | Assim como os ``EntitySets``, os ``FunctionImports`` também retornam dados em formato tabular. 309 | A principal diferença entre os ``EntitySets`` e ``FunctionImports`` é que estes possuem parâmetros, como uma função, e 310 | estes parâmetros devem ser definidos para que a consulta seja realizada. 311 | 312 | Vamos ver o *endpoint* ``CotacaoMoedaPeriodo`` 313 | 314 | .. ipython:: python 315 | 316 | ptax.describe("CotacaoMoedaPeriodo") 317 | 318 | Este *endpoint* tem 3 parâmetros: 319 | 320 | - codigoMoeda 321 | - dataInicial 322 | - dataFinalCotacao 323 | 324 | Para conhecer como os parâmetros devem ser definidos é necessário ler a documentação da API. 325 | Eventualmente a definição dos parâmetros não é óbvia. 326 | Por exemplo, neste *endpoint*, os parâmetros ``dataInicial`` e ``dataFinalCotacao`` são formatados com 327 | mês-dia-ano (formato americano), ao invés de ano-mês-dia (formato ISO), e como o tipo dos parâmetros é ``str``, 328 | uma formatação incorreta não retorna um erro, apenas retorna um DataFrame vazio. 329 | 330 | Vamos realizar uma consulta para obter as cotações de dólar americano entre 2022-01-01 e 2022-01-05. 331 | 332 | .. ipython:: python 333 | 334 | ep = ptax.get_endpoint("CotacaoMoedaPeriodo") 335 | (ep.query() 336 | .parameters(moeda="USD", 337 | dataInicial="1/1/2022", 338 | dataFinalCotacao="1/5/2022") 339 | .collect()) 340 | 341 | Note que a primeira data é 2022-01-03, pois os primeiros dias do ano não são úteis. 342 | Podemos aplicar filtros nessa consulta utilizando o método ``filter``, da mesma forma que realizamos na consulta ao 343 | ``EntitySet``. 344 | 345 | .. ipython:: python 346 | 347 | (ep.query() 348 | .parameters(moeda="USD", 349 | dataInicial="1/1/2022", 350 | dataFinalCotacao="1/5/2022") 351 | .filter(ep.tipoBoletim == "Fechamento") 352 | .collect()) 353 | 354 | Obtendo o Texto da API 355 | ^^^^^^^^^^^^^^^^^^^^^^ 356 | 357 | Uma alternativa ao DataFrame retornado pela consulta, via o método ``collect``, é obter o texto, em formato JSON 358 | (padrão) ou XML, retornado pela consulta. 359 | 360 | O método ``collect`` faz o *parsing* do texto retornado na consulta e cria um DataFrame, o método ``text`` retorna 361 | esse texto bruto. 362 | 363 | Isso é útil para fazer o armazenamento de dados da API para a construção de bancos de dados ou *data lakes*. 364 | 365 | Para obter o conteúdo bruto, basta executar o método ``text`` ao invés do ``collect``, ao fim da cadeia da consulta. 366 | 367 | .. ipython:: python 368 | 369 | ep = em.get_endpoint('ExpectativasMercadoTop5Anuais') 370 | (ep.query() 371 | .select(ep.Indicador, ep.Data, ep.DataReferencia, ep.tipoCalculo, ep.Media) 372 | .orderby(ep.Data.desc()) 373 | .limit(5) 374 | .text()) 375 | 376 | O texto retornado está no formato JSON. 377 | Contudo, as APIs OData também retornam conteúdo em XML. 378 | Para isso incluímos o método ``format`` na cadeia da consulta e passamos como parâmetro o tipo desejado. 379 | 380 | .. ipython:: python 381 | 382 | ep = em.get_endpoint('ExpectativasMercadoTop5Anuais') 383 | (ep.query() 384 | .select(ep.Indicador, ep.Data, ep.DataReferencia, ep.tipoCalculo, ep.Media) 385 | .orderby(ep.Data.desc()) 386 | .format("xml") 387 | .limit(5) 388 | .text()) 389 | 390 | 391 | Classe ODataAPI 392 | --------------- 393 | 394 | O portal de Dados Abertos to Banco Central apresenta diversas APIs OData, são 395 | dezenas de APIs disponíveis. 396 | A URL com metadados de cada API pode ser obtida no `portal `_. 397 | A classe :py:class:`bcb.odata.api.ODataAPI` permite acessar qualquer API Odata de posse da sua URL. 398 | 399 | Por exemplo, a API de estatísticas de operações registradas no Selic tem a seguinte URL:: 400 | 401 | https://olinda.bcb.gov.br/olinda/servico/selic_operacoes/versao/v1/odata/ 402 | 403 | que pode ser obtida no portal de dados abertos no `link `_. 404 | 405 | Essa API pode ser diretamente acessada através da classe :py:class:`bcb.odata.api.ODataAPI`. 406 | 407 | .. ipython:: python 408 | 409 | from bcb import ODataAPI 410 | url = "https://olinda.bcb.gov.br/olinda/servico/selic_operacoes/versao/v1/odata/" 411 | service = ODataAPI(url) 412 | service.describe() 413 | 414 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | ipython 2 | pygments >= 2.7.* 3 | pydata-sphinx-theme 4 | sphinx == 6.* 5 | babel == 2.9 6 | docutils == 0.18.* 7 | packaging >= 21.* 8 | pandas 9 | pytz >= 2020.* 10 | lxml 11 | numpy 12 | matplotlib 13 | httpx 14 | requests >= 2.25.* 15 | furo -------------------------------------------------------------------------------- /docs/sgs.rst: -------------------------------------------------------------------------------- 1 | SGS 2 | === 3 | 4 | A função :py:func:`bcb.sgs.get` obtem os dados do webservice do Banco Central , 5 | interface json do serviço BCData/SGS - 6 | `Sistema Gerenciador de Séries Temporais (SGS) `_. 7 | 8 | Exemplos 9 | -------- 10 | 11 | .. ipython:: python 12 | 13 | from bcb import sgs 14 | import matplotlib.pyplot as plt 15 | import matplotlib as mpl 16 | mpl.style.use('bmh') 17 | 18 | df = sgs.get({'IPCA': 433}, start='2002-02-01') 19 | df.index = df.index.to_period('M') 20 | df.head() 21 | 22 | .. ipython:: python 23 | 24 | dfr = df.rolling(12) 25 | i12 = dfr.apply(lambda x: (1 + x/100).prod() - 1).dropna() * 100 26 | i12.head() 27 | 28 | .. ipython:: python 29 | 30 | i12.plot(figsize=(12,6)) 31 | plt.title('Fonte: https://dadosabertos.bcb.gov.br', fontsize=10) 32 | plt.suptitle('IPCA acumulado 12 meses - Janela Móvel', fontsize=18) 33 | plt.xlabel('Data') 34 | plt.ylabel('%') 35 | @savefig sgs1.png 36 | plt.legend().set_visible(False) 37 | 38 | 39 | Dados de Inadimplência de Operações de Crédito 40 | ============================================== 41 | 42 | .. ipython:: python 43 | 44 | from bcb.sgs.regional_economy import get_non_performing_loans 45 | from bcb.utils import BRAZILIAN_REGIONS, BRAZILIAN_STATES 46 | import pandas as pd 47 | get_non_performing_loans(["RR"], last=10, mode="all") 48 | 49 | .. ipython:: python 50 | 51 | northeast_states = BRAZILIAN_REGIONS["NE"] 52 | get_non_performing_loans(northeast_states, last=5, mode="pj") 53 | 54 | .. ipython:: python 55 | 56 | get_non_performing_loans(BRAZILIAN_STATES, mode="PF", start="2024-01-01") -------------------------------------------------------------------------------- /docs/taxajuros.rst: -------------------------------------------------------------------------------- 1 | Taxas de Juros 2 | ############## 3 | 4 | A API de taxas de juros de operações de crédito pode ser acessada através da 5 | classe :py:class:`bcb.TaxaJuros`. 6 | 7 | .. _documentacao: https://olinda.bcb.gov.br/olinda/servico/TaxaJuros/versao/v1/documentacao 8 | 9 | __ documentacao_ 10 | 11 | Os dados são obtidos a partir da `API de Taxas de Juros`__. 12 | 13 | 14 | Esta API tem os ``EntitySets``: 15 | 16 | .. ipython:: python 17 | 18 | from bcb import TaxaJuros 19 | em = TaxaJuros() 20 | em.describe() 21 | 22 | As características do ``EntitySets`` podem ser visualizadas por: 23 | 24 | .. ipython:: python 25 | 26 | em.describe("TaxasJurosDiariaPorInicioPeriodo") 27 | 28 | Vejamos um gráfico da mediana das taxas de juros do cheque especial praticada 29 | pelas instituições financeiras. 30 | 31 | .. ipython:: python 32 | 33 | import pandas as pd 34 | 35 | ep = em.get_endpoint('TaxasJurosDiariaPorInicioPeriodo') 36 | df_cheque = (ep.query() 37 | .filter(ep.Segmento == 'PESSOA FÍSICA', 38 | ep.Modalidade == 'Cheque especial - Pré-fixado') 39 | .collect()) 40 | grp = df_cheque.groupby('InicioPeriodo') 41 | df_mean = grp.agg({'TaxaJurosAoMes': 'median'}) 42 | 43 | @savefig taxajuros1.png 44 | df_mean['TaxaJurosAoMes'].plot(figsize=(16,6), style='o', markersize=1, 45 | xlabel='Data', ylabel='Taxa', 46 | title='Mediana das Taxas de Juros de Cheque Especial - Fonte:BCB'); 47 | 48 | -------------------------------------------------------------------------------- /notebooks/bcb_Expectativas_da_SELIC_(nova_API).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "id": "_9HSUl-wtcQp", 8 | "slideshow": { 9 | "slide_type": "slide" 10 | } 11 | }, 12 | "outputs": [], 13 | "source": [ 14 | "from bcb import Expectativas" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "metadata": { 21 | "cell_style": "center", 22 | "colab": { 23 | "base_uri": "https://localhost:8080/" 24 | }, 25 | "id": "bOIg0BAMt4Vk", 26 | "outputId": "2c8afe70-6e81-4e5a-a057-444a5f2668b5" 27 | }, 28 | "outputs": [ 29 | { 30 | "name": "stdout", 31 | "output_type": "stream", 32 | "text": [ 33 | "EntitySets:\n", 34 | " ExpectativasMercadoTop5Anuais\n", 35 | " ExpectativasMercadoInstituicoes\n", 36 | " ExpectativaMercadoMensais\n", 37 | " ExpectativasMercadoInflacao12Meses\n", 38 | " ExpectativasMercadoSelic\n", 39 | " ExpectativasMercadoTop5Selic\n", 40 | " ExpectativasMercadoTop5Mensais\n", 41 | " ExpectativasMercadoTrimestrais\n", 42 | " ExpectativasMercadoAnuais\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "em = Expectativas()\n", 48 | "em.describe()" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 3, 54 | "metadata": { 55 | "colab": { 56 | "base_uri": "https://localhost:8080/" 57 | }, 58 | "id": "hpU7tepNt-Np", 59 | "outputId": "e2b2f7f5-0b8e-43f0-a1c7-aae050d77990", 60 | "slideshow": { 61 | "slide_type": "slide" 62 | } 63 | }, 64 | "outputs": [ 65 | { 66 | "name": "stdout", 67 | "output_type": "stream", 68 | "text": [ 69 | "\n", 70 | "EntitySet (Endpoint): ExpectativasMercadoSelic\n", 71 | "EntityType: br.gov.bcb.olinda.servico.Expectativas.ExpectativaMercadoSelic\n", 72 | "Properties: Indicador, Data, Reuniao, Media, Mediana, DesvioPadrao, Minimo, Maximo, numeroRespondentes, baseCalculo\n" 73 | ] 74 | } 75 | ], 76 | "source": [ 77 | "em.describe('ExpectativasMercadoSelic')" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 4, 83 | "metadata": { 84 | "colab": { 85 | "base_uri": "https://localhost:8080/" 86 | }, 87 | "id": "A73OkUbLuPdK", 88 | "outputId": "f2b4091d-eead-465e-ac2c-49cbb277feb7" 89 | }, 90 | "outputs": [ 91 | { 92 | "name": "stdout", 93 | "output_type": "stream", 94 | "text": [ 95 | "\n", 96 | "EntitySet (Endpoint): ExpectativasMercadoTop5Selic\n", 97 | "EntityType: br.gov.bcb.olinda.servico.Expectativas.ExpectativasMercadoSelicTop5\n", 98 | "Properties: indicador, Data, reuniao, tipoCalculo, media, mediana, desvioPadrao, coeficienteVariacao, minimo, maximo\n" 99 | ] 100 | } 101 | ], 102 | "source": [ 103 | "em.describe('ExpectativasMercadoTop5Selic')" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 7, 109 | "metadata": { 110 | "colab": { 111 | "base_uri": "https://localhost:8080/", 112 | "height": 551 113 | }, 114 | "id": "QlwvnQIMv2nw", 115 | "outputId": "668f5dd9-cb98-43c9-e7f2-920ef5d149c8", 116 | "slideshow": { 117 | "slide_type": "slide" 118 | } 119 | }, 120 | "outputs": [ 121 | { 122 | "data": { 123 | "text/html": [ 124 | "
\n", 125 | "\n", 138 | "\n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | "
IndicadorDataReuniaoMediaMedianaDesvioPadraoMinimoMaximonumeroRespondentesbaseCalculo
0Selic2022-03-18R2/20248.56488.500.77767.0010.75270
1Selic2022-03-18R1/20248.63068.501.06615.5012.75940
2Selic2022-03-18R8/20239.01469.001.01085.5013.001170
3Selic2022-03-18R7/20239.41939.251.08726.0013.251150
4Selic2022-03-18R6/20239.84789.751.08636.5013.251150
5Selic2022-03-18R5/202310.379110.501.09037.0013.251150
6Selic2022-03-18R4/202311.010411.001.02008.0013.251150
7Selic2022-03-18R3/202311.600411.750.95899.0013.251150
8Selic2022-03-18R2/202312.183512.250.798410.0013.501150
9Selic2022-03-18R1/202312.593112.750.661910.0013.501170
10Selic2022-03-18R8/202212.880513.000.422811.5013.501250
11Selic2022-03-18R7/202212.923813.000.394811.0013.501230
12Selic2022-03-18R6/202212.942213.000.356911.5013.501230
13Selic2022-03-18R5/202212.944113.000.337412.0013.501230
14Selic2022-03-18R4/202212.929413.000.341311.7513.501230
15Selic2022-03-18R3/202212.617712.750.221511.7513.001230
\n", 365 | "
" 366 | ], 367 | "text/plain": [ 368 | " Indicador Data Reuniao Media Mediana DesvioPadrao Minimo \\\n", 369 | "0 Selic 2022-03-18 R2/2024 8.5648 8.50 0.7776 7.00 \n", 370 | "1 Selic 2022-03-18 R1/2024 8.6306 8.50 1.0661 5.50 \n", 371 | "2 Selic 2022-03-18 R8/2023 9.0146 9.00 1.0108 5.50 \n", 372 | "3 Selic 2022-03-18 R7/2023 9.4193 9.25 1.0872 6.00 \n", 373 | "4 Selic 2022-03-18 R6/2023 9.8478 9.75 1.0863 6.50 \n", 374 | "5 Selic 2022-03-18 R5/2023 10.3791 10.50 1.0903 7.00 \n", 375 | "6 Selic 2022-03-18 R4/2023 11.0104 11.00 1.0200 8.00 \n", 376 | "7 Selic 2022-03-18 R3/2023 11.6004 11.75 0.9589 9.00 \n", 377 | "8 Selic 2022-03-18 R2/2023 12.1835 12.25 0.7984 10.00 \n", 378 | "9 Selic 2022-03-18 R1/2023 12.5931 12.75 0.6619 10.00 \n", 379 | "10 Selic 2022-03-18 R8/2022 12.8805 13.00 0.4228 11.50 \n", 380 | "11 Selic 2022-03-18 R7/2022 12.9238 13.00 0.3948 11.00 \n", 381 | "12 Selic 2022-03-18 R6/2022 12.9422 13.00 0.3569 11.50 \n", 382 | "13 Selic 2022-03-18 R5/2022 12.9441 13.00 0.3374 12.00 \n", 383 | "14 Selic 2022-03-18 R4/2022 12.9294 13.00 0.3413 11.75 \n", 384 | "15 Selic 2022-03-18 R3/2022 12.6177 12.75 0.2215 11.75 \n", 385 | "\n", 386 | " Maximo numeroRespondentes baseCalculo \n", 387 | "0 10.75 27 0 \n", 388 | "1 12.75 94 0 \n", 389 | "2 13.00 117 0 \n", 390 | "3 13.25 115 0 \n", 391 | "4 13.25 115 0 \n", 392 | "5 13.25 115 0 \n", 393 | "6 13.25 115 0 \n", 394 | "7 13.25 115 0 \n", 395 | "8 13.50 115 0 \n", 396 | "9 13.50 117 0 \n", 397 | "10 13.50 125 0 \n", 398 | "11 13.50 123 0 \n", 399 | "12 13.50 123 0 \n", 400 | "13 13.50 123 0 \n", 401 | "14 13.50 123 0 \n", 402 | "15 13.00 123 0 " 403 | ] 404 | }, 405 | "execution_count": 7, 406 | "metadata": {}, 407 | "output_type": "execute_result" 408 | } 409 | ], 410 | "source": [ 411 | "ep = em.get_endpoint('ExpectativasMercadoSelic')\n", 412 | "ep.query().filter(ep.baseCalculo == 0, ep.Data == '2022-03-18').collect()" 413 | ] 414 | } 415 | ], 416 | "metadata": { 417 | "celltoolbar": "Slideshow", 418 | "colab": { 419 | "name": "bcb - Expectativas da SELIC (nova API).ipynb", 420 | "provenance": [] 421 | }, 422 | "kernelspec": { 423 | "display_name": "Python 3", 424 | "language": "python", 425 | "name": "python3" 426 | }, 427 | "language_info": { 428 | "codemirror_mode": { 429 | "name": "ipython", 430 | "version": 3 431 | }, 432 | "file_extension": ".py", 433 | "mimetype": "text/x-python", 434 | "name": "python", 435 | "nbconvert_exporter": "python", 436 | "pygments_lexer": "ipython3", 437 | "version": "3.7.11" 438 | } 439 | }, 440 | "nbformat": 4, 441 | "nbformat_minor": 1 442 | } 443 | -------------------------------------------------------------------------------- /notebooks/currency PTAX.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 12, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import sys\n", 10 | "sys.path.append('..')\n", 11 | "import pandas as pd\n", 12 | "from bcb import PTAX" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 13, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "ptax = PTAX()" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 14, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "name": "stdout", 31 | "output_type": "stream", 32 | "text": [ 33 | "EntitySets:\n", 34 | " Moedas\n", 35 | "FunctionImports:\n", 36 | " CotacaoMoedaPeriodoFechamento\n", 37 | " CotacaoMoedaAberturaOuIntermediario\n", 38 | " CotacaoMoedaDia\n", 39 | " CotacaoMoedaPeriodo\n", 40 | " CotacaoDolarDia\n", 41 | " CotacaoDolarPeriodo\n" 42 | ] 43 | } 44 | ], 45 | "source": [ 46 | "ptax.describe()" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 15, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "data": { 56 | "text/html": [ 57 | "
\n", 58 | "\n", 71 | "\n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | "
simbolonomeFormatadotipoMoeda
0AUDDólar australianoB
1CADDólar canadenseA
2CHFFranco suíçoA
3DKKCoroa dinamarquesaA
4EUREuroB
5GBPLibra EsterlinaB
6JPYIeneA
7NOKCoroa norueguesaA
8SEKCoroa suecaA
9USDDólar dos Estados UnidosA
\n", 143 | "
" 144 | ], 145 | "text/plain": [ 146 | " simbolo nomeFormatado tipoMoeda\n", 147 | "0 AUD Dólar australiano B\n", 148 | "1 CAD Dólar canadense A\n", 149 | "2 CHF Franco suíço A\n", 150 | "3 DKK Coroa dinamarquesa A\n", 151 | "4 EUR Euro B\n", 152 | "5 GBP Libra Esterlina B\n", 153 | "6 JPY Iene A\n", 154 | "7 NOK Coroa norueguesa A\n", 155 | "8 SEK Coroa sueca A\n", 156 | "9 USD Dólar dos Estados Unidos A" 157 | ] 158 | }, 159 | "execution_count": 15, 160 | "metadata": {}, 161 | "output_type": "execute_result" 162 | } 163 | ], 164 | "source": [ 165 | "ep = ptax.get_endpoint('Moedas')\n", 166 | "ep.query().limit(10).collect()" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": 16, 172 | "metadata": {}, 173 | "outputs": [ 174 | { 175 | "name": "stdout", 176 | "output_type": "stream", 177 | "text": [ 178 | "\n", 179 | "Function: CotacaoDolarDia\n", 180 | "Parameters: dataCotacao \n", 181 | "EntitySet: _CotacaoDolarDia\n", 182 | "EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoDolar\n", 183 | "Properties: cotacaoCompra , cotacaoVenda , dataHoraCotacao \n" 184 | ] 185 | } 186 | ], 187 | "source": [ 188 | "ptax.describe('CotacaoDolarDia')" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 17, 194 | "metadata": {}, 195 | "outputs": [ 196 | { 197 | "data": { 198 | "text/html": [ 199 | "
\n", 200 | "\n", 213 | "\n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | "
cotacaoCompracotacaoVendadataHoraCotacao
05.11775.11832022-09-12 13:04:46.736
\n", 231 | "
" 232 | ], 233 | "text/plain": [ 234 | " cotacaoCompra cotacaoVenda dataHoraCotacao\n", 235 | "0 5.1177 5.1183 2022-09-12 13:04:46.736" 236 | ] 237 | }, 238 | "execution_count": 17, 239 | "metadata": {}, 240 | "output_type": "execute_result" 241 | } 242 | ], 243 | "source": [ 244 | "ep = ptax.get_endpoint('CotacaoDolarDia')\n", 245 | "ep.query().parameters(dataCotacao='9/12/2022').collect()" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 18, 251 | "metadata": {}, 252 | "outputs": [ 253 | { 254 | "name": "stdout", 255 | "output_type": "stream", 256 | "text": [ 257 | "\n", 258 | "Function: CotacaoMoedaPeriodo\n", 259 | "Parameters: moeda , dataInicial , dataFinalCotacao \n", 260 | "EntitySet: _CotacaoMoedaPeriodo\n", 261 | "EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoMoeda\n", 262 | "Properties: paridadeCompra , paridadeVenda , cotacaoCompra , cotacaoVenda , dataHoraCotacao , tipoBoletim \n" 263 | ] 264 | } 265 | ], 266 | "source": [ 267 | "ptax.describe('CotacaoMoedaPeriodo')" 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 19, 273 | "metadata": {}, 274 | "outputs": [ 275 | { 276 | "data": { 277 | "text/html": [ 278 | "
\n", 279 | "\n", 292 | "\n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | "
paridadeCompraparidadeVendacotacaoCompracotacaoVendadataHoraCotacaotipoBoletim
00.72430.72444.04774.04872022-01-03 10:04:22.186Abertura
10.72210.72234.06124.06282022-01-03 11:11:42.883Intermediário
20.71970.71984.06234.06332022-01-03 12:09:19.760Intermediário
30.71860.71884.07044.07192022-01-03 13:11:50.353Intermediário
40.71860.71884.04594.04752022-01-03 13:11:50.357Fechamento
50.71880.71894.09014.09112022-01-04 10:05:22.015Abertura
60.72080.72094.10964.11062022-01-04 11:05:20.148Intermediário
70.72170.72194.07674.07822022-01-04 12:10:19.466Intermediário
80.72460.72484.10664.10822022-01-04 13:08:59.118Intermediário
90.72460.72484.11364.11512022-01-04 13:08:59.123Fechamento
100.72500.72514.11554.11652022-01-05 10:06:19.404Abertura
110.72580.72594.11254.11352022-01-05 11:06:19.009Intermediário
120.72640.72664.10114.10272022-01-05 12:03:19.428Intermediário
130.72700.72714.11494.11592022-01-05 13:07:53.088Intermediário
140.72700.72714.11644.11742022-01-05 13:07:53.094Fechamento
\n", 442 | "
" 443 | ], 444 | "text/plain": [ 445 | " paridadeCompra paridadeVenda cotacaoCompra cotacaoVenda \\\n", 446 | "0 0.7243 0.7244 4.0477 4.0487 \n", 447 | "1 0.7221 0.7223 4.0612 4.0628 \n", 448 | "2 0.7197 0.7198 4.0623 4.0633 \n", 449 | "3 0.7186 0.7188 4.0704 4.0719 \n", 450 | "4 0.7186 0.7188 4.0459 4.0475 \n", 451 | "5 0.7188 0.7189 4.0901 4.0911 \n", 452 | "6 0.7208 0.7209 4.1096 4.1106 \n", 453 | "7 0.7217 0.7219 4.0767 4.0782 \n", 454 | "8 0.7246 0.7248 4.1066 4.1082 \n", 455 | "9 0.7246 0.7248 4.1136 4.1151 \n", 456 | "10 0.7250 0.7251 4.1155 4.1165 \n", 457 | "11 0.7258 0.7259 4.1125 4.1135 \n", 458 | "12 0.7264 0.7266 4.1011 4.1027 \n", 459 | "13 0.7270 0.7271 4.1149 4.1159 \n", 460 | "14 0.7270 0.7271 4.1164 4.1174 \n", 461 | "\n", 462 | " dataHoraCotacao tipoBoletim \n", 463 | "0 2022-01-03 10:04:22.186 Abertura \n", 464 | "1 2022-01-03 11:11:42.883 Intermediário \n", 465 | "2 2022-01-03 12:09:19.760 Intermediário \n", 466 | "3 2022-01-03 13:11:50.353 Intermediário \n", 467 | "4 2022-01-03 13:11:50.357 Fechamento \n", 468 | "5 2022-01-04 10:05:22.015 Abertura \n", 469 | "6 2022-01-04 11:05:20.148 Intermediário \n", 470 | "7 2022-01-04 12:10:19.466 Intermediário \n", 471 | "8 2022-01-04 13:08:59.118 Intermediário \n", 472 | "9 2022-01-04 13:08:59.123 Fechamento \n", 473 | "10 2022-01-05 10:06:19.404 Abertura \n", 474 | "11 2022-01-05 11:06:19.009 Intermediário \n", 475 | "12 2022-01-05 12:03:19.428 Intermediário \n", 476 | "13 2022-01-05 13:07:53.088 Intermediário \n", 477 | "14 2022-01-05 13:07:53.094 Fechamento " 478 | ] 479 | }, 480 | "execution_count": 19, 481 | "metadata": {}, 482 | "output_type": "execute_result" 483 | } 484 | ], 485 | "source": [ 486 | "ep = ptax.get_endpoint('CotacaoMoedaPeriodo')\n", 487 | "ep.query().parameters(moeda='AUD', dataInicial='1/1/2022', dataFinalCotacao='1/5/2022').collect()" 488 | ] 489 | }, 490 | { 491 | "cell_type": "code", 492 | "execution_count": 20, 493 | "metadata": {}, 494 | "outputs": [ 495 | { 496 | "name": "stdout", 497 | "output_type": "stream", 498 | "text": [ 499 | "\n", 500 | "Function: CotacaoMoedaDia\n", 501 | "Parameters: moeda , dataCotacao \n", 502 | "EntitySet: _CotacaoMoedaDia\n", 503 | "EntityType: br.gov.bcb.olinda.servico.PTAX.TipoCotacaoMoeda\n", 504 | "Properties: paridadeCompra , paridadeVenda , cotacaoCompra , cotacaoVenda , dataHoraCotacao , tipoBoletim \n" 505 | ] 506 | } 507 | ], 508 | "source": [ 509 | "ptax.describe('CotacaoMoedaDia')" 510 | ] 511 | }, 512 | { 513 | "cell_type": "code", 514 | "execution_count": 21, 515 | "metadata": {}, 516 | "outputs": [ 517 | { 518 | "data": { 519 | "text/html": [ 520 | "
\n", 521 | "\n", 534 | "\n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | " \n", 577 | " \n", 578 | " \n", 579 | " \n", 580 | " \n", 581 | " \n", 582 | " \n", 583 | " \n", 584 | " \n", 585 | " \n", 586 | " \n", 587 | " \n", 588 | " \n", 589 | " \n", 590 | " \n", 591 | " \n", 592 | " \n", 593 | "
paridadeCompraparidadeVendacotacaoCompracotacaoVendadataHoraCotacaotipoBoletim
00.70510.70533.80013.80162022-01-31 10:11:20.549Abertura
10.70680.70703.79113.79262022-01-31 11:04:17.576Intermediário
20.70660.70683.79203.79352022-01-31 12:02:19.723Intermediário
30.70510.70523.74223.74322022-01-31 13:07:02.500Intermediário
40.70510.70523.77713.77802022-01-31 13:07:02.511Fechamento PTAX
\n", 594 | "
" 595 | ], 596 | "text/plain": [ 597 | " paridadeCompra paridadeVenda cotacaoCompra cotacaoVenda \\\n", 598 | "0 0.7051 0.7053 3.8001 3.8016 \n", 599 | "1 0.7068 0.7070 3.7911 3.7926 \n", 600 | "2 0.7066 0.7068 3.7920 3.7935 \n", 601 | "3 0.7051 0.7052 3.7422 3.7432 \n", 602 | "4 0.7051 0.7052 3.7771 3.7780 \n", 603 | "\n", 604 | " dataHoraCotacao tipoBoletim \n", 605 | "0 2022-01-31 10:11:20.549 Abertura \n", 606 | "1 2022-01-31 11:04:17.576 Intermediário \n", 607 | "2 2022-01-31 12:02:19.723 Intermediário \n", 608 | "3 2022-01-31 13:07:02.500 Intermediário \n", 609 | "4 2022-01-31 13:07:02.511 Fechamento PTAX " 610 | ] 611 | }, 612 | "execution_count": 21, 613 | "metadata": {}, 614 | "output_type": "execute_result" 615 | } 616 | ], 617 | "source": [ 618 | "ep = ptax.get_endpoint('CotacaoMoedaDia')\n", 619 | "ep.query().parameters(moeda='AUD', dataCotacao='1/31/2022').collect()" 620 | ] 621 | }, 622 | { 623 | "cell_type": "code", 624 | "execution_count": null, 625 | "metadata": {}, 626 | "outputs": [], 627 | "source": [] 628 | } 629 | ], 630 | "metadata": { 631 | "kernelspec": { 632 | "display_name": "Python 3.8.13 ('python-bcb-fnNEZeeT-py3.8')", 633 | "language": "python", 634 | "name": "python3" 635 | }, 636 | "language_info": { 637 | "codemirror_mode": { 638 | "name": "ipython", 639 | "version": 3 640 | }, 641 | "file_extension": ".py", 642 | "mimetype": "text/x-python", 643 | "name": "python", 644 | "nbconvert_exporter": "python", 645 | "pygments_lexer": "ipython3", 646 | "version": "3.8.13" 647 | }, 648 | "orig_nbformat": 4, 649 | "vscode": { 650 | "interpreter": { 651 | "hash": "f35dbda34a25025166348a7c894c748e62490c9bfe629a53156239e0b7b9ad50" 652 | } 653 | } 654 | }, 655 | "nbformat": 4, 656 | "nbformat_minor": 2 657 | } 658 | -------------------------------------------------------------------------------- /notebooks/odata ODataAPI.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "%load_ext autoreload\n", 10 | "%autoreload 2" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 2, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "import pandas as pd" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 3, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "import sys\n", 29 | "sys.path.insert(0, '..')\n", 30 | "from bcb import ODataAPI" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 9, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "name": "stdout", 40 | "output_type": "stream", 41 | "text": [ 42 | "EntitySets:\n", 43 | " DatasOperacoesSelic\n", 44 | "FunctionImports:\n", 45 | " OperacoesEmUmAno\n", 46 | " OperacoesEmUmaData\n" 47 | ] 48 | } 49 | ], 50 | "source": [ 51 | "url = \"https://olinda.bcb.gov.br/olinda/servico/selic_operacoes/versao/v1/odata/\"\n", 52 | "service = ODataAPI(url)\n", 53 | "service.describe()" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 6, 59 | "metadata": {}, 60 | "outputs": [ 61 | { 62 | "name": "stdout", 63 | "output_type": "stream", 64 | "text": [ 65 | "\n", 66 | "EntitySet (Endpoint): Selic\n", 67 | "EntityType: br.gov.bcb.olinda.servico.ResumoCamaras_pt.ResumoMensalSelic\n", 68 | "Properties: mes, valorOperacoes, quantidadeOperacoes\n" 69 | ] 70 | } 71 | ], 72 | "source": [ 73 | "service.describe(\"Selic\")" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 7, 79 | "metadata": {}, 80 | "outputs": [ 81 | { 82 | "data": { 83 | "text/html": [ 84 | "
\n", 85 | "\n", 98 | "\n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | "
mesvalorOperacoesquantidadeOperacoes
0abr/2002776971794
1mai/20021054042276
2jun/20021107952307
3jul/20021248202322
4ago/20021414382423
5set/20021863512504
6out/20022056482715
7nov/20022448372969
8dez/20022570062837
9jan/20032499452907
\n", 170 | "
" 171 | ], 172 | "text/plain": [ 173 | " mes valorOperacoes quantidadeOperacoes\n", 174 | "0 abr/2002 77697 1794\n", 175 | "1 mai/2002 105404 2276\n", 176 | "2 jun/2002 110795 2307\n", 177 | "3 jul/2002 124820 2322\n", 178 | "4 ago/2002 141438 2423\n", 179 | "5 set/2002 186351 2504\n", 180 | "6 out/2002 205648 2715\n", 181 | "7 nov/2002 244837 2969\n", 182 | "8 dez/2002 257006 2837\n", 183 | "9 jan/2003 249945 2907" 184 | ] 185 | }, 186 | "execution_count": 7, 187 | "metadata": {}, 188 | "output_type": "execute_result" 189 | } 190 | ], 191 | "source": [ 192 | "ep = service.get_endpoint('Selic')\n", 193 | "ep.query().limit(10).collect()" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": 23, 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "df = ep.query().filter(ep.anoMes >= \"2020-00\").collect()" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 28, 208 | "metadata": {}, 209 | "outputs": [ 210 | { 211 | "data": { 212 | "text/html": [ 213 | "
\n", 214 | "\n", 227 | "\n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | "
TaxaJurosAoAno
Modalidade
FINANCIAMENTO IMOBILIÁRIO COM TAXAS DE MERCADO - PRÉ-FIXADO13.860
FINANCIAMENTO IMOBILIÁRIO COM TAXAS DE MERCADO - PÓS-FIXADO REFERENCIADO EM IPCA9.310
FINANCIAMENTO IMOBILIÁRIO COM TAXAS DE MERCADO - PÓS-FIXADO REFERENCIADO EM TR7.740
FINANCIAMENTO IMOBILIÁRIO COM TAXAS REGULADAS - PRÉ-FIXADO9.415
FINANCIAMENTO IMOBILIÁRIO COM TAXAS REGULADAS - PÓS-FIXADO REFERENCIADO EM IPCA4.490
FINANCIAMENTO IMOBILIÁRIO COM TAXAS REGULADAS - PÓS-FIXADO REFERENCIADO EM TR7.400
\n", 265 | "
" 266 | ], 267 | "text/plain": [ 268 | " TaxaJurosAoAno\n", 269 | "Modalidade \n", 270 | "FINANCIAMENTO IMOBILIÁRIO COM TAXAS DE MERCADO ... 13.860\n", 271 | "FINANCIAMENTO IMOBILIÁRIO COM TAXAS DE MERCADO ... 9.310\n", 272 | "FINANCIAMENTO IMOBILIÁRIO COM TAXAS DE MERCADO ... 7.740\n", 273 | "FINANCIAMENTO IMOBILIÁRIO COM TAXAS REGULADAS -... 9.415\n", 274 | "FINANCIAMENTO IMOBILIÁRIO COM TAXAS REGULADAS -... 4.490\n", 275 | "FINANCIAMENTO IMOBILIÁRIO COM TAXAS REGULADAS -... 7.400" 276 | ] 277 | }, 278 | "execution_count": 28, 279 | "metadata": {}, 280 | "output_type": "execute_result" 281 | } 282 | ], 283 | "source": [ 284 | "df.groupby(\"Modalidade\").agg({\"TaxaJurosAoAno\": \"median\"})" 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": 26, 290 | "metadata": {}, 291 | "outputs": [ 292 | { 293 | "data": { 294 | "text/html": [ 295 | "
\n", 296 | "\n", 309 | "\n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | "
TaxaJurosAoAno
ModalidadeanoMes
FINANCIAMENTO IMOBILIÁRIO COM TAXAS DE MERCADO - PRÉ-FIXADO2020-0114.485
2020-0214.120
2020-0314.145
2020-0413.950
2020-0515.210
.........
FINANCIAMENTO IMOBILIÁRIO COM TAXAS REGULADAS - PÓS-FIXADO REFERENCIADO EM TR2022-038.065
2022-048.020
2022-058.390
2022-068.340
2022-078.450
\n", 372 | "

183 rows × 1 columns

\n", 373 | "
" 374 | ], 375 | "text/plain": [ 376 | " TaxaJurosAoAno\n", 377 | "Modalidade anoMes \n", 378 | "FINANCIAMENTO IMOBILIÁRIO COM TAXAS DE MERCADO ... 2020-01 14.485\n", 379 | " 2020-02 14.120\n", 380 | " 2020-03 14.145\n", 381 | " 2020-04 13.950\n", 382 | " 2020-05 15.210\n", 383 | "... ...\n", 384 | "FINANCIAMENTO IMOBILIÁRIO COM TAXAS REGULADAS -... 2022-03 8.065\n", 385 | " 2022-04 8.020\n", 386 | " 2022-05 8.390\n", 387 | " 2022-06 8.340\n", 388 | " 2022-07 8.450\n", 389 | "\n", 390 | "[183 rows x 1 columns]" 391 | ] 392 | }, 393 | "execution_count": 26, 394 | "metadata": {}, 395 | "output_type": "execute_result" 396 | } 397 | ], 398 | "source": [ 399 | "df.groupby([\"Modalidade\", \"anoMes\"]).agg({\"TaxaJurosAoAno\": \"median\"})" 400 | ] 401 | }, 402 | { 403 | "cell_type": "code", 404 | "execution_count": 8, 405 | "metadata": {}, 406 | "outputs": [ 407 | { 408 | "name": "stdout", 409 | "output_type": "stream", 410 | "text": [ 411 | "\n", 412 | "EntitySet (Endpoint): TaxasJurosDiariaPorInicioPeriodo\n", 413 | "EntityType: br.gov.bcb.olinda.servico.taxaJuros.TaxaJurosDiaria\n", 414 | "Properties: InicioPeriodo, FimPeriodo, Segmento, Modalidade, Posicao, InstituicaoFinanceira, TaxaJurosAoMes, TaxaJurosAoAno, cnpj8\n" 415 | ] 416 | } 417 | ], 418 | "source": [ 419 | "service.describe(\"TaxasJurosDiariaPorInicioPeriodo\")" 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": 9, 425 | "metadata": {}, 426 | "outputs": [ 427 | { 428 | "data": { 429 | "text/html": [ 430 | "
\n", 431 | "\n", 444 | "\n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | " \n", 449 | " \n", 450 | " \n", 451 | " \n", 452 | " \n", 453 | " \n", 454 | " \n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | " \n", 461 | " \n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | " \n", 481 | " \n", 482 | " \n", 483 | " \n", 484 | " \n", 485 | " \n", 486 | " \n", 487 | " \n", 488 | " \n", 489 | " \n", 490 | " \n", 491 | " \n", 492 | " \n", 493 | " \n", 494 | " \n", 495 | " \n", 496 | " \n", 497 | " \n", 498 | " \n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | " \n", 528 | " \n", 529 | " \n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | " \n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | " \n", 577 | " \n", 578 | " \n", 579 | " \n", 580 | " \n", 581 | "
InicioPeriodoFimPeriodoSegmentoModalidadePosicaoInstituicaoFinanceiraTaxaJurosAoMesTaxaJurosAoAnocnpj8
02022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...1BCO SOCIETE GENERALE BRASIL0.000.0061533584
12022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...2ITAÚ UNIBANCO S.A.0.101.2660701190
22022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...3BCO MIZUHO S.A.0.283.3561088183
32022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...4BCO RABOBANK INTL BRASIL S.A.0.313.7401023570
42022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...5BCO DA CHINA BRASIL S.A.0.313.8210690848
52022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...6BCO MUFG BRASIL S.A.0.323.9660498557
62022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...7BCO DO BRASIL S.A.0.344.2100000000
72022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...8BCO BNP PARIBAS BRASIL S A0.374.4701522368
82022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...9SCOTIABANK BRASIL0.374.4829030467
92022-08-192022-08-25PESSOA JURÍDICAADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -...10BCO SUMITOMO MITSUI BRASIL S.A.0.404.8760518222
\n", 582 | "
" 583 | ], 584 | "text/plain": [ 585 | " InicioPeriodo FimPeriodo Segmento \\\n", 586 | "0 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 587 | "1 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 588 | "2 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 589 | "3 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 590 | "4 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 591 | "5 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 592 | "6 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 593 | "7 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 594 | "8 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 595 | "9 2022-08-19 2022-08-25 PESSOA JURÍDICA \n", 596 | "\n", 597 | " Modalidade Posicao \\\n", 598 | "0 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 1 \n", 599 | "1 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 2 \n", 600 | "2 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 3 \n", 601 | "3 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 4 \n", 602 | "4 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 5 \n", 603 | "5 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 6 \n", 604 | "6 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 7 \n", 605 | "7 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 8 \n", 606 | "8 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 9 \n", 607 | "9 ADIANTAMENTO SOBRE CONTRATOS DE CÂMBIO (ACC) -... 10 \n", 608 | "\n", 609 | " InstituicaoFinanceira TaxaJurosAoMes TaxaJurosAoAno cnpj8 \n", 610 | "0 BCO SOCIETE GENERALE BRASIL 0.00 0.00 61533584 \n", 611 | "1 ITAÚ UNIBANCO S.A. 0.10 1.26 60701190 \n", 612 | "2 BCO MIZUHO S.A. 0.28 3.35 61088183 \n", 613 | "3 BCO RABOBANK INTL BRASIL S.A. 0.31 3.74 01023570 \n", 614 | "4 BCO DA CHINA BRASIL S.A. 0.31 3.82 10690848 \n", 615 | "5 BCO MUFG BRASIL S.A. 0.32 3.96 60498557 \n", 616 | "6 BCO DO BRASIL S.A. 0.34 4.21 00000000 \n", 617 | "7 BCO BNP PARIBAS BRASIL S A 0.37 4.47 01522368 \n", 618 | "8 SCOTIABANK BRASIL 0.37 4.48 29030467 \n", 619 | "9 BCO SUMITOMO MITSUI BRASIL S.A. 0.40 4.87 60518222 " 620 | ] 621 | }, 622 | "execution_count": 9, 623 | "metadata": {}, 624 | "output_type": "execute_result" 625 | } 626 | ], 627 | "source": [ 628 | "ep = service.get_endpoint(\"TaxasJurosDiariaPorInicioPeriodo\")\n", 629 | "ep.query().limit(10).collect()" 630 | ] 631 | }, 632 | { 633 | "cell_type": "code", 634 | "execution_count": null, 635 | "metadata": {}, 636 | "outputs": [], 637 | "source": [] 638 | } 639 | ], 640 | "metadata": { 641 | "kernelspec": { 642 | "display_name": "Python 3.8.13 ('python-bcb-fnNEZeeT-py3.8')", 643 | "language": "python", 644 | "name": "python3" 645 | }, 646 | "language_info": { 647 | "codemirror_mode": { 648 | "name": "ipython", 649 | "version": 3 650 | }, 651 | "file_extension": ".py", 652 | "mimetype": "text/x-python", 653 | "name": "python", 654 | "nbconvert_exporter": "python", 655 | "pygments_lexer": "ipython3", 656 | "version": "3.8.13" 657 | }, 658 | "orig_nbformat": 4, 659 | "vscode": { 660 | "interpreter": { 661 | "hash": "f35dbda34a25025166348a7c894c748e62490c9bfe629a53156239e0b7b9ad50" 662 | } 663 | } 664 | }, 665 | "nbformat": 4, 666 | "nbformat_minor": 2 667 | } 668 | -------------------------------------------------------------------------------- /notebooks/pix.odata: -------------------------------------------------------------------------------- 1 | https://olinda.bcb.gov.br/olinda/servico/SPI/versao/v1/odata/PixLiquidadosAtual?$filter=Data gt 2023-01-01 -------------------------------------------------------------------------------- /notebooks/sgs get series with join.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "knowing-register", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import sys\n", 11 | "sys.path.append('..')\n", 12 | "from datetime import datetime\n", 13 | "import pandas as pd\n", 14 | "from bcb import sgs" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "id": "polyphonic-bicycle", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "df = sgs.get({'IPCA': 433, 'IGPM': 189}, start='2002-01-01', end='2021-01-01', multi=True)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 3, 30 | "id": "dependent-player", 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "data": { 35 | "text/html": [ 36 | "
\n", 37 | "\n", 50 | "\n", 51 | " \n", 52 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | "
IPCAIGPM
Date
2002-01-010.520.36
2002-02-010.360.06
2002-03-010.600.09
2002-04-010.800.56
2002-05-010.210.83
.........
2020-09-010.644.34
2020-10-010.863.23
2020-11-010.893.28
2020-12-011.350.96
2021-01-010.252.58
\n", 121 | "

229 rows × 2 columns

\n", 122 | "
" 123 | ], 124 | "text/plain": [ 125 | " IPCA IGPM\n", 126 | "Date \n", 127 | "2002-01-01 0.52 0.36\n", 128 | "2002-02-01 0.36 0.06\n", 129 | "2002-03-01 0.60 0.09\n", 130 | "2002-04-01 0.80 0.56\n", 131 | "2002-05-01 0.21 0.83\n", 132 | "... ... ...\n", 133 | "2020-09-01 0.64 4.34\n", 134 | "2020-10-01 0.86 3.23\n", 135 | "2020-11-01 0.89 3.28\n", 136 | "2020-12-01 1.35 0.96\n", 137 | "2021-01-01 0.25 2.58\n", 138 | "\n", 139 | "[229 rows x 2 columns]" 140 | ] 141 | }, 142 | "execution_count": 3, 143 | "metadata": {}, 144 | "output_type": "execute_result" 145 | } 146 | ], 147 | "source": [ 148 | "df" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "id": "amateur-runner", 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [] 158 | } 159 | ], 160 | "metadata": { 161 | "kernelspec": { 162 | "display_name": "Python 3", 163 | "language": "python", 164 | "name": "python3" 165 | }, 166 | "language_info": { 167 | "codemirror_mode": { 168 | "name": "ipython", 169 | "version": 3 170 | }, 171 | "file_extension": ".py", 172 | "mimetype": "text/x-python", 173 | "name": "python", 174 | "nbconvert_exporter": "python", 175 | "pygments_lexer": "ipython3", 176 | "version": "3.7.6" 177 | } 178 | }, 179 | "nbformat": 4, 180 | "nbformat_minor": 5 181 | } 182 | -------------------------------------------------------------------------------- /notebooks/sgs get series with period index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "addressed-representation", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import sys\n", 11 | "sys.path.insert(0, '..')\n", 12 | "from datetime import datetime\n", 13 | "import pandas as pd\n", 14 | "from bcb import sgs" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "id": "fatty-regulation", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "df = sgs.get({'IPCA': 433}, last=5, freq='M')" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 4, 30 | "id": "interstate-offer", 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "data": { 35 | "text/html": [ 36 | "
\n", 37 | "\n", 50 | "\n", 51 | " \n", 52 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | "
IPCA
Date
2021-070.96
2021-080.87
2021-091.16
2021-101.25
2021-110.95
\n", 84 | "
" 85 | ], 86 | "text/plain": [ 87 | " IPCA\n", 88 | "Date \n", 89 | "2021-07 0.96\n", 90 | "2021-08 0.87\n", 91 | "2021-09 1.16\n", 92 | "2021-10 1.25\n", 93 | "2021-11 0.95" 94 | ] 95 | }, 96 | "execution_count": 4, 97 | "metadata": {}, 98 | "output_type": "execute_result" 99 | } 100 | ], 101 | "source": [ 102 | "df" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "id": "6516a1b4", 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [] 112 | } 113 | ], 114 | "metadata": { 115 | "kernelspec": { 116 | "display_name": "Python 3", 117 | "language": "python", 118 | "name": "python3" 119 | }, 120 | "language_info": { 121 | "codemirror_mode": { 122 | "name": "ipython", 123 | "version": 3 124 | }, 125 | "file_extension": ".py", 126 | "mimetype": "text/x-python", 127 | "name": "python", 128 | "nbconvert_exporter": "python", 129 | "pygments_lexer": "ipython3", 130 | "version": "3.7.6" 131 | } 132 | }, 133 | "nbformat": 4, 134 | "nbformat_minor": 5 135 | } 136 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "python-bcb" 3 | version = "0.3.3" 4 | description = "" 5 | authors = ["wilsonfreitas "] 6 | readme = "README.md" 7 | packages = [{ include = "bcb" }] 8 | 9 | [tool.poetry.dependencies] 10 | python = ">= 3.10" 11 | httpx = ">= 0.24.0" 12 | lxml = ">= 4.9.2" 13 | pandas = ">= 2.0.0" 14 | requests = ">= 2.31.0" 15 | 16 | [tool.poetry.group.test.dependencies] 17 | pytest = ">= 7.1.3" 18 | flaky = ">= 3.7.0" 19 | 20 | [tool.poetry.group.docs.dependencies] 21 | Sphinx = "^6" 22 | pydata-sphinx-theme = "^0.16" 23 | matplotlib = ">= 3.5.3" 24 | ipython = ">= 8.14.0" 25 | furo = "^2024" 26 | pickleshare = "^0.7.5" 27 | pygments = "^2.7" 28 | 29 | [tool.poetry.group.dev.dependencies] 30 | pycodestyle = ">= 2.9.1" 31 | ipykernel = ">= 6.15.2" 32 | black = { version = ">= 22.8.0", allow-prereleases = true } 33 | jupyter = "^1.1.1" 34 | 35 | [build-system] 36 | requires = ["poetry-core"] 37 | build-backend = "poetry.core.masonry.api" 38 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | lxml 2 | pandas 3 | numpy 4 | requests 5 | httpx -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = python-bcb 3 | version = 0.1.7 4 | author = Wilson Freitas 5 | author_email = wilsonfreitas@gmail.com 6 | description = Python interface to Brazilian Central Bank web services 7 | long_description = file: README.md 8 | long_description_content_type = text/markdown 9 | url = https://github.com/wilsonfreitas/python-bcb 10 | project_urls = 11 | Bug Tracker = https://github.com/wilsonfreitas/python-bcb/issues 12 | classifiers = 13 | Programming Language :: Python :: 3 14 | License :: OSI Approved :: MIT License 15 | Operating System :: OS Independent 16 | 17 | [options] 18 | packages = find: 19 | install_requires = 20 | httpx 21 | python_requires = >=3.6 22 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wilsonfreitas/python-bcb/740551b5a78b50fa72c86a063ddf91c4556fd331/tests/__init__.py -------------------------------------------------------------------------------- /tests/sgs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wilsonfreitas/python-bcb/740551b5a78b50fa72c86a063ddf91c4556fd331/tests/sgs/__init__.py -------------------------------------------------------------------------------- /tests/sgs/test_regional_economy.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pytest 3 | from bcb.sgs.regional_economy import get_non_performing_loans, get_non_performing_loans_codes 4 | from bcb.utils import BRAZILIAN_REGIONS, BRAZILIAN_STATES 5 | from bcb.sgs import regional_economy 6 | 7 | 8 | class TestGetNonPerformingLoansCodes: 9 | @pytest.mark.parametrize("states,expected_codes", [ 10 | (["ba", "pa"], {"BA": "15929", "PA": "15938"}), 11 | (["BA"], {"BA": "15929"}), 12 | ("N", {"N": "15952"}), 13 | ]) 14 | def test_get_non_performing_loans_codes_by_state_total(self, states, expected_codes): 15 | assert get_non_performing_loans_codes(states) == expected_codes 16 | 17 | 18 | class TestGetNonPerformingLoans: 19 | @pytest.mark.parametrize("states,expected_columns", [ 20 | (["BA"], ["BA"]), 21 | (["am", "pa"], ["AM", "PA"]), 22 | ("N", ["N"]), 23 | ]) 24 | def test_get_series_by_states_pf(self, states, expected_columns): 25 | series = get_non_performing_loans(states, last=10, mode="pf") 26 | 27 | assert isinstance(series, pd.DataFrame) 28 | assert (series.columns == expected_columns).all() 29 | assert len(series) == 10 30 | 31 | def test_get_series_by_region_pj(self): 32 | south_states = BRAZILIAN_REGIONS["S"] 33 | series = get_non_performing_loans(south_states, last=5, mode="pj") 34 | 35 | assert isinstance(series, pd.DataFrame) 36 | assert (series.columns == south_states).all() 37 | assert len(series) == 5 38 | 39 | 40 | class TestNonPerformingLoansCodes: 41 | @pytest.fixture 42 | def non_performing_constants(self): 43 | constants = [ 44 | item 45 | for item in dir(regional_economy) 46 | if item.startswith("NON_PERFORMING_LOANS_BY") 47 | ] 48 | return constants 49 | 50 | def test_if_all_regions_and_states_are_there(self, non_performing_constants): 51 | for item_str in non_performing_constants: 52 | item = getattr(regional_economy, item_str) 53 | if "REGION" in str(item): 54 | assert (list(item.values()) == list(BRAZILIAN_REGIONS.keys())), item_str 55 | elif "STATE" in str(item): 56 | assert (list(item.values()) == BRAZILIAN_STATES), item_str 57 | 58 | def test_check_if_codes_are_unique(self, non_performing_constants): 59 | for item_str in non_performing_constants: 60 | item = getattr(regional_economy, item_str) 61 | 62 | unique_values = set(item.values()) 63 | assert all(unique_values), item_str 64 | assert (len(item.values()) == len(unique_values)), item_str 65 | -------------------------------------------------------------------------------- /tests/sgs/test_series.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | import pandas as pd 4 | 5 | from bcb import sgs 6 | 7 | 8 | def test_series_code_args(): 9 | code = sgs.SGSCode(1) 10 | assert code.name == "1" 11 | assert code.value == 1 12 | 13 | code = sgs.SGSCode("1") 14 | assert code.name == "1" 15 | assert code.value == 1 16 | 17 | code = sgs.SGSCode(1, "name") 18 | assert code.name == "name" 19 | assert code.value == 1 20 | 21 | 22 | def test_series_code_iter(): 23 | x = list(sgs._codes(None)) 24 | assert len(x) == 0 25 | 26 | x = list(sgs._codes(1)) 27 | assert len(x) == 1 28 | assert isinstance(x[0], sgs.SGSCode) 29 | assert x[0].name == "1" 30 | assert x[0].value == 1 31 | 32 | x = list(sgs._codes("1")) 33 | assert len(x) == 1 34 | assert isinstance(x[0], sgs.SGSCode) 35 | assert x[0].name == "1" 36 | assert x[0].value == 1 37 | 38 | x = list(sgs._codes([1, 2])) 39 | assert len(x) == 2 40 | assert isinstance(x[0], sgs.SGSCode) 41 | assert x[0].name == "1" 42 | assert x[0].value == 1 43 | assert x[1].name == "2" 44 | assert x[1].value == 2 45 | 46 | x = list(sgs._codes(("name", 1))) 47 | assert len(x) == 1 48 | assert isinstance(x[0], sgs.SGSCode) 49 | assert x[0].name == "name" 50 | assert x[0].value == 1 51 | 52 | x = list(sgs._codes([("name", 1), 2])) 53 | assert len(x) == 2 54 | assert isinstance(x[0], sgs.SGSCode) 55 | assert x[0].name == "name" 56 | assert x[0].value == 1 57 | assert x[1].name == "2" 58 | assert x[1].value == 2 59 | 60 | x = list(sgs._codes({"1": 1})) 61 | assert len(x) == 1 62 | assert isinstance(x[0], sgs.SGSCode) 63 | assert x[0].name == "1" 64 | assert x[0].value == 1 65 | 66 | x = list(sgs._codes({"name1": 1, "name2": 2})) 67 | assert len(x) == 2 68 | assert isinstance(x[0], sgs.SGSCode) 69 | assert x[0].name == "name1" 70 | assert x[0].value == 1 71 | assert x[1].name == "name2" 72 | assert x[1].value == 2 73 | 74 | 75 | def test_get_series(): 76 | x = sgs.get(1, last=10) 77 | assert isinstance(x, pd.DataFrame) 78 | assert x.columns == ["1"] 79 | assert len(x) == 10 80 | 81 | x = sgs.get({"USDBRL": 1}, last=5) 82 | assert isinstance(x, pd.DataFrame) 83 | assert x.columns == ["USDBRL"] 84 | assert len(x) == 5 85 | 86 | x = sgs.get({"USDBRL": 1}, start="2021-01-18", end="2021-01-22") 87 | assert isinstance(x, pd.DataFrame) 88 | assert x.columns == ["USDBRL"] 89 | assert len(x) == 5 90 | assert x.index[0] == datetime.strptime("2021-01-18", "%Y-%m-%d") 91 | assert x.index[-1] == datetime.strptime("2021-01-22", "%Y-%m-%d") 92 | 93 | 94 | def test_json_return(): 95 | # Test for JSON return 96 | x = sgs.get_json(1, last=10) 97 | assert isinstance(x, str) 98 | assert len(x) > 0 99 | assert x.startswith("[") 100 | assert x.endswith("]") 101 | 102 | 103 | def test_json_return_long_series_error(): 104 | # Test for JSON return long series error 105 | try: 106 | sgs.get_json(1, start="2000-01-01", end="2023-01-01") 107 | except Exception as e: 108 | assert ( 109 | str(e) 110 | == "BCB error: O sistema aceita uma janela de consulta de, no máximo, 10 anos em séries de periodicidade diária" 111 | ) 112 | else: 113 | assert False, "Expected an exception but none was raised." 114 | 115 | try: 116 | sgs.get_json(1, last=50) 117 | except Exception as e: 118 | assert ( 119 | str(e) 120 | == "BCB error: br.gov.bcb.pec.sgs.comum.excecoes.SGSNegocioException: A quantidade máxima de valores deve ser 20" 121 | ) 122 | else: 123 | assert False, "Expected an exception but none was raised." 124 | -------------------------------------------------------------------------------- /tests/test_currency.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, date 2 | import pandas as pd 3 | from pytest import mark 4 | from bcb import currency 5 | 6 | 7 | def test_currency_id(): 8 | assert currency._get_currency_id("USD") == 61 9 | 10 | 11 | @mark.flaky(max_runs=20, min_passes=1) 12 | def test_currency_get_symbol(): 13 | start_date = datetime.strptime("2020-12-01", "%Y-%m-%d") 14 | end_date = datetime.strptime("2020-12-05", "%Y-%m-%d") 15 | x = currency._get_symbol("USD", start_date, end_date) 16 | assert isinstance(x, pd.DataFrame) 17 | x = currency._get_symbol("ZAR", start_date, end_date) 18 | assert x is None 19 | x = currency.get("USD", start_date, end_date) 20 | assert isinstance(x, pd.DataFrame) 21 | x = currency.get("ZAR", start_date, end_date) 22 | assert x is None 23 | x = currency.get(["ZAR", "ZZ1"], start_date, end_date) 24 | assert x is None 25 | 26 | 27 | def test_get_valid_currency_list(): 28 | x = currency._get_valid_currency_list(date.today()) 29 | assert x is not None 30 | -------------------------------------------------------------------------------- /tests/test_expectativas.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from datetime import datetime 3 | from pytest import fixture 4 | 5 | from bcb import Expectativas 6 | 7 | 8 | @fixture 9 | def endpoints(): 10 | ep = Expectativas() 11 | return [ep.get_endpoint(e.data["name"]) for e in ep.service.endpoints] 12 | 13 | 14 | def test_expectativas_date_format(endpoints): 15 | for endpoint in endpoints: 16 | query = endpoint.query().limit(1) 17 | data = query.collect() 18 | assert isinstance(data, pd.DataFrame) 19 | assert data.shape[0] == 1 20 | assert isinstance(data["Data"].iloc[0], datetime) 21 | -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | from datetime import date, datetime 2 | 3 | from bcb import utils 4 | 5 | 6 | def test_date(): 7 | d = utils.Date("2020-01-01") 8 | assert d.date == date(2020, 1, 1) 9 | d = utils.Date("01/01/2020", format="%d/%m/%Y") 10 | assert d.date == date(2020, 1, 1) 11 | d = utils.Date(date(2020, 1, 1)) 12 | assert d.date == date(2020, 1, 1) 13 | d = utils.Date(datetime(2020, 1, 1)) 14 | assert d.date == date(2020, 1, 1) 15 | d = utils.Date("now") 16 | assert d.date == date.today() 17 | d = utils.Date("today") 18 | assert d.date == date.today() 19 | --------------------------------------------------------------------------------