Initial commit for 0.0.1

This commit is contained in:
dpguthrie 2020-08-21 22:29:52 -06:00
commit b11c84fbde
31 changed files with 7205 additions and 0 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto

80
.gitignore vendored Normal file
View File

@ -0,0 +1,80 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# PyBuilder
target/
# pyenv
.python-version
# Environments
.venv
# mkdocs documentation
*/docs/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# Project
.vscode/
reference/
next.py

26
.travis.yml Normal file
View File

@ -0,0 +1,26 @@
language: python
python:
- 3.5
- 3.6
- 3.7
- 3.8
before_install:
- python --version
- pip install -U pip
- pip install -U pytest
- pip install codecov
install:
- pip install Cython
- pip install -r requirements.txt
- pip install ".[test]" .
script: pytest
after_success:
- codecov
deploy:
provider: pypi
username: "__token__"
password:
secure: Fbf2V6YVrjQaD3jNMP6Iu7gkGhPQjLhEWWVATaB4hAD/SXVdjKwOmdGgw7fhEgDT0SRrWiamo/2C6qTUtD/g17gNYlsvsjp5dmWuh27hLF0j9Ng0Xti5P1vw5NsGGOqvb3Bvd+YegTUWOw6QQ695OXox9UAOFjvwbshk+YhaJ/CuerPBZKEm7lbsoPfKwsg+u7s9eh6LTPyFZpyNlEyeOew8/YP30Rk8JD6wEy9FSgyyawIUpeJjczwSMKhLXdtHiXhhEEAr9Ce+Epi1JPVnO8QcdWQK8PfjDBc7reBkeO1k+1bNMtPlDBYHYnOR9aci5nsKFTd3XAxAV1n8tCohnnPBHMlh8F/UbtjVtXoxxfVzBMeWyV65nymHbgk5sk0WWd6Ae+IEvRb6PKHxU49DQfoxku39tQMyfA9gWdtpOu8d5TNLrcRsAwrNOhB7qT7bp4dmcx3FoctZzJ6d0Y3B7jcneo8229G+3HL8XLyHb5CLiGJ7S9IOWwa3ctshW36vXydGZmb4+BqUv/DRfUlNsgndTpImRSG7HqTPqgCc7OMsyYWOKiZyKJqYGHBSiMaLWoTJUoAR86CnOm+0aqevk/K2vC0ek69E6wDxakuLAd4cqXeyhv2RYUGOW/aKtvfqEJllfu/pHkhq98rnd567Ki7KX29q1zM/frP5r76mPLY=
on:
tags: true
python: 3.8

5
CHANGELOG.md Normal file
View File

@ -0,0 +1,5 @@
# Changelog
## 0.0.1
- Ability to hit 5 separate endpoints (institutions, failures, history, locations, and summary) as well as filter and search according to the API specifications

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2020 Doug Guthrie
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

74
README.md Normal file
View File

@ -0,0 +1,74 @@
<p align="center">
<a href="#"><img src="img/logo.png"></a>
</p>
<p align="center">
<em>Python interface to the FDIC's API for publically available bank data</em>
</p>
<p align="center">
<a href="https://travis-ci.com/dpguthrie/bankfind" target="_blank">
<img src="https://travis-ci.com/dpguthrie/bankfind.svg?branch=master" alt="Build Status">
</a>
<a href="https://codecov.io/gh/dpguthrie/bankfind" target="_blank">
<img src="https://img.shields.io/codecov/c/github/dpguthrie/bankfind" alt="Coverage">
</a>
<a href="https://pypi.org/project/bankfind" target="_blank">
<img src="https://badge.fury.io/py/bankfind.svg" alt="Package version">
</a>
</p>
---
**Documentation**: <a target="_blank" href="https://bankfind.dpguthrie.com">https://bankfind.dpguthrie.com</a>
**Source Code**: <a target="_blank" href="https://github.com/dpguthrie/bankfind">https://github.com/dpguthrie/bankfind</a>
**FDIC Documentation**: <a target="_blank" href="https://banks.data.fdic.gov/docs/">https://banks.data.fdic.gov/docs/</a>
---
## Overview
**bankfind** is a python interface to publically available bank data from the FDIC.
There are currently, as of 8/11/20, five endpoints that the FDIC has exposed to the public:
- **failures** - returns detail on failed financial institutions
- **institutions** - returns a list of financial institutions
- **history** - returns detail on structure change events
- **locations** - returns locations / branches of financial institutions
- **summary** - returns aggregate financial and structure data, subtotaled by year, regarding financial institutions
## Requirements
Python 2.7, 3.5+
- [Requests](https://requests.readthedocs.io/en/master/) - The elegant and simple HTTP library for Python, built for human beings.
- [Pandas](https://pandas.pydata.org/) - Fast, powerful, flexible and easy to use open source data analysis and manipulation tool
## Installation
<div class="termynal" data-termynal data-ty-typeDelay="40" data-ty-lineDelay="700">
<span data-ty="input">pip install bankfind</span>
<span data-ty="progress"></span>
<span data-ty>Successfully installed bankfind</span>
<a href="#" data-terminal-control="">restart ↻</a>
</div>
## Example
```python
import bankfind as bf
# Get Institutions
data = bf.get_institutions()
# Get Institutions from Colorado with high ROE
data = bf.get_institutions(filters="STNAME:Colorado AND ROE:[25 TO *]")
# Get Commercial Banks from Colorado that aren't S-Corps
data = bf.get_institutions(filters="STNAME:Colorado AND SUBCHAPS:0 AND CB:1")
```
## License
This project is licensed under the terms of the MIT license.

8
bankfind/__init__.py Normal file
View File

@ -0,0 +1,8 @@
"""Python interface to the FDIC's API for publically available bank data"""
__version__ = '0.0.1'
from .main import (get_failures, get_history, get_institutions, # noqa
get_locations, get_summary)
from .metadata import meta_dict # noqa

131
bankfind/base.py Normal file
View File

@ -0,0 +1,131 @@
from io import StringIO
import urllib.parse
import pandas as pd
import requests
from requests.models import Response
from bankfind.metadata import meta_dict
class BF:
DEFAULTS = {
'institutions': {
'sort_by': 'OFFICES',
'sort_order': 'ASC',
'limit': 10000,
'offset': 0,
'format': 'json',
'search': True
},
'locations': {
'sort_by': 'NAME',
'sort_order': 'ASC',
'limit': 10000,
'offset': 0,
'format': 'json',
'search': False
},
'history': {
'sort_by': 'PROCDATE',
'sort_order': 'DESC',
'limit': 10000,
'offset': 0,
'format': 'json',
'search': True
},
'summary': {
'sort_by': 'YEAR',
'sort_order': 'DESC',
'limit': 10000,
'offset': 0,
'format': 'json',
'search': False
},
'failures': {
'sort_by': 'FAILDATE',
'sort_order': 'DESC',
'limit': 10000,
'offset': 0,
'format': 'json',
'search': False
}
}
def __init__(self):
pass
def _construct_params(
self,
key: str,
filters: str = None,
search: str = None,
**kwargs):
d = self.DEFAULTS[key]
params = {
'sort_by': kwargs.get('sort_by', d['sort_by']),
'sort_order': kwargs.get(
'sort_order', d['sort_order']),
'limit': kwargs.get('limit', d['limit']),
'offset': kwargs.get('offset', d['offset']),
'format': 'csv' if kwargs.get('output') == 'pandas' else 'json',
'download': 'false',
'fields': kwargs.get(
'fields', ','.join(list(meta_dict[key].keys())))
}
if filters:
params.update({'filters': filters})
if search and d['search']:
params.update({'search': search})
return params
def _friendly_fields(self, key, data, dataframe=True):
meta = meta_dict[key]
if isinstance(data, list):
data = pd.DataFrame([i['data'] for i in data])
data.columns = data.columns.map(
dict((k, meta[k]['title'])
for k in meta.keys() if k in data.columns))
if dataframe:
return data
return data.to_dict(orient='records')
def _to_json(
self,
key: str,
response: Response,
friendly_fields: bool = False):
json_data = response.json()
if friendly_fields:
json_data['data'] = self._friendly_fields(
key, json_data['data'], dataframe=False)
else:
json_data['data'] = [i['data'] for i in json_data['data']]
return json_data
def _to_pandas(
self,
key: str,
response: Response,
friendly_fields: bool = False):
df = pd.read_csv(StringIO(response.text))
if friendly_fields:
df = self._friendly_fields(key, df)
return df
def _get_data(
self,
key: str,
filters: str = None,
search: str = None,
**kwargs):
params = self._construct_params(key, filters, search, **kwargs)
r = requests.get(
f"https://banks.data.fdic.gov/api/{key}",
params=urllib.parse.urlencode(params)
)
if r.ok:
return getattr(self, f"_to_{kwargs.get('output', 'json')}")(
key, r, kwargs.get('friendly_fields', False))
return r

154
bankfind/main.py Normal file
View File

@ -0,0 +1,154 @@
from bankfind.base import BF
def get_failures(filters: str = None, **kwargs):
"""
Detail on failed financial institutions
Arguments
---------
filters: str, default None, optional
Filter for the bank search
Keyword Arguments
-----------------
fields: str, default ALL FIELDS, optional
Comma delimited list of fields to search
sort_by: str, default OFFICES, optional
Field name by which to sort returned data
sort_order: str, default ASC, optional
Indicator if ascending (ASC) or descending (DESC)
limit: int, default 10,000, optional
Number of records to return. Maximum is 10,000
offset: int, default 0, optional
Offset of page to return
format: str, default json, optional
Format of the data to return
friendly_fields: bool, default False, optional
Return friendly field names
"""
return BF()._get_data("failures", filters, **kwargs)
def get_history(filters: str = None, search: str = None, **kwargs):
"""
Detail on structure change events
Arguments
---------
filters: str, default None, optional
Filter for the bank search
search: str
Flexible text search against institution records. Currently, only
supports name search. Text search and fuzzy matching is supported
as well.
Keyword Arguments
-----------------
fields: str, default ALL FIELDS, optional
Comma delimited list of fields to search
sort_by: str, default OFFICES, optional
Field name by which to sort returned data
sort_order: str, default ASC, optional
Indicator if ascending (ASC) or descending (DESC)
limit: int, default 10,000, optional
Number of records to return. Maximum is 10,000
offset: int, default 0, optional
Offset of page to return
output: str, default json, optional
Format of the data to return, json or pandas
friendly_fields: bool, default False, optional
Return friendly field names
"""
return BF()._get_data("history", filters, search, **kwargs)
def get_institutions(filters: str = None, search: str = None, **kwargs):
"""
List of financial institutions
Arguments
---------
filters: str, default None, optional
Filter for the bank search
search: str
Flexible text search against institution records. Currently, only
supports name search. Text search and fuzzy matching is supported
as well.
Keyword Arguments
-----------------
fields: str, default ALL FIELDS, optional
Comma delimited list of fields to search
sort_by: str, default OFFICES, optional
Field name by which to sort returned data
sort_order: str, default ASC, optional
Indicator if ascending (ASC) or descending (DESC)
limit: int, default 10,000, optional
Number of records to return. Maximum is 10,000
offset: int, default 0, optional
Offset of page to return
format: str, default json, optional
Format of the data to return
friendly_fields: bool, default False, optional
Return friendly field names
"""
return BF()._get_data("institutions", filters, search, **kwargs)
def get_locations(filters: str = None, **kwargs):
"""
List of locations / branches of financial institutions
Arguments
---------
filters: str, default None, optional
Filter for the bank search
Keyword Arguments
-----------------
fields: str, default ALL FIELDS, optional
Comma delimited list of fields to search
sort_by: str, default OFFICES, optional
Field name by which to sort returned data
sort_order: str, default ASC, optional
Indicator if ascending (ASC) or descending (DESC)
limit: int, default 10,000, optional
Number of records to return. Maximum is 10,000
offset: int, default 0, optional
Offset of page to return
format: str, default json, optional
Format of the data to return
friendly_fields: bool, default False, optional
Return friendly field names
"""
return BF()._get_data("locations", filters, **kwargs)
def get_summary(filters: str = None, **kwargs):
"""
Aggregate financial and structure data, subtotaled by year
Arguments
---------
filters: str, default None, optional
Filter for the bank search
Keyword Arguments
-----------------
fields: str, default ALL FIELDS, optional
Comma delimited list of fields to search
sort_by: str, default OFFICES, optional
Field name by which to sort returned data
sort_order: str, default ASC, optional
Indicator if ascending (ASC) or descending (DESC)
limit: int, default 10,000, optional
Number of records to return. Maximum is 10,000
offset: int, default 0, optional
Offset of page to return
format: str, default json, optional
Format of the data to return
friendly_fields: bool, default False, optional
Return friendly field names
"""
return BF()._get_data("summary", filters, **kwargs)

View File

@ -0,0 +1,14 @@
from .failure import failure_dict
from .history import history_dict
from .institution import institution_dict
from .location import location_dict
from .summary import summary_dict
meta_dict = {
'failures': failure_dict,
'history': history_dict,
'institutions': institution_dict,
'locations': location_dict,
'summary': summary_dict
}

View File

@ -0,0 +1,93 @@
failure_dict = {
'NAME': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Institution Name',
'description': "This is the legal name of the institution. When available, the Institution's name links to useful information for the customers and vendors of these institutions. This information includes press releases, information about the acquiring institution, (if applicable), how your accounts and loans are affected, and how vendors can file claims against the receivership."
},
'CERT': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Cert',
'description': 'The certificate number assigned by the FDIC used to identify institutions and for the issuance of insurance certificates. By clicking on this number, you will link to the Institution Directory (ID) system which will provide the last demographic and financial data filed by the selected institution.'
},
'FIN': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'FIN',
'description': 'Financial Institution Number (FIN) is a unique number assigned to the institution as an Assistance Agreement, Conservatorship, Bridge Bank or Receivership.'
},
'CITYST': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Location',
'description': 'The city and state (or territory) of the headquarters of the institution.'
},
'FAILDATE': {
'type': 'string',
'format': 'date-time',
'title': 'Effective Date',
'description': 'The date that the failed / assisted institution ceased to exist as a privately held going concern. For institutions that entered into government ownership, such as FDIC Bridge Banks and RTC conservatorships, this is the date that they entered into such ownership.'
},
'FAILYR': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Year',
'description': 'The 4-digit year that the failed / assisted institution ceased to exist as a privately held going concern. For institutions that entered into government ownership, such as FDIC Bridge Banks and RTC conservatorships, this is the date that they entered into such ownership.'
},
'SAVR': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Insurance Fund',
'description': 'Before 1989, there were two federal deposit insurance funds, one administered by the FDIC, which insured deposits in commercial banks and state-chartered savings banks, and another administered by the Federal Savings and Loan Insurance Corporation (FSLIC), which insured deposits in state- and federally-chartered savings associations. In 1989, the Financial Institutions Reform, Recovery and Enforcement Act (FIRREA) specified that thereafter the FDIC would be the federal deposit insurer of all banks and savings associations and would administer both the FDIC fund, which was renamed the Bank Insurance Fund (BIF) and the replacement for the insolvent FSLIC fund, which was called the Savings Association Insurance Fund (SAIF). Although it was created in 1989, the SAIF was not responsible for savings association failures until 1996. From 1989 through 1995, savings association failures were the responsibility of the Resolution Trust Corporation (RTC). In February 2006, The Federal Deposit Insurance Reform Act of 2005 provided for the merger of the BIF and the SAIF into a single Deposit Insurance Fund (DIF). Necessary technical and conforming changes to the law were made under The Federal Deposit Insurance Reform Conforming Amendments Act of 2005. The merger of the funds was effective on March 31, 2006. For additional information about deposit insurance fund and legislation, go to http://www.fdic.gov/deposit/insurance/index.html.',
'options': ['BIF', 'RTC', 'FSLIC', 'SAIF', 'DIF', 'FDIC']
},
'RESTYPE1': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Transaction Type',
'description': "Institutions have been resolved through several different types of transactions. The transaction types outlined below can be grouped into three general categories, based upon the method employed to protect insured depositors and how each transaction affects a failed / assisted institution's charter. In most assistance transactions, insured and uninsured depositors are protected, the failed / assisted institution remains open and its charter survives the resolution process. In purchase and assumption transactions, the failed / assisted institution's insured deposits are transferred to a successor institution, and its charter is closed. In most of these transactions, additional liabilities and assets are also transferred to the successor institution. In payoff transactions, the deposit insurer - the FDIC or the former Federal Savings and Loan Insurance Corporation - pays insured depositors, the failed / assisted institution's charter is closed, and there is no successor institution. For a more complete description of resolution transactions and the FDIC's receivership activities, see Managing the Crisis: The FDIC and RTC Experience, a study prepared by the FDIC's Division of Resolutions and Receiverships. Copies are available from the FDIC's Public Information Center.\nCategory 1 - Institution's charter survives\nA/A\t- Assistance Transactions. These include: 1) transactions where assistance was provided to the acquirer, who purchased the entire institution. For a few FSLIC transactions, the acquirer purchased the entire bridge bank - type entity, but certain other assets were moved into a liquidating receivership prior to the sale, and 2) open bank assistance transactions, including those where assistance was provided under a systemic risk determination (in such cases any costs that exceed the amounts estimated under the least cost resolution requirement would be recovered through a special assessment on all FDIC-insured institutions).\nREP -\tReprivatization, management takeover with or without assistance at takeover, followed by a sale with or without additional assistance.\nCategory 2 - Institution's charter is terminated, insured deposits plus some assets and other liabilities are transferred to a successor charter\nP&A - Purchase and Assumption, where some or all of the deposits, certain other liabilities and a portion of the assets (sometimes all of the assets) were sold to an acquirer. It was not determined if all of the deposits (PA) or only the insured deposits (PI) were assumed.\nPA - Purchase and Assumption, where the insured and uninsured deposits, certain other liabilities and a portion of the assets were sold to an acquirer.\nPI - Purchase and Assumption of the insured deposits only, where the traditional P&A was modified so that only the insured deposits were assumed by the acquiring institution.\nIDT - Insured Deposit Transfer, where the acquiring institution served as a paying agent for the insurer, established accounts on their books for depositors, and often acquired some assets as well. Includes ABT (asset-backed transfer, a FSLIC transaction that is very similar to an IDT).\nMGR - An institution where FSLIC took over management and generally provided financial assistance. FSLIC closed down before the institution was sold.\nCategory 3\nPO - Payout, where the insurer paid the depositors directly and placed the assets in a liquidating receivership. Note: Includes transactions where the FDIC established a Deposit Insurance National Bank to facilitate the payout process.",
'options': ['A/A', 'REP', 'P&A', 'PA', 'PI', 'IDT', 'MGR', 'PO']
},
'CHCLASS1': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Charter Class',
'description': "The FDIC assigns classification codes indicating an institution's charter type (commercial bank, savings bank, or savings association), its chartering agent (state or federal government), its Federal Reserve membership status (member or nonmember), and its primary federal regulator (state-chartered institutions are subject to both federal and state supervision). These codes are:\nN - National chartered commercial bank supervised by the Office of the Comptroller of the Currency;\nSM - State charter Fed member commercial bank supervised by the Federal Reserve;\nNM - State charter Fed nonmember commercial bank supervised by the FDIC;\nSA - State or federal charter savings association supervised by the Office of Thrift Supervision or Office of the Comptroller of the Currency;\nSB - State charter savings bank supervised by the FDIC.",
'options': ['N', 'SM', 'NM', 'SA', 'SB']
},
'RESTYPE': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Resolution',
'description': 'The given institution has failure stature or it can be assistance has been provided by FDIC in merging with other institution.',
'options': ['Failure', 'Assistance']
},
'QBFDEP': {
'type': 'number',
'x-elastic-type': 'double',
'x-number-unit': 'Thousands of US Dollars',
'title': 'Total Deposits',
'description': 'Total including demand deposits, money market deposits, other savings deposits, time deposits and deposits in foreign offices as of the last Call Report or Thrift Financial Report filed by the institution prior to the effective date. Note this does not necessarily reflect total deposits on the last report filed because in some cases reports were filed after the effective date.'
},
'QBFASSET': {
'type': 'number',
'x-elastic-type': 'double',
'x-number-unit': 'Thousands of US Dollars',
'title': 'Total Assets',
'description': 'The Total assets owned by the institution including cash, loans, securities, bank premises and other assets as of the last Call Report or Thrift Financial Report filed by the institution prior to the effective date. Note this does not necessarily reflect total assets on the last report filed because in some cases reports were filed after the effective date. This total does not include off-balance-sheet accounts.'
},
'COST': {
'type': 'number',
'x-elastic-type': 'double',
'x-number-unit': 'Thousands of US Dollars',
'title': 'Estimated Loss',
'description': 'The estimated loss is the difference between the amount disbursed from the Deposit Insurance Fund (DIF) to cover obligations to insured depositors and the amount estimated to be ultimately recovered from the liquidation of the receivership estate. Estimated losses reflect unpaid principal amounts deemed unrecoverable and do not reflect interest that may be due on the DIF\'s administrative or subrogated claims should its principal be repaid in full.\nNotes:\nComprehensive data on estimated losses are not available for FDIC-insured failures prior to 1986, or for FSLIC-insured failures from 1934-88. Estimated loss is presented as "N/A" in years for which comprehensive information is not available.\nEstimated Loss data was previously referred to as \'Estimated Cost\' in past releases of the Historical Statistic on Banking. For RTC receiverships, the \'Estimated Cost\' included an allocation of FDIC corporate revenue and expense items such as interest expense on Federal Financing Bank debt, interest expense on escrowed funds and interest revenue on advances to receiverships. Other FDIC receiverships did not include such an allocation. To maintain consistency with FDIC receiverships, the RTC allocation is no longer reflected in the estimated loss amounts for failed / assisted institutions that were resolved through RTC receiverships.\nBeginning with the release of 2007 information, the \'Estimated Loss\' in the Historical Statistics on Banking is presented and defined consistently with the aggregate Estimated Receivership Loss for FRF-RTC institutions and Estimated Losses for FDIC receiverships that are reported in the FDIC\'s Annual Report. The estimated loss is obtained from the FDIC\'s Failed Bank Cost Analysis (FBCA) report and the RTC Loss report. The FBCA provides data for receiverships back to 1986. The RTC Loss Report provides similar data back to 1989. \nQuestions regarding Estimated Loss should be sent to DOFBusinessCenter@fdic.gov. \nAlso, for more detail regarding resolution transactions and the FDIC\'s receivership activities, see Managing the Crisis: The FDIC and RTC Experience, a historical study prepared by the FDIC\'s Division of Resolutions and Receiverships. Copies are available from the FDIC\'s Public Information Center.'
},
'PSTALP': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'State',
'description': 'Two-character alphanumeric code for US state or Territory'
}
}

2108
bankfind/metadata/history.py Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,348 @@
location_dict = {
'ADDRESS': {
'type': 'string',
'title': 'Branch Address',
'description': 'Street address at which the branch is physically located.',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'LOCN_PHY_LNE1_TXT'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'LOCN_ADDR_LNE1_TXT'
}]
},
'BKCLASS': {
'type': 'string',
'title': 'Institution Class',
'description': "A classification code assigned by the FDIC based on the institution''s charter type (commercial bank or savings institution), charter agent (state or federal), Federal Reserve membership status (Fed member, Fed nonmember) and its primary federal regulator (state chartered institutions are subject to both federal and state supervision). N - Commercial bank, national (federal) charter and Fed member, supervised by the Office of the Comptroller of the Currency (OCC); NM - Commercial bank, state charter and Fed nonmember, supervised by the FDIC; OI - Insured U.S. branch of a foreign chartered institution (IBA); SA - Savings associations, state or federal charter, supervised by the Office of Thrift Supervision (OTS); SB - Savings banks, state charter, supervised by the FDIC; SM - Commercial bank, state charter and Fed member, supervised by the Federal Reserve (FRB)",
'options': ['N', 'NM', 'OI', 'SA', 'SB', 'SM'],
'x-source-mapping': [{
'formula': {
'type': 'raw',
'parameters': {
'script': 'if(ctx.INST_CLASS_CDE?.toLowerCase() == "sb" || ctx.INST_CLASS_CDE?.toLowerCase() == "sl") { \n ctx.BKCLASS = \'SA\'; \n} else if (ctx.INST_CLASS_CDE?.toLowerCase() == "mi" || ctx.INST_CLASS_CDE?.toLowerCase() == "si") { \n ctx.BKCLASS = \'SB\';\n} else {\n ctx.BKCLASS = ctx.INST_CLASS_CDE;\n}\n'
}
}
}]
},
'CBSA': {
'type': 'string',
'title': 'Core Based Statistical Area Name (Branch)',
'description': 'Name of the Core Based Statistical Area (CBSA) as defined by the US Census Bureau Office of Management and Budget.',
'x-source-mapping': [{
'file': 'RELATION',
'field': 'CBSANAME'
}]
},
'CBSA_DIV': {
'type': 'string',
'title': 'Metropolitan Divisions Name (Branch)',
'description': 'Name of the Core Based Statistical Division as defined by the US Census Bureau Office of Management and Budget.',
'x-source-mapping': [{
'file': 'RELATION',
'field': 'CBSA_DIV_NAME'
}]
},
'CBSA_DIV_FLG': {
'type': 'string',
'title': 'Metropolitan Divisions Flag (Branch)',
'description': 'A flag (1=Yes) indicating member of a Core Based Statistical Division as defined by the US Census Bureau Office of Management and Budget.',
'options': [0, 1],
'x-source-mapping': [{
'file': 'RELATION',
'field': 'DIVISION_FLAG'
}]
},
'CBSA_DIV_NO': {
'type': 'string',
'title': 'Metropolitan Divisions Number (Branch)',
'description': 'Numeric code of the Core Based Statistical Division as defined by the US Census Bureau Office of Management and Budget.',
'x-source-mapping': [{
'file': 'RELATION',
'field': 'CBSA_DIVISION'
}]
},
'CBSA_METRO': {
'type': 'string',
'title': 'Metropolitan Division Number (Branch)',
'description': 'Numeric code of the Metropolitan Statistical Area as defined by the US Census Bureau Office of Management and Budget',
'x-source-mapping': [{
'formula': {
'type': 'raw',
'parameters': {
'script': 'if(ctx.CBSA_METRO_FLG == "1") {\n ctx.CBSA_METRO = ctx.CBSA_NO;\n} else {\n ctx.CBSA_METRO = 0;\n} \n'
}
}
}]
},
'CBSA_METRO_FLG': {
'type': 'string',
'title': 'Metropolitan Division Flag (Branch)',
'description': 'A flag (1=Yes) used to indicate whether an branch is in a Metropolitan Statistical Area as defined by the US Census Bureau Office of Management and Budget',
'x-source-mapping': [{
'file': 'RELATION',
'field': 'METRO_FLAG'
}]
},
'CBSA_METRO_NAME': {
'type': 'string',
'title': 'Metropolitan Division Name (Branch)',
'description': 'Name of the Metropolitan Statistical Area as defined by the US Census Bureau Office of Management and Budget',
'x-source-mapping': [{
'formula': {
'type': 'raw',
'parameters': {
'script': 'if(ctx.CBSA_METRO_FLG == "1") {\n ctx.CBSA_METRO_NAME = ctx.CBSA;\n} else {\n ctx.CBSA_METRO_NAME = 0;\n}\n'
}
}
}]
},
'CBSA_MICRO_FLG': {
'type': 'string',
'title': 'Micropolitan Division Flag (Branch)',
'description': 'A flag (1=Yes) used to indicate whether an branch is in a Micropolitan Statistical Area as defined by the US Census Bureau Office of Management and Budget',
'options': [0, 1],
'x-source-mapping': [{
'file': 'RELATION',
'field': 'MICRO_FLAG'
}]
},
'CBSA_NO': {
'type': 'string',
'title': 'Core Based Statistical Areas (Branch)',
'description': 'Numeric code of the Core Based Statistical Area (CBSA) as defined by the US Census Bureau Office of Management and Budget.',
'x-source-mapping': [{
'file': 'RELATION',
'field': 'CBSA'
}]
},
'CERT': {
'type': 'string',
'title': 'Institution FDIC Certificate #',
'description': 'A unique number assigned by the FDIC used to identify institutions and for the issuance of insurance certificates.',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'ORG_CERT_NUM'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'ORG_CERT_NUM'
}]
},
'CITY': {
'type': 'string',
'title': 'Branch City',
'description': 'City in which branch is physically located.',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'LOCN_PHY_CTY_NME'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'LOCN_CTY_NME'
}]
},
'COUNTY': {
'type': 'string',
'title': 'Branch County',
'description': 'County where the branch is physically located.',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'LOCN_PHY_CNTY_NME'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'LOCN_CNTY_NME'
}]
},
'CSA': {
'type': 'string',
'title': 'Combined Statistical Area Name (Branch)',
'description': 'Name of the Combined Statistical Area (CSA) as defined by the US Census Bureau Office of Management and Budget',
'x-source-mapping': [{
'file': 'RELATION',
'field': 'CSANAME'
}]
},
'CSA_FLG': {
'type': 'string',
'title': 'Combined Statistical Area Flag (Branch)',
'description': 'Flag (1=Yes) indicating member of a Combined Statistical Area (CSA) as defined by the US Census Bureau Office of Management and Budget',
'options': [0, 1],
'x-source-mapping': [{
'file': 'RELATION',
'field': 'CSA_FLAG'
}]
},
'CSA_NO': {
'type': 'string',
'title': 'Combined Statistical Area Number (Branch)',
'description': 'Numeric code of the Combined Statistical Area (CSA) as defined by the US Census Bureau Office of Management and Budget',
'x-source-mapping': [{
'file': 'RELATION',
'field': 'CSA'
}]
},
'ESTYMD': {
'type': 'string',
'format': 'date-time',
'title': 'Branch Established Date',
'description': 'The date on which the branch began operations.',
'x-source-mapping': [{
'formula': {
'type': 'date',
'parameters': {
'inputFormat': "yyyy-MM-dd'T'HH:mm:ss",
'outputFormat': 'MM/dd/yyyy',
'inputField': 'ESTYMD_RAW',
'outputField': 'ESTYMD'
}
}
}]
},
'FI_UNINUM': {
'type': 'string',
'title': 'FDIC UNINUM of the Owner Institution',
'description': 'This is the FDIC UNINUM of the institution that owns the branch. A UNINUM is a unique sequentially number added to the FDIC database for both banks and branches. There is no pattern imbedded within the number. The FI_UNINUM is updated with every merger or purchase of branches to reflect the most current owner.',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'ORG_UNIQ_NUM'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'FI_ORG_UNIQ_NUM'
}]
},
'MAINOFF': {
'type': 'number',
'title': 'Main Office',
'description': 'Flag (1=Yes) indicating this location is the main office for the institution.',
'options': [0, 1],
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'MAINOFF'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'MAINOFF'
}]
},
'NAME': {
'type': 'string',
'x-elastic-type': 'keyword',
'title': 'Institution Name',
'description': 'Legal name of the FDIC Insured Institution',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'INST_FIN_LGL_NME'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'INST_FIN_LGL_NME'
}]
},
'OFFNAME': {
'type': 'string',
'title': 'Office Name',
'description': 'Name of the branch.',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'INST_FIN_LGL_NME'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'INST_BR_NME'
}]
},
'OFFNUM': {
'type': 'string',
'title': 'Branch Number',
'description': "The branch's corresponding office number.",
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'OFFNUM'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'INST_BR_OFC_NUM'
}]
},
'RUNDATE': {
'type': 'string',
'format': 'date-time',
'title': 'Run Date',
'description': 'The day the institution information was updated.',
'x-source-mapping': [{
'formula': {
'type': 'simpleSetScript',
'parameters': {
'setField': 'RUNDATE',
'script': 'new SimpleDateFormat("MM/dd/yyyy").format(new Date())'
}
}
}]
},
'SERVTYPE': {
'type': 'number',
'title': 'Service Type Code',
'description': 'Define the various types of offices of FDIC-insured institutions. 11 - Full Service Brick and Mortar Office; 12 - Full Service Retail Office; 13 - Full Service Cyber Office; 14 - Full Service Mobile Office; 15 - Full Service Home/Phone Banking; 16 - Full Service Seasonal Office; 21 - Limited Service Administrative Office; 22 - Limited Service Military Facility; 23 - Limited Service Facility Office; 24 - Limited Service Loan Production Office; 25 - Limited Service Consumer Credit Office; 26 - Limited Service Contractual Office; 27 - Limited Service Messenger Office; 28 - Limited Service Retail Office; 29 - Limited Service Mobile Office; 30 - Limited Service Trust Office;',
'options': [11, 12, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'SERVTYPE'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'INST_BR_SVC_NUM'
}]
},
'STALP': {
'type': 'string',
'title': 'Branch State Abbreviation',
'description': 'State abbreviation in which the branch is physically located. The FDIC Act defines state as any State of the United States, the District of Columbia, and any territory of the United States, Puerto Rico, Guam, American Samoa, the Trust Territory of the Pacific Islands, the Virgin Island, and the Northern Mariana Islands.',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'LOCN_PHY_ST_ABNME'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'LOCN_ST_ABBV_NME'
}]
},
'STCNTY': {
'type': 'string',
'title': 'State and County Number',
'description': 'A five digit number representing the state and county in which the institution is physically located. The first two digits represent the FIPS state numeric code and the last three digits represent the FIPS county numeric code.',
'x-source-mapping': [{
'file': 'CALCULATED_IN_PIPELINE',
'field': 'N/A'
}]
},
'STNAME': {
'type': 'string',
'title': 'Branch State',
'description': 'State in which the branch is physically located. The FDIC Act defines state as any State of the United States, the District of Columbia, and any territory of the United States, Puerto Rico, Guam, American Samoa, the Trust Territory of the Pacific Islands, the Virgin Island, and the Northern Mariana Islands.',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'LOCN_PHY_ST_NME'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'LOCN_ST_NME'
}]
},
'UNINUM': {
'type': 'string',
'title': 'Unique Identification Number for a Branch Office',
'description': 'Unique Identification Number for a Branch Office as assigned by the FDIC',
'x-source-mapping': [{
'file': 'VINST_FIN_CUR_SDC',
'field': 'ORG_UNIQ_NUM'
}, {
'file': 'VINST_BR_CUR_SDC',
'field': 'ORG_UNIQ_NUM'
}]
},
'ZIP': {
'type': 'string',
'title': 'Branch Zip Code',
'description': 'The first five digits of the full postal zip code representing physical location of the branch.',
'x-source-mapping': [{
'formula': {
'type': 'raw',
'parameters': {
'script': "if (ctx.ZIP_RAW != null && ctx.ZIP_RAW?.length() < 5){\n StringBuilder sb = new StringBuilder();\n for (int i = 0; i < 5; i++) {\n sb.append('0');\n }\n ctx.ZIP = sb.substring(ctx.ZIP_RAW.length()) + ctx.ZIP_RAW;\n} else {\n ctx.ZIP = ctx.ZIP_RAW;\n}"
}
}
}]
}
}

1178
bankfind/metadata/summary.py Normal file

File diff suppressed because it is too large Load Diff

101
docs/docs/css/termynal.css Normal file
View File

@ -0,0 +1,101 @@
/**
* termynal.js
*
* @author Ines Montani <ines@ines.io>
* @version 0.0.1
* @license MIT
*/
:root {
--color-bg: #252a33;
--color-text: #eee;
--color-text-subtle: #a2a2a2;
}
[data-termynal] {
width: 750px;
max-width: 100%;
background: var(--color-bg);
color: var(--color-text);
font-size: 18px;
font-family: 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace;
border-radius: 4px;
padding: 75px 45px 35px;
position: relative;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
[data-termynal]:before {
content: '';
position: absolute;
top: 15px;
left: 15px;
display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
/* A little hack to display the window buttons in one pseudo element. */
background: #d9515d;
-webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
}
[data-termynal]:after {
content: 'bash';
position: absolute;
color: var(--color-text-subtle);
top: 5px;
left: 0;
width: 100%;
text-align: center;
}
[data-ty] {
display: block;
line-height: 2;
}
[data-ty]:before {
/* Set up defaults and ensure empty lines are displayed. */
content: '';
display: inline-block;
vertical-align: middle;
}
[data-ty="input"]:before,
[data-ty-prompt]:before {
margin-right: 0.75em;
color: var(--color-text-subtle);
}
[data-ty="input"]:before {
content: '$';
}
[data-ty][data-ty-prompt]:before {
content: attr(data-ty-prompt);
}
[data-ty-cursor]:after {
content: attr(data-ty-cursor);
font-family: monospace;
margin-left: 0.5em;
-webkit-animation: blink 1s infinite;
animation: blink 1s infinite;
}
/* Cursor animation */
@-webkit-keyframes blink {
50% {
opacity: 0;
}
}
@keyframes blink {
50% {
opacity: 0;
}
}

156
docs/docs/filtering.md Normal file
View File

@ -0,0 +1,156 @@
The API uses the Elastic Search [query string syntax](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax) for filtering.
## Overview
First, get an idea of what fields you can use to filter from the `meta_dict`.
```python
>>> import bankfind as bf
>>> fields = bf.meta_dict.keys()
dict_keys(['failures', 'history', 'institutions', 'locations', 'summary'])
```
Each of the keys above represent an endpoint. The values corresponding to each of the keys above are dictionaries. The dictionaries contain the fields available as well as the data type, description, and, sometimes, options to filter with.
```python
>>> bf.meta_dict['failures'].keys()
dict_keys(['NAME', 'CERT', 'FIN', 'CITYST', 'FAILDATE', 'FAILYR', 'SAVR', 'RESTYPE1', 'CHCLASS1', 'RESTYPE', 'QBFDEP', 'QBFASSET', 'COST', 'PSTALP'])
>>> bf.meta_dict['failures']['NAME']
{'type': 'string', 'x-elastic-type': 'keyword', 'title': 'Institution Name', 'description': "This is the legal name of the institution. When available, the Institution's name links to useful information for the customers and vendors of these institutions. This information includes press releases, information about the acquiring institution, (if applicable), how your accounts and loans are affected, and how vendors can file claims against the receivership."}
```
## Filters
The syntax for filtering will change based on the data-type.
### strings
**Syntax**: `<FIELD>:<VALUE>`
First, let's filter based on cert, which as you can see from the `meta_dict` is a string field.
```python
>>> bf.meta_dict['failures']['CERT']['type']
'string'
>>> data = bf.get_institutions(filters="CERT:57295")
>>> len(data['data'])
1
```
Chain filters together with "AND":
```python
>>> data = bf.get_institutions(filters="STNAME:Colorado AND CITY:Denver")
>>> len(data['data'])
108
```
Filtering with "OR" is easy also:
```python
>>> data = bf.get_institutions(filters='STNAME:("Colorado","Wyoming")')
>>> len(data['data'])
844
```
### dates
Dates must be entered in the following format:
**Syntax**: `<FIELD>:yyyy-mm-dd`
```python
>>> data = bf.get_institutions(filters='DATEUPDT:2019-12-31')
>>> len(data['data'])
3919
```
They can also be used as ranges:
#### exclusive
Use curly braces `{}` and the range will exclude the beginning and end dates used in the range:
**Syntax**: `<FIELD>:{yyyy-mm-dd TO yyyy-mm-dd}`
```python
>>> data = bf.get_institutions(filters='DATEUPDT:{2015-01-01 TO 2018-12-31}')
>>> len(data['data'])
1921
```
#### inclusive
Use brackets `[]` and the range will the include the beginning and end dates used in the range
**Syntax**: `<FIELD>:[yyyy-mm-dd TO yyyy-mm-dd]`
```python
>>> data = bf.get_institutions(filters='DATEUPDT:[2010-01-01 TO 2018-12-31]')
>>> len(data['data'])
4556
```
### numbers
Numbers can also be used in ranges with the same syntax as dates
#### exclusive
Use curly braces `{}` and the range will exclude the beginning and end values in the range. Most of the values are represented in thousands.
**Syntax**: `<FIELD>:{Number TO Number}`
```python
>>> data = bf.get_institutions(filters='ASSET:{25000 TO 75000}')
>>> len(data['data'])
5530
```
#### inclusive
Use brackets `[]` and the range will the include the beginning and end dates used in the range
**Syntax**: `<FIELD>:[Number TO Number]`
*The filter below will retrieve institutions with assets greater than or equal to 2 billion or less than or equal to 5 billion.*
```python
>>> data = bf.get_institutions(filters='ASSET:[2000000 TO 5000000]')
>>> len(data['data'])
685
```
#### wildcard
**Syntax**: `<FIELD>:[Number to *]`
*The filter below will retrieve institutions with assets greater than or equal to 5 billion.*
```python
>>> data = bf.get_institutions(filters='ASSET:[5000000 TO *]')
>>> len(data['data'])
602
```
## Search
Flexible text search is also available. Search supports text search and fuzzy matching, as opposed to filters that are exact matches. Currently, only two endpoints support the search functionality: `get_institutions` and `get_history`.
The only field that currently supports the search functionality is `NAME`. It's a similar syntax to the [string filter](#strings).
```python
>>> data = bf.get_institutions(search='NAME:AMG')
>>> len(data['data'])
5
```
Take it a little further:
```python
>>> data = bf.get_institutions(search='NAME:AMG National')
>>> len(data['data'])
1
```

588
docs/docs/functions.md Normal file
View File

@ -0,0 +1,588 @@
## **get_failures**
=== "Details"
- *Description*: Detail on failed financial institutions
- *Return*: `dict`
- *Arguments*
| Argument | Description | Type | Default | Required | Options |
|:-----------|:-----------------------------------------|:-----------------------------|:----------|:-----------|:--------------------------------------------------------------------------------------|
| filters | Filter(s) for the bank search | `str` | `None` | optional | |
| fields | Comma delimited list of fields to retrieve | `str` | All fields included by default | optional | | |
| sort_by | Field name by which to sort returned data | `str`| `FAILDATE` | optional | See meta_dict
| sort_order | Indicator if ascending or descending | `str` | `DESC` | optional | `ASC`<br>`DESC`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| offset | Offset of page to return | `int` | `0` | optional |
| output | Format of data to return | `str` | `json` | optional | `json`<br>`pandas`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| friendly_fields | Replace keys / column names with friendlier title | `bool` | `False` | optional | `True`<br>`False`
=== "Example"
```python hl_lines="3"
import bankfind as bf
data = bf.get_failures()
data['data'][0]
```
=== "Data"
```python
{
'data': {
'QBFDEP': 139526,
'PSTALP': 'WV',
'FIN': '10536',
'FAILDATE': '04/03/2020',
'RESTYPE': 'FAILURE',
'CITYST': 'BARBOURSVILLE, WV',
'SAVR': 'DIF',
'RESTYPE1': 'PA',
'CHCLASS1': 'NM',
'NAME': 'THE FIRST STATE BANK',
'COST': None,
'QBFASSET': 152400,
'CERT': 14361,
'FAILYR': '2020',
'ID': '4102'
},
'score': 1
}
```
## **get_history**
=== "Details"
- *Description*: Detail on structure change events
- *Return*: `dict`
- *Arguments*
| Argument | Description | Type | Default | Required | Options |
|:-----------|:-----------------------------------------|:-----------------------------|:----------|:-----------|:--------------------------------------------------------------------------------------|
| filters | Filter(s) for the bank search | `str` | `None` | optional | |
| search | Flexible text search against institution records (fuzzy name matching) | `str` | `None` | optional | |
| fields | Comma delimited list of fields to retrieve | `str` | All fields included by default | optional | | |
| sort_by | Field name by which to sort returned data | `str`| `FAILDATE` | optional | See meta_dict
| sort_order | Indicator if ascending or descending | `str` | `DESC` | optional | `ASC`<br>`DESC`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| offset | Offset of page to return | `int` | `0` | optional |
| output | Format of data to return | `str` | `json` | optional | `json`<br>`pandas`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| friendly_fields | Replace keys / column names with friendlier title | `bool` | `False` | optional | `True`<br>`False`
=== "Example"
```python hl_lines="3"
import bankfind as bf
data = bf.get_history()
data['data'][0]
```
=== "Data"
```python
{
'data': {
'REPORT_TYPE': 711,
'INSAGENT1': 'DIF',
'INSAGENT2': '',
'OFF_PCITY': 'Colorado Springs',
'EFFDATE': '2020-07-27T00:00:00',
'CHARTAGENT': 'STATE',
'PSTALP': 'NE',
'CLASS': 'NM',
'FRM_OFF_SERVTYPE': 0,
'OFF_LONGITUDE': -104.87635200138965,
'OFF_PSTATE': 'COLORADO',
'BANK_INSURED': 'Y',
'CNTYNUM': 157,
'INSTNAME': 'First State Bank',
'OFF_PADDR': '3216 W Colorado AVE',
'FRM_CLCODE': 0,
'OFF_SERVTYPE_DESC': 'FULL SERVICE - BRICK AND MORTAR',
'TRANSNUM': 202012234,
'MZIPREST': '0000',
'FDICREGION_DESC': 'KANSAS CITY',
'FRM_OFF_CLCODE': 0,
'PZIP5': '69361',
'OFF_PZIPREST': '1906',
'OFF_NAME': 'First State Bank Colorado Springs West Branch',
'CERT': 15586,
'OFF_PSTALP': 'CO',
'PCITY': 'SCOTTSBLUFF',
'LATITUDE': 0,
'PROCDATE': '2020-08-05T00:00:00',
'ACQDATE': '9999-12-31T00:00:00',
'CHANGECODE': 711,
'PADDR': '2002 BROADWAY',
'MZIP5': '69361',
'FI_UNINUM': 9873,
'LONGITUDE': 0,
'FRM_LATITUDE': 0,
'STATE': 'NEBRASKA',
'MSTALP': 'NE',
'CNTYNAME': 'SCOTTS BLUFF',
'ACQ_UNINUM': 0,
'OFF_CNTYNUM': 41,
'FI_EFFDATE': '2019-06-10T00:00:00',
'FDICREGION': 11,
'MSTATE': 'NEBRASKA',
'FRM_LONGITUDE': 0,
'OFF_CNTYNAME': 'EL PASO',
'CHANGECODE_DESC': 'BRANCH OPENING',
'MCITY': 'SCOTTSBLUFF',
'MADDR': 'P.O. BOX 1267',
'OFF_PZIP5': '80904',
'OUT_UNINUM': 0,
'PZIPREST': '0000',
'ORG_STAT_FLG': 'Y',
'FRM_OFF_LONGITUDE': 0,
'ENDDATE': '9999-12-31T00:00:00',
'UNINUM': 625952,
'OFF_NUM': 6,
'CLCODE': 21,
'OFF_SERVTYPE': 11,
'FRM_OFF_CNTYNUM': 0,
'ORG_ROLE_CDE': 'BR',
'REGAGENT': 'FDIC',
'OFF_LATITUDE': 38.85583298227556,
'ESTDATE': '2020-07-27T00:00:00',
'FRM_OFF_LATITUDE': 0,
'TRUST': 'Full',
'ID': '20eb98a36c7c77cf6bc019ce391ba7c9'
},
'score': 1
}
```
## **get_institutions**
=== "Details"
- *Description*: List of financial institutions
- *Return*: `dict`
- *Arguments*
| Argument | Description | Type | Default | Required | Options |
|:-----------|:-----------------------------------------|:-----------------------------|:----------|:-----------|:--------------------------------------------------------------------------------------|
| filters | Filter(s) for the bank search | `str` | `None` | optional | |
| search | Flexible text search against institution records (fuzzy name matching) | `str` | `None` | optional | |
| fields | Comma delimited list of fields to retrieve | `str` | All fields included by default | optional | | |
| sort_by | Field name by which to sort returned data | `str`| `FAILDATE` | optional | See meta_dict
| sort_order | Indicator if ascending or descending | `str` | `DESC` | optional | `ASC`<br>`DESC`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| offset | Offset of page to return | `int` | `0` | optional |
| output | Format of data to return | `str` | `json` | optional | `json`<br>`pandas`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| friendly_fields | Replace keys / column names with friendlier title | `bool` | `False` | optional | `True`<br>`False`
=== "Example"
```python hl_lines="3"
import bankfind as bf
data = bf.get_institutions()
data['data'][0]
```
=== "Data"
```python
{
'data': {
'ZIP': '31087',
'SASSER': 0,
'CHRTAGNT': 'STATE',
'CONSERVE': 'N',
'REGAGENT2': '',
'STNAME': 'Georgia',
'ROAQ': 0.65,
'INSDATE': '01/01/1934',
'TE06N528': '',
'TE06N529': '',
'OFFOA': 0,
'FDICDBS': '05',
'NAMEHCR': '',
'OCCDIST': '5',
'CMSA': '',
'DEPDOM': 59267,
'CBSA_METRO_FLG': '0',
'TE10N528': '',
'NETINC': 124,
'CBSA_DIV_NO': '',
'MUTUAL': '0',
'MSA_NO': '0',
'OFFFOR': 0,
'INSSAVE': 0,
'CHARTER': '0',
'RSSDHCR': '',
'TE04N528': '',
'TE04N529': '',
'CERT': '10057',
'STALP': 'GA',
'SPECGRP': 7,
'CFPBENDDTE': '31-Dec-9999',
'TE09N528': '',
'IBA': 0,
'INSBIF': 0,
'INSFDIC': 1,
'ENDEFYMD': '12/31/9999',
'MSA': '',
'TE02N528': '',
'CB': '1',
'TE02N529': '',
'TE07N528': '',
'FDICSUPV': 'Atlanta',
'FED': '6',
'REGAGNT': 'FDIC',
'NEWCERT': 0,
'ASSET': 76416,
'CBSA_MICRO_FLG': '1',
'OFFICES': 1,
'STCNTY': '13141',
'CSA_FLG': '0',
'CITY': 'Sparta',
'CLCODE': '21',
'INACTIVE': 0,
'CMSA_NO': '0',
'STALPHCR': '',
'INSAGNT1': 'DIF',
'BKCLASS': 'NM',
'EFFDATE': '08/31/2009',
'SUPRV_FD': '05',
'DATEUPDT': '09/02/2009',
'INSAGNT2': '',
'TE05N528': '',
'TE05N529': '',
'ROEQ': 2.96,
'FDICREGN': 'Atlanta',
'FLDOFF': 'Savannah',
'WEBADDR': 'http://www.bankofhancock.com',
'QBPRCOML': '2',
'COUNTY': 'Hancock',
'DOCKET': '0',
'ULTCERT': '10057',
'OTSDIST': '2',
'LAW_SASSER_FLG': 'N',
'PARCERT': '0',
'ROA': 0.65,
'CFPBFLAG': 0,
'RISDATE': '12/31/2019',
'ROE': 2.96,
'INSCOML': 1,
'OTSREGNM': 'Southeast',
'EQ': '17026',
'RUNDATE': '08/08/2020',
'TE03N528': '',
'TE03N529': '',
'NAME': 'Bank of Hancock County',
'HCTMULT': '',
'CBSA_DIV': '',
'ADDRESS': '12855 Broad Street',
'OFFDOM': 1,
'SUBCHAPS': '0',
'PROCDATE': '09/02/2009',
'INSSAIF': 0,
'DENOVO': '0',
'CBSA_NO': '33300',
'ACTIVE': 1,
'CFPBEFFDTE': '31-Dec-9999',
'STCHRTR': 1,
'REPDTE': '03/31/2020',
'FORM31': '0',
'CSA': '',
'INSDIF': 1,
'TE01N529': '',
'ROAPTX': 0.65,
'STNUM': '13',
'OAKAR': 0,
'SPECGRPN': 'Other Specialized Under 1 Billion',
'ROAPTXQ': 0.65,
'FED_RSSD': '37',
'CSA_NO': '',
'CBSA_METRO': 0,
'INSTCRCD': 0,
'DEP': 59267,
'UNINUM': '6429',
'INSTAG': '0',
'TE01N528': '',
'CITYHCR': '',
'TRACT': '0',
'CBSA': 'Milledgeville, GA',
'CBSA_DIV_FLG': '0',
'TE08N528': '',
'NETINCQ': 124,
'CHANGEC1': 520,
'CERTCONS': '0',
'ESTYMD': '09/01/1904',
'FEDCHRTR': 0,
'TRUST': '0',
'ID': '10057'
},
'score': 1
}
```
## **get_locations**
=== "Details"
- *Description*: Detail on failed financial institutions
- *Return*: `dict`
- *Arguments*
| Argument | Description | Type | Default | Required | Options |
|:-----------|:-----------------------------------------|:-----------------------------|:----------|:-----------|:--------------------------------------------------------------------------------------|
| filters | Filter(s) for the bank search | `str` | `None` | optional | |
| fields | Comma delimited list of fields to retrieve | `str` | All fields included by default | optional | | |
| sort_by | Field name by which to sort returned data | `str`| `FAILDATE` | optional | See meta_dict
| sort_order | Indicator if ascending or descending | `str` | `DESC` | optional | `ASC`<br>`DESC`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| offset | Offset of page to return | `int` | `0` | optional |
| output | Format of data to return | `str` | `json` | optional | `json`<br>`pandas`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| friendly_fields | Replace keys / column names with friendlier title | `bool` | `False` | optional | `True`<br>`False`
=== "Example"
```python hl_lines="3"
import bankfind as bf
data = bf.get_locations()
data['data'][0]
```
=== "Data"
```python
{
'data': {
'ZIP': '21613',
'CBSA_NO': '15700',
'BKCLASS': 'SM',
'FI_UNINUM': 3221,
'STNAME': 'Maryland',
'CSA': 'Salisbury-Cambridge, MD-DE',
'COUNTY': 'Dorchester',
'MAINOFF': 0,
'OFFNAME': 'WOODS ROAD BRANCH',
'CBSA_METRO_FLG': '0',
'CBSA_MICRO_FLG': '1',
'CSA_NO': '480',
'CBSA_METRO': 0,
'CBSA_DIV_NO': '',
'RUNDATE': '08/07/2020',
'NAME': '1880 Bank',
'UNINUM': 204568,
'SERVTYPE': 11,
'CSA_FLG': '1',
'STCNTY': '24019',
'CBSA': 'Cambridge, MD',
'CBSA_DIV': '',
'CBSA_DIV_FLG': '0',
'CITY': 'Cambridge',
'ADDRESS': '803 Woods Road',
'CERT': '4829',
'STALP': 'MD',
'OFFNUM': 1,
'ESTYMD': '12/23/1968',
'ID': '204568'
},
'score': 1
}
```
## **get_summary**
=== "Details"
- *Description*: Detail on failed financial institutions
- *Return*: `dict`
- *Arguments*
| Argument | Description | Type | Default | Required | Options |
|:-----------|:-----------------------------------------|:-----------------------------|:----------|:-----------|:--------------------------------------------------------------------------------------|
| filters | Filter(s) for the bank search | `str` | `None` | optional | |
| fields | Comma delimited list of fields to retrieve | `str` | All fields included by default | optional | | |
| sort_by | Field name by which to sort returned data | `str`| `FAILDATE` | optional | See meta_dict
| sort_order | Indicator if ascending or descending | `str` | `DESC` | optional | `ASC`<br>`DESC`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| offset | Offset of page to return | `int` | `0` | optional |
| output | Format of data to return | `str` | `json` | optional | `json`<br>`pandas`
| limit | Number of records to return | `int` | `10000` | optional | 0 to 10,000
| friendly_fields | Replace keys / column names with friendlier title | `bool` | `False` | optional | `True`<br>`False`
=== "Example"
```python hl_lines="3"
import bankfind as bf
data = bf.get_failures()
data['data'][0]
```
=== "Data"
```python
{
'data': {
'INTINC2': 51722726,
'EXTRA': 1316,
'LNATRES': 9769341,
'chrtrest': 0,
'STNAME': 'United States and Other Areas',
'ILNS': 39718788,
'LNAG': 3306388,
'EINTEXP2': 10348941,
'EPREMAGG': 2063405,
'YEAR': '2019',
'BKPREM': 8315925,
'INTAN': 12025281,
'LNRE': 444072342,
'chartoth': 1,
'IGLSEC': 482482,
'OT_BIF': 0,
'EAMINTAN': 456598,
'newcount': 0,
'DEPI': 840535976,
'EFHLBADV': None,
'tofail': 1,
'SCMTGBK': 292023664,
'NTRTMLG': 118177154,
'OEA': 1483578,
'EFREPP': 90846,
'LNLSGR': 655127513,
'NETINC': 15194171,
'TOT_OTS': 334,
'CONS': 0,
'OTHNBORR': 91479748,
'LNREMULT': 68529412,
'P9LNLS': 7463014,
'COUNT': 659,
'LNRERES': 253541537,
'EQCS': 790384,
'SCAGE': 304050945,
'LNRECONS': 23453492,
'TOT_FDIC': 325,
'EINTEXP': 10348941,
'TPD': 13656751,
'LNCI': 43378018,
'EQNM': 125002942,
'INTBLIB': 1007906756,
'liqasstd': 0,
'SC': 385021771,
'INTBAST': 1096557030,
'EDEPDOM': 8287049,
'ILNDOM': 39718603,
'NCLNLS': 11414221,
'UNINC': 133264,
'ISC': 10339424,
'LIABEQ': 1153906385,
'tochrt': 7,
'IFEE': 865589,
'TOT_SAVE': 659,
'LNRESRE': None,
'alsonew': 0,
'NUMEMP': 121746,
'ASSET': 1153906405,
'TINTINC': 11723463,
'NALNLS': 3951207,
'EOTHNINT': 14513593,
'TRADES': 0,
'ESAL': 12889946,
'ILNLS': 39999263,
'LIAB': 1028873691,
'LNDEP': 417597,
'OTHBFHLB': 75972627,
'ITAX': 4361954,
'EQCDIVP': 12402,
'SCRES': None,
'TRADE': 356945,
'MISSADJ': -1,
'FD_BIF': 0,
'CRLNLS': 1422110,
'LS': 5575099,
'tomerg': 11,
'ELNATR': 5247975,
'LNCRCD': 99551689,
'INTINC': 51722726,
'EQUPTOT': 70024149,
'CHBALI': 64693509,
'EQPP': 282890,
'PTXNOINC': 19078526,
'OINTINC': 11723463,
'tortc': 0,
'ILS': 280475,
'FD_SAIF': 0,
'EQNWCERT': None,
'OINTBOR': 85304294,
'SCUST': 12170713,
'combos': 12,
'P3LNLS': 6193737,
'OTLNCNTA': None,
'OTHLIAB': 16342193,
'IFREPO': 18439,
'LNLSNET': 645358172,
'LNCONOT1': None,
'EQCDIVC': 13089203,
'SCUSA': 316221658,
'DRLNLS': 7211296,
'OTHBORR': 1685904,
'EQCDIV': 13101605,
'EDEP': 8287065,
'BRWDMONY': 1685904,
'comboass': 0,
'FREPO': 1126633,
'CHBAL': 73009001,
'ALLOTHER': 14950385,
'FREPP': 6067807,
'IRAKEOGH': 123424709,
'OT_SAIF': 0,
'ORE': 302690,
'SCMUNI': 10308292,
'ESUBND': 278,
'SCUS': 316221658,
'ITRADE': 0,
'OINTEXP': 1777028,
'liqunass': 1,
'DDT': 58550380,
'EDEPFOR': 16,
'LNALLOTH': 42378773,
'SCEQ': 258574,
'ITAXR': 19078526,
'ILNFOR': 185,
'ICHBAL': 1365600,
'LNRELOC': 21179492,
'STNUM': '0',
'SUBLLPF': 26052,
'OONONII': 11554071,
'CORPBNDS': 55721897,
'NONIX': 29466944,
'NCHGREC': 5789186,
'OTHASST': 28389467,
'DEP': 921025698,
'NIM': 41373785,
'LNCON': 141930462,
'EQSUR': 53905519,
'SAVINGS': 659,
'ORET': 302690,
'CB_SI': 'SI',
'TOINTEXP': 2061876,
'LNMUNI': 1630491,
'LNRENRES': 98547901,
'NONII': 12419660,
'BRO': 104643398,
'ID': 'SI_2019_0'
},
'score': 1
}
```

BIN
docs/docs/img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
docs/docs/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

75
docs/docs/index.md Normal file
View File

@ -0,0 +1,75 @@
<p align="center">
<a href="#"><img src="img/logo.png"></a>
</p>
<p align="center">
<em>Python interface to the FDIC's API for publically available bank data</em>
</p>
<p align="center">
<a href="https://travis-ci.com/dpguthrie/bankfind" target="_blank">
<img src="https://travis-ci.com/dpguthrie/bankfind.svg?branch=master" alt="Build Status">
</a>
<a href="https://codecov.io/gh/dpguthrie/bankfind" target="_blank">
<img src="https://img.shields.io/codecov/c/github/dpguthrie/bankfind" alt="Coverage">
</a>
<a href="https://pypi.org/project/bankfind" target="_blank">
<img src="https://badge.fury.io/py/bankfind.svg" alt="Package version">
</a>
</p>
---
**Documentation**: <a target="_blank" href="https://bankfind.dpguthrie.com">https://bankfind.dpguthrie.com</a>
<!-- **Interactive Demo**: <a target="_blank" href="https://bankfind-streamlit.dpguthrie.com">https://bankfind-streamlit.herokuapp.com</a> -->
**Source Code**: <a target="_blank" href="https://github.com/dpguthrie/bankfind">https://github.com/dpguthrie/bankfind</a>
**FDIC Documentation**: <a target="_blank" href="https://banks.data.fdic.gov/docs/">https://banks.data.fdic.gov/docs/</a>
---
## Overview
**bankfind** is a python interface to publically available bank data from the FDIC.
There are currently, as of 8/11/20, five endpoints that the FDIC has exposed to the public:
- **failures** - returns detail on failed financial institutions
- **institutions** - returns a list of financial institutions
- **history** - returns detail on structure change events
- **locations** - returns locations / branches of financial institutions
- **summary** - returns aggregate financial and structure data, subtotaled by year, regarding financial institutions
## Requirements
Python 2.7, 3.5+
- [Requests](https://requests.readthedocs.io/en/master/) - The elegant and simple HTTP library for Python, built for human beings.
## Installation
<div class="termynal" data-termynal data-ty-typeDelay="40" data-ty-lineDelay="700">
<span data-ty="input">pip install bankfind</span>
<span data-ty="progress"></span>
<span data-ty>Successfully installed bankfind</span>
<a href="#" data-terminal-control="">restart ↻</a>
</div>
## Example
```python
import bankfind as bf
# Get Institutions
data = bf.get_institutions()
# Get Institutions from Colorado with high ROE
data = bf.get_institutions(filters="STNAME:Colorado AND ROE:[25 TO *]")
# Get Commercial Banks from Colorado that aren't S-Corps
data = bf.get_institutions(filters="STNAME:Colorado AND SUBCHAPS:0 AND CB:1")
```
## License
This project is licensed under the terms of the MIT license.

149
docs/docs/js/custom.js Normal file
View File

@ -0,0 +1,149 @@
const div = document.querySelector('.github-topic-projects')
async function getDataBatch(page) {
const response = await fetch(`https://api.github.com/search/repositories?q=topic:bankfind&per_page=100&page=${page}`, { headers: { Accept: 'application/vnd.github.mercy-preview+json' } })
const data = await response.json()
return data
}
async function getData() {
let page = 1
let data = []
let dataBatch = await getDataBatch(page)
data = data.concat(dataBatch.items)
const totalCount = dataBatch.total_count
while (data.length < totalCount) {
page += 1
dataBatch = await getDataBatch(page)
data = data.concat(dataBatch.items)
}
return data
}
function setupTermynal() {
document.querySelectorAll(".termynal").forEach(node => {
node.style.display = "block";
new Termynal(node, {
lineDelay: 500
});
});
const progressLiteralStart = "---> 100%";
const promptLiteralStart = "$ ";
const customPromptLiteralStart = "# ";
const termynalActivateClass = "termy";
let termynals = [];
function createTermynals() {
document
.querySelectorAll(`.${termynalActivateClass} .highlight`)
.forEach(node => {
const text = node.textContent;
const lines = text.split("\n");
const useLines = [];
let buffer = [];
function saveBuffer() {
if (buffer.length) {
let isBlankSpace = true;
buffer.forEach(line => {
if (line) {
isBlankSpace = false;
}
});
dataValue = {};
if (isBlankSpace) {
dataValue["delay"] = 0;
}
if (buffer[buffer.length - 1] === "") {
// A last single <br> won't have effect
// so put an additional one
buffer.push("");
}
const bufferValue = buffer.join("<br>");
dataValue["value"] = bufferValue;
useLines.push(dataValue);
buffer = [];
}
}
for (let line of lines) {
if (line === progressLiteralStart) {
saveBuffer();
useLines.push({
type: "progress"
});
} else if (line.startsWith(promptLiteralStart)) {
saveBuffer();
const value = line.replace(promptLiteralStart, "").trimEnd();
useLines.push({
type: "input",
value: value
});
} else if (line.startsWith("// ")) {
saveBuffer();
const value = "💬 " + line.replace("// ", "").trimEnd();
useLines.push({
value: value,
class: "termynal-comment",
delay: 0
});
} else if (line.startsWith(customPromptLiteralStart)) {
saveBuffer();
const promptStart = line.indexOf(promptLiteralStart);
if (promptStart === -1) {
console.error("Custom prompt found but no end delimiter", line)
}
const prompt = line.slice(0, promptStart).replace(customPromptLiteralStart, "")
let value = line.slice(promptStart + promptLiteralStart.length);
useLines.push({
type: "input",
value: value,
prompt: prompt
});
} else {
buffer.push(line);
}
}
saveBuffer();
const div = document.createElement("div");
node.replaceWith(div);
const termynal = new Termynal(div, {
lineData: useLines,
noInit: true,
lineDelay: 500
});
termynals.push(termynal);
});
}
function loadVisibleTermynals() {
termynals = termynals.filter(termynal => {
if (termynal.container.getBoundingClientRect().top - innerHeight <= 0) {
termynal.init();
return false;
}
return true;
});
}
window.addEventListener("scroll", loadVisibleTermynals);
createTermynals();
loadVisibleTermynals();
}
async function main() {
if (div) {
data = await getData()
div.innerHTML = '<ul></ul>'
const ul = document.querySelector('.github-topic-projects ul')
data.forEach(v => {
if (v.full_name === 'dpguthrie/bankfind') {
return
}
const li = document.createElement('li')
li.innerHTML = `<a href="${v.html_url}" target="_blank">★ ${v.stargazers_count} - ${v.full_name}</a> by <a href="${v.owner.html_url}" target="_blank">@${v.owner.login}</a>`
ul.append(li)
})
}
setupTermynal();
}
main()

263
docs/docs/js/termynal.js Normal file
View File

@ -0,0 +1,263 @@
/**
* termynal.js
* A lightweight, modern and extensible animated terminal window, using
* async/await.
*
* @author Ines Montani <ines@ines.io>
* @version 0.0.1
* @license MIT
*/
'use strict';
/** Generate a terminal widget. */
class Termynal {
/**
* Construct the widget's settings.
* @param {(string|Node)=} container - Query selector or container element.
* @param {Object=} options - Custom settings.
* @param {string} options.prefix - Prefix to use for data attributes.
* @param {number} options.startDelay - Delay before animation, in ms.
* @param {number} options.typeDelay - Delay between each typed character, in ms.
* @param {number} options.lineDelay - Delay between each line, in ms.
* @param {number} options.progressLength - Number of characters displayed as progress bar.
* @param {string} options.progressChar Character to use for progress bar, defaults to .
* @param {number} options.progressPercent - Max percent of progress.
* @param {string} options.cursor Character to use for cursor, defaults to .
* @param {Object[]} lineData - Dynamically loaded line data objects.
* @param {boolean} options.noInit - Don't initialise the animation.
*/
constructor(container = '#termynal', options = {}) {
this.container = (typeof container === 'string') ? document.querySelector(container) : container;
this.pfx = `data-${options.prefix || 'ty'}`;
this.originalStartDelay = this.startDelay = options.startDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-startDelay`)) || 600;
this.originalTypeDelay = this.typeDelay = options.typeDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-typeDelay`)) || 90;
this.originalLineDelay = this.lineDelay = options.lineDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-lineDelay`)) || 1500;
this.progressLength = options.progressLength
|| parseFloat(this.container.getAttribute(`${this.pfx}-progressLength`)) || 40;
this.progressChar = options.progressChar
|| this.container.getAttribute(`${this.pfx}-progressChar`) || '█';
this.progressPercent = options.progressPercent
|| parseFloat(this.container.getAttribute(`${this.pfx}-progressPercent`)) || 100;
this.cursor = options.cursor
|| this.container.getAttribute(`${this.pfx}-cursor`) || '▋';
this.lineData = this.lineDataToElements(options.lineData || []);
this.loadLines()
if (!options.noInit) this.init()
}
loadLines() {
// Load all the lines and create the container so that the size is fixed
// Otherwise it would be changing and the user viewport would be constantly
// moving as she/he scrolls
const finish = this.generateFinish()
finish.style.visibility = 'hidden'
this.container.appendChild(finish)
// Appends dynamically loaded lines to existing line elements.
this.lines = [...this.container.querySelectorAll(`[${this.pfx}]`)].concat(this.lineData);
for (let line of this.lines) {
line.style.visibility = 'hidden'
this.container.appendChild(line)
}
const restart = this.generateRestart()
restart.style.visibility = 'hidden'
this.container.appendChild(restart)
this.container.setAttribute('data-termynal', '');
}
/**
* Initialise the widget, get lines, clear container and start animation.
*/
init() {
/**
* Calculates width and height of Termynal container.
* If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS.
*/
const containerStyle = getComputedStyle(this.container);
this.container.style.width = containerStyle.width !== '0px' ?
containerStyle.width : undefined;
this.container.style.minHeight = containerStyle.height !== '0px' ?
containerStyle.height : undefined;
this.container.setAttribute('data-termynal', '');
this.container.innerHTML = '';
for (let line of this.lines) {
line.style.visibility = 'visible'
}
this.start();
}
/**
* Start the animation and rener the lines depending on their data attributes.
*/
async start() {
this.addFinish()
await this._wait(this.startDelay);
for (let line of this.lines) {
const type = line.getAttribute(this.pfx);
const delay = line.getAttribute(`${this.pfx}-delay`) || this.lineDelay;
if (type == 'input') {
line.setAttribute(`${this.pfx}-cursor`, this.cursor);
await this.type(line);
await this._wait(delay);
}
else if (type == 'progress') {
await this.progress(line);
await this._wait(delay);
}
else {
this.container.appendChild(line);
await this._wait(delay);
}
line.removeAttribute(`${this.pfx}-cursor`);
}
this.addRestart()
this.finishElement.style.visibility = 'hidden'
this.lineDelay = this.originalLineDelay
this.typeDelay = this.originalTypeDelay
this.startDelay = this.originalStartDelay
}
generateRestart() {
const restart = document.createElement('a')
restart.onclick = (e) => {
e.preventDefault()
this.container.innerHTML = ''
this.init()
}
restart.href = '#'
restart.setAttribute('data-terminal-control', '')
restart.innerHTML = "restart ↻"
return restart
}
generateFinish() {
const finish = document.createElement('a')
finish.onclick = (e) => {
e.preventDefault()
this.lineDelay = 0
this.typeDelay = 0
this.startDelay = 0
}
finish.href = '#'
finish.setAttribute('data-terminal-control', '')
this.finishElement = finish
return finish
}
addRestart() {
const restart = this.generateRestart()
this.container.appendChild(restart)
}
addFinish() {
const finish = this.generateFinish()
this.container.appendChild(finish)
}
/**
* Animate a typed line.
* @param {Node} line - The line element to render.
*/
async type(line) {
const chars = [...line.textContent];
line.textContent = '';
this.container.appendChild(line);
for (let char of chars) {
const delay = line.getAttribute(`${this.pfx}-typeDelay`) || this.typeDelay;
await this._wait(delay);
line.textContent += char;
}
}
/**
* Animate a progress bar.
* @param {Node} line - The line element to render.
*/
async progress(line) {
const progressLength = line.getAttribute(`${this.pfx}-progressLength`)
|| this.progressLength;
const progressChar = line.getAttribute(`${this.pfx}-progressChar`)
|| this.progressChar;
const chars = progressChar.repeat(progressLength);
const progressPercent = line.getAttribute(`${this.pfx}-progressPercent`)
|| this.progressPercent;
line.textContent = '';
this.container.appendChild(line);
for (let i = 1; i < chars.length + 1; i++) {
await this._wait(this.typeDelay);
const percent = Math.round(i / chars.length * 100);
line.textContent = `${chars.slice(0, i)} ${percent}%`;
if (percent>progressPercent) {
break;
}
}
}
/**
* Helper function for animation delays, called with `await`.
* @param {number} time - Timeout, in ms.
*/
_wait(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
/**
* Converts line data objects into line elements.
*
* @param {Object[]} lineData - Dynamically loaded lines.
* @param {Object} line - Line data object.
* @returns {Element[]} - Array of line elements.
*/
lineDataToElements(lineData) {
return lineData.map(line => {
let div = document.createElement('div');
div.innerHTML = `<span ${this._attributes(line)}>${line.value || ''}</span>`;
return div.firstElementChild;
});
}
/**
* Helper function for generating attributes string.
*
* @param {Object} line - Line data object.
* @returns {string} - String of attributes.
*/
_attributes(line) {
let attrs = '';
for (let prop in line) {
// Custom add class
if (prop === 'class') {
attrs += ` class=${line[prop]} `
continue
}
if (prop === 'type') {
attrs += `${this.pfx}="${line[prop]}" `
} else if (prop !== 'value') {
attrs += `${this.pfx}-${prop}="${line[prop]}" `
}
}
return attrs;
}
}
/**
* HTML API: If current script has container(s) specified, initialise Termynal.
*/
if (document.currentScript.hasAttribute('data-termynal-container')) {
const containers = document.currentScript.getAttribute('data-termynal-container');
containers.split('|')
.forEach(container => new Termynal(container))
}

View File

63
docs/mkdocs.yml Normal file
View File

@ -0,0 +1,63 @@
# Project Information
site_name: bankfind
site_description: Python wrapper allowing developers access to the FDICs publically available bank data
site_author: Doug Guthrie
# Repository
repo_name: bankfind
repo_url: https://github.com/dpguthrie/bankfind
# Configuration
theme:
name: material
palette:
primary: black
icon:
repo: fontawesome/brands/github-alt
logo: img/small_logo.png
favicon: img/favicon.png
language: en
# Extras
extra:
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/dpguthrie
- icon: fontawesome/brands/linkedin
link: https://www.linkedin.com/in/douglas-guthrie-07994a48/
- icon: fontawesome/brands/medium
link: https://medium.com/@douglas.p.guthrie
- icon: fontawesome/solid/globe
link: https://dpguthrie.com
extra_css:
- css/termynal.css
extra_javascript:
- js/termynal.js
- js/custom.js
# Extensions
markdown_extensions:
- admonition
- codehilite:
guess_lang: false
- toc:
permalink: true
- pymdownx.superfences
- pymdownx.tabbed
- pymdownx.details
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
# Google Analytics
google_analytics:
- UA-175202147-1
- auto
nav:
- index.md
- functions.md
- filtering.md
- release_notes.md

43
pyproject.toml Normal file
View File

@ -0,0 +1,43 @@
[build-system]
requires = ["flit_core >=2,<4"]
build-backend = "flit_core.buildapi"
[tool.flit.metadata]
module = "bankfind"
author = "Doug Guthrie"
author-email = "douglas.p.guthrie@gmail.com"
home-page = "https://github.com/dpguthrie/bankfind"
keywords = "banking, finance, fdic, api, requests"
requires-python="2.7,>=3.5"
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Intended Audience :: Financial and Insurance Industry",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
]
requires = [
"requests == 2.24.0",
"pandas>=0.24"
]
description-file = "README.md"
[tool.flit.metadata.requires-extra]
test = [
'pytest',
'coverage',
'pytest-cov'
]
doc = [
'mkdocs-material',
'pymdown-extensions'
]
[tool.flit.metadata.urls]
Documentation = "https://bankfind.dpguthrie.com"

10
pytest.ini Normal file
View File

@ -0,0 +1,10 @@
[pytest]
testpaths =
tests
bankfind
norecursedirs=dist build .venv .vscode demo
addopts =
--doctest-modules
--cov=bankfind
-r a
-v

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
pandas>=0.24
requests=2.24.0

0
tests/__init__.py Normal file
View File

46
tests/test_functions.py Normal file
View File

@ -0,0 +1,46 @@
import bankfind as bf
def test_institutions():
data = bf.get_institutions(
filters="STALP:CO AND ACTIVE:1",
search="NAME: AMG",
)
assert len(data['data']) == 1
def test_locations():
data = bf.get_locations(
filters="CERT:57295"
)
assert len(data['data']) >= 7
def test_history():
data = bf.get_history(
filters="CERT:57295",
output='pandas',
friendly_fields=True
)
assert len(data) >= 18
def test_summary():
df = bf.get_summary(
filters='CB_SI:CB AND ASSET:[10000000000 TO *] AND YEAR:["2018" TO "2019"]',
output='pandas')
assert len(df) >= 4
def test_failures():
data = bf.get_failures(
filters='PSTALP:CO AND FAILYR:["2008" TO "2011"]',
sort_by='COST',
sort_order='DESC',
friendly_fields=True)
assert len(data['data']) == 9
def test_bad_request():
response = bf.get_institutions(sort_by="BAD_SORT_BY_FIELD")
assert response.status_code == 400