├── tabela_sac ├── __init__.py ├── _modidx.py ├── cli.py └── core.py ├── MANIFEST.in ├── nbs ├── sidebar.yml ├── nbdev.yml ├── _quarto.yml ├── styles.css ├── 02_cli.ipynb ├── 01_what_is_sac.ipynb ├── 00_core.ipynb └── index.ipynb ├── .github └── workflows │ ├── test.yaml │ └── deploy.yaml ├── settings.ini ├── .gitignore ├── setup.py ├── README.md └── LICENSE /tabela_sac/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "2.0.0" 2 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include settings.ini 2 | include LICENSE 3 | include CONTRIBUTING.md 4 | include README.md 5 | recursive-exclude * __pycache__ 6 | -------------------------------------------------------------------------------- /nbs/sidebar.yml: -------------------------------------------------------------------------------- 1 | website: 2 | sidebar: 3 | contents: 4 | - index.ipynb 5 | - 00_core.ipynb 6 | - 01_what_is_sac.ipynb 7 | - 02_cli.ipynb 8 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [workflow_dispatch, pull_request, push] 3 | 4 | jobs: 5 | test: 6 | runs-on: ubuntu-latest 7 | steps: [uses: fastai/workflows/nbdev-ci@master] 8 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | on: 3 | push: 4 | branches: [ "main", "master" ] 5 | workflow_dispatch: 6 | jobs: 7 | deploy: 8 | runs-on: ubuntu-latest 9 | steps: [uses: fastai/workflows/quarto-ghp@master] 10 | -------------------------------------------------------------------------------- /nbs/nbdev.yml: -------------------------------------------------------------------------------- 1 | project: 2 | output-dir: _docs 3 | 4 | website: 5 | title: "tabela-sac" 6 | site-url: "https://joaopcnogueira.github.io/tabela-sac" 7 | description: "Forma Simples de Gerar uma Tabela SAC" 8 | repo-branch: main 9 | repo-url: "https://github.com/joaopcnogueira/tabela-sac" 10 | -------------------------------------------------------------------------------- /nbs/_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: website 3 | 4 | format: 5 | html: 6 | theme: cosmo 7 | css: styles.css 8 | toc: true 9 | 10 | website: 11 | twitter-card: true 12 | open-graph: true 13 | repo-actions: [issue] 14 | navbar: 15 | background: primary 16 | search: true 17 | sidebar: 18 | style: floating 19 | 20 | metadata-files: [nbdev.yml, sidebar.yml] -------------------------------------------------------------------------------- /nbs/styles.css: -------------------------------------------------------------------------------- 1 | .cell { 2 | margin-bottom: 1rem; 3 | } 4 | 5 | .cell > .sourceCode { 6 | margin-bottom: 0; 7 | } 8 | 9 | .cell-output > pre { 10 | margin-bottom: 0; 11 | } 12 | 13 | .cell-output > pre, .cell-output > .sourceCode > pre, .cell-output-stdout > pre { 14 | margin-left: 0.8rem; 15 | margin-top: 0; 16 | background: none; 17 | border-left: 2px solid lightsalmon; 18 | border-top-left-radius: 0; 19 | border-top-right-radius: 0; 20 | } 21 | 22 | .cell-output > .sourceCode { 23 | border: none; 24 | } 25 | 26 | .cell-output > .sourceCode { 27 | background: none; 28 | margin-top: 0; 29 | } 30 | 31 | div.description { 32 | padding-left: 2px; 33 | padding-top: 5px; 34 | font-style: italic; 35 | font-size: 135%; 36 | opacity: 70%; 37 | } 38 | -------------------------------------------------------------------------------- /settings.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | repo = tabela-sac 3 | lib_name = tabela-sac 4 | version = 2.0.0 5 | min_python = 3.7 6 | license = apache2 7 | doc_path = _docs 8 | lib_path = tabela_sac 9 | nbs_path = nbs 10 | recursive = True 11 | tst_flags = notest 12 | put_version_in_init = True 13 | branch = main 14 | custom_sidebar = False 15 | doc_host = https://joaopcnogueira.github.io 16 | doc_baseurl = /tabela-sac 17 | git_url = https://github.com/joaopcnogueira/tabela-sac 18 | title = tabela-sac 19 | audience = Developers 20 | author = João Paulo Nogueira 21 | author_email = joaopcnogueira@gmail.com 22 | copyright = 2022 onwards, João Paulo Nogueira 23 | description = Forma Simples de Gerar uma Tabela SAC 24 | keywords = nbdev jupyter notebook python 25 | language = English 26 | status = 3 27 | user = joaopcnogueira 28 | requirements = fastcore pandas 29 | dev_requirements = jupyter 30 | console_scripts = gerar_tabela_sac=tabela_sac.cli:gerar_tabela_sac 31 | black_formatting = False 32 | readme_nb = index.ipynb 33 | allowed_metadata_keys = 34 | allowed_cell_metadata_keys = 35 | jupyter_hooks = True 36 | clean_ids = True 37 | clear_all = False 38 | 39 | -------------------------------------------------------------------------------- /tabela_sac/_modidx.py: -------------------------------------------------------------------------------- 1 | # Autogenerated by nbdev 2 | 3 | d = { 'settings': { 'branch': 'main', 4 | 'doc_baseurl': '/tabela-sac', 5 | 'doc_host': 'https://joaopcnogueira.github.io', 6 | 'git_url': 'https://github.com/joaopcnogueira/tabela-sac', 7 | 'lib_path': 'tabela_sac'}, 8 | 'syms': { 'tabela_sac.cli': { 'tabela_sac.cli.gerar_tabela_sac': ('cli.html#gerar_tabela_sac', 'tabela_sac/cli.py'), 9 | 'tabela_sac.cli.install_package': ('cli.html#install_package', 'tabela_sac/cli.py')}, 10 | 'tabela_sac.core': { 'tabela_sac.core.SACCalculator': ('core.html#saccalculator', 'tabela_sac/core.py'), 11 | 'tabela_sac.core.SACCalculator.__init__': ('core.html#saccalculator.__init__', 'tabela_sac/core.py'), 12 | 'tabela_sac.core.SACCalculator.amortizacao_extra_mensal': ( 'core.html#saccalculator.amortizacao_extra_mensal', 13 | 'tabela_sac/core.py'), 14 | 'tabela_sac.core.SACCalculator.tabela': ('core.html#saccalculator.tabela', 'tabela_sac/core.py')}}} 15 | -------------------------------------------------------------------------------- /tabela_sac/cli.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_cli.ipynb. 2 | 3 | # %% auto 0 4 | __all__ = ['gerar_tabela_sac', 'install_package'] 5 | 6 | # %% ../nbs/02_cli.ipynb 2 7 | import os 8 | from fastcore.script import call_parse 9 | from .core import SACCalculator 10 | 11 | # %% ../nbs/02_cli.ipynb 3 12 | @call_parse 13 | def gerar_tabela_sac(valor_financiado:float, # Valor financiado 14 | prazo:int, # Prazo em meses 15 | taxa_juros:float, # Taxa de juros ao mês (ex: 0.01 para uma taxa de 1% ao mês) 16 | path:str='.' 17 | ): 18 | "Gera a tabela SAC para o valor financiado, prazo e taxa de juros informados." 19 | 20 | sac = SACCalculator(valor_financiado, prazo, taxa_juros) 21 | tabela = sac.tabela() 22 | 23 | try: 24 | tabela.to_csv(f'{path}/tabela_sac.csv', sep=';', index=False) 25 | return f"Tabela gerada com sucesso! Path: {path}/tabela_sac.csv" 26 | except: 27 | raise Exception(f"Não foi possível gerar a tabela. Verifique os parâmetros informados.") 28 | 29 | # %% ../nbs/02_cli.ipynb 5 30 | @call_parse 31 | def install_package(): 32 | "Install the package" 33 | os.system("pip install -e '.[dev]'") 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _docs/ 2 | _proc/ 3 | 4 | *.bak 5 | .gitattributes 6 | .last_checked 7 | .gitconfig 8 | *.bak 9 | *.log 10 | *~ 11 | ~* 12 | _tmp* 13 | tmp* 14 | tags 15 | *.pkg 16 | 17 | # Byte-compiled / optimized / DLL files 18 | __pycache__/ 19 | *.py[cod] 20 | *$py.class 21 | 22 | # C extensions 23 | *.so 24 | 25 | # Distribution / packaging 26 | .Python 27 | env/ 28 | build/ 29 | develop-eggs/ 30 | dist/ 31 | downloads/ 32 | eggs/ 33 | .eggs/ 34 | lib/ 35 | lib64/ 36 | parts/ 37 | sdist/ 38 | var/ 39 | wheels/ 40 | *.egg-info/ 41 | .installed.cfg 42 | *.egg 43 | 44 | # PyInstaller 45 | # Usually these files are written by a python script from a template 46 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 47 | *.manifest 48 | *.spec 49 | 50 | # Installer logs 51 | pip-log.txt 52 | pip-delete-this-directory.txt 53 | 54 | # Unit test / coverage reports 55 | htmlcov/ 56 | .tox/ 57 | .coverage 58 | .coverage.* 59 | .cache 60 | nosetests.xml 61 | coverage.xml 62 | *.cover 63 | .hypothesis/ 64 | 65 | # Translations 66 | *.mo 67 | *.pot 68 | 69 | # Django stuff: 70 | *.log 71 | local_settings.py 72 | 73 | # Flask stuff: 74 | instance/ 75 | .webassets-cache 76 | 77 | # Scrapy stuff: 78 | .scrapy 79 | 80 | # Sphinx documentation 81 | docs/_build/ 82 | 83 | # PyBuilder 84 | target/ 85 | 86 | # Jupyter Notebook 87 | .ipynb_checkpoints 88 | 89 | # pyenv 90 | .python-version 91 | 92 | # celery beat schedule file 93 | celerybeat-schedule 94 | 95 | # SageMath parsed files 96 | *.sage.py 97 | 98 | # dotenv 99 | .env 100 | 101 | # virtualenv 102 | .venv 103 | venv/ 104 | ENV/ 105 | 106 | # Spyder project settings 107 | .spyderproject 108 | .spyproject 109 | 110 | # Rope project settings 111 | .ropeproject 112 | 113 | # mkdocs documentation 114 | /site 115 | 116 | # mypy 117 | .mypy_cache/ 118 | 119 | .vscode 120 | *.swp 121 | 122 | # osx generated files 123 | .DS_Store 124 | .DS_Store? 125 | .Trashes 126 | ehthumbs.db 127 | Thumbs.db 128 | .idea 129 | 130 | # pytest 131 | .pytest_cache 132 | 133 | # tools/trust-doc-nbs 134 | docs_src/.last_checked 135 | 136 | # symlinks to fastai 137 | docs_src/fastai 138 | tools/fastai 139 | 140 | # link checker 141 | checklink/cookies.txt 142 | 143 | # .gitconfig is now autogenerated 144 | .gitconfig 145 | 146 | # Quarto installer 147 | .deb 148 | .pkg 149 | 150 | # Quarto 151 | .quarto 152 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from pkg_resources import parse_version 2 | from configparser import ConfigParser 3 | import setuptools 4 | assert parse_version(setuptools.__version__)>=parse_version('36.2') 5 | 6 | # note: all settings are in settings.ini; edit there, not here 7 | config = ConfigParser(delimiters=['=']) 8 | config.read('settings.ini') 9 | cfg = config['DEFAULT'] 10 | 11 | cfg_keys = 'version description keywords author author_email'.split() 12 | expected = cfg_keys + "lib_name user branch license status min_python audience language".split() 13 | for o in expected: assert o in cfg, "missing expected setting: {}".format(o) 14 | setup_cfg = {o:cfg[o] for o in cfg_keys} 15 | 16 | licenses = { 17 | 'apache2': ('Apache Software License 2.0','OSI Approved :: Apache Software License'), 18 | 'mit': ('MIT License', 'OSI Approved :: MIT License'), 19 | 'gpl2': ('GNU General Public License v2', 'OSI Approved :: GNU General Public License v2 (GPLv2)'), 20 | 'gpl3': ('GNU General Public License v3', 'OSI Approved :: GNU General Public License v3 (GPLv3)'), 21 | 'bsd3': ('BSD License', 'OSI Approved :: BSD License'), 22 | } 23 | statuses = [ '1 - Planning', '2 - Pre-Alpha', '3 - Alpha', 24 | '4 - Beta', '5 - Production/Stable', '6 - Mature', '7 - Inactive' ] 25 | py_versions = '3.6 3.7 3.8 3.9 3.10'.split() 26 | 27 | requirements = cfg.get('requirements','').split() 28 | if cfg.get('pip_requirements'): requirements += cfg.get('pip_requirements','').split() 29 | min_python = cfg['min_python'] 30 | lic = licenses.get(cfg['license'].lower(), (cfg['license'], None)) 31 | dev_requirements = (cfg.get('dev_requirements') or '').split() 32 | 33 | setuptools.setup( 34 | name = cfg['lib_name'], 35 | license = lic[0], 36 | classifiers = [ 37 | 'Development Status :: ' + statuses[int(cfg['status'])], 38 | 'Intended Audience :: ' + cfg['audience'].title(), 39 | 'Natural Language :: ' + cfg['language'].title(), 40 | ] + ['Programming Language :: Python :: '+o for o in py_versions[py_versions.index(min_python):]] + (['License :: ' + lic[1] ] if lic[1] else []), 41 | url = cfg['git_url'], 42 | packages = setuptools.find_packages(), 43 | include_package_data = True, 44 | install_requires = requirements, 45 | extras_require={ 'dev': dev_requirements }, 46 | dependency_links = cfg.get('dep_links','').split(), 47 | python_requires = '>=' + cfg['min_python'], 48 | long_description = open('README.md').read(), 49 | long_description_content_type = 'text/markdown', 50 | zip_safe = False, 51 | entry_points = { 52 | 'console_scripts': cfg.get('console_scripts','').split(), 53 | 'nbdev': [f'{cfg.get("lib_path")}={cfg.get("lib_path")}._modidx:d'] 54 | }, 55 | **setup_cfg) 56 | 57 | 58 | -------------------------------------------------------------------------------- /nbs/02_cli.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "#| default_exp cli" 10 | ] 11 | }, 12 | { 13 | "attachments": {}, 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "# CLI\n", 18 | "\n", 19 | "> cli commands" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": null, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "#| export\n", 29 | "import os\n", 30 | "from fastcore.script import call_parse\n", 31 | "from tabela_sac.core import SACCalculator" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "#| export\n", 41 | "@call_parse\n", 42 | "def gerar_tabela_sac(valor_financiado:float, # Valor financiado\n", 43 | " prazo:int, # Prazo em meses\n", 44 | " taxa_juros:float, # Taxa de juros ao mês (ex: 0.01 para uma taxa de 1% ao mês)\n", 45 | " path:str='.'\n", 46 | "):\n", 47 | " \"Gera a tabela SAC para o valor financiado, prazo e taxa de juros informados.\"\n", 48 | "\n", 49 | " sac = SACCalculator(valor_financiado, prazo, taxa_juros)\n", 50 | " tabela = sac.tabela()\n", 51 | "\n", 52 | " try:\n", 53 | " tabela.to_csv(f'{path}/tabela_sac.csv', sep=';', index=False)\n", 54 | " return f\"Tabela gerada com sucesso! Path: {path}/tabela_sac.csv\"\n", 55 | " except:\n", 56 | " raise Exception(f\"Não foi possível gerar a tabela. Verifique os parâmetros informados.\")" 57 | ] 58 | }, 59 | { 60 | "attachments": {}, 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "#### Exemplo de como utilizar a cli\n", 65 | "\n", 66 | "```sh\n", 67 | "$ gerar_tabela_sac 100000 360 0.01\n", 68 | "```\n", 69 | "\n", 70 | "O comando `gerar_tabela_sac` está conectado a função `gerar_tabela_sac` através da entrada `console_scripts` no arquivo `settings.ini`, localizado na raiz do projeto:\n", 71 | "\n", 72 | "```sh\n", 73 | "gerar_tabela_sac=tabela_sac.cli:gerar_tabela_sac\n", 74 | "```" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "#|export\n", 84 | "@call_parse\n", 85 | "def install_package():\n", 86 | " \"Install the package\"\n", 87 | " os.system(\"pip install -e '.[dev]'\")" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "metadata": {}, 94 | "outputs": [], 95 | "source": [] 96 | } 97 | ], 98 | "metadata": { 99 | "kernelspec": { 100 | "display_name": "python3", 101 | "language": "python", 102 | "name": "python3" 103 | } 104 | }, 105 | "nbformat": 4, 106 | "nbformat_minor": 2 107 | } 108 | -------------------------------------------------------------------------------- /tabela_sac/core.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb. 2 | 3 | # %% auto 0 4 | __all__ = ['SACCalculator'] 5 | 6 | # %% ../nbs/00_core.ipynb 3 7 | import numpy as np 8 | import pandas as pd 9 | 10 | class SACCalculator: 11 | "A simple calculator class" 12 | def __init__(self, 13 | valor_financiado: float, # Valor financiado 14 | prazo: int, # Prazo em meses 15 | taxa_anual: float # Taxa de juros anual 16 | ): 17 | self.valor_financiado = valor_financiado 18 | self.prazo = prazo 19 | self.taxa_juros = (1 + taxa_anual/100)**(1/12) - 1 20 | self.amortizacao = self.valor_financiado / self.prazo 21 | 22 | def tabela(self): 23 | """ 24 | Gera a tabela SAC 25 | """ 26 | parcelas = np.array([p for p in range(1, self.prazo+1)]) 27 | juros = np.array([self.taxa_juros * (self.valor_financiado - p * self.amortizacao) for p in range(self.prazo)]) 28 | amortizacao = np.array([self.amortizacao for p in range(1, self.prazo+1)]) 29 | valor_da_parcela = juros + amortizacao 30 | saldo_devedor = np.array([self.valor_financiado - p * self.amortizacao for p in range(1, self.prazo+1)]) 31 | 32 | return ( 33 | pd.DataFrame({ 34 | 'Parcela': parcelas, 35 | 'Amortização': amortizacao, 36 | 'Juros': juros, 37 | 'Valor da Parcela': valor_da_parcela, 38 | 'Saldo Devedor': saldo_devedor 39 | }).round(decimals=2) 40 | ) 41 | 42 | def amortizacao_extra_mensal(self, valor_amortizado_extra_mensal: float): 43 | 44 | amortizacao = self.valor_financiado / self.prazo 45 | taxa_mensal = self.taxa_juros 46 | 47 | # Listas para armazenar os dados da tabela 48 | meses_extra = [] 49 | saldos_devedores_extra = [] 50 | amortizacoes_extra = [] 51 | juros_extra = [] 52 | prestacoes_extra = [] 53 | amortizacoes_extras = [] 54 | 55 | # Saldo devedor inicial é o valor financiado 56 | saldo_devedor = self.valor_financiado 57 | 58 | # Cálculo da tabela SAC com amortização extra 59 | mes = 0 60 | while saldo_devedor >= 0: 61 | mes += 1 62 | meses_extra.append(mes) 63 | saldos_devedores_extra.append(saldo_devedor) 64 | amortizacoes_extra.append(amortizacao) 65 | juro = saldo_devedor * taxa_mensal 66 | juros_extra.append(juro) 67 | prestacao = amortizacao + juro 68 | prestacoes_extra.append(prestacao) 69 | 70 | # Abate a amortização extra do saldo devedor 71 | saldo_devedor -= (amortizacao + min(valor_amortizado_extra_mensal, saldo_devedor)) 72 | amortizacoes_extras.append(min(valor_amortizado_extra_mensal, saldo_devedor)) 73 | 74 | # Criação da tabela SAC com amortização extra 75 | tabela_sac_extra = pd.DataFrame({ 76 | 'Parcela': meses_extra, 77 | 'Saldo Devedor Inicial': saldos_devedores_extra, 78 | 'Amortização': amortizacoes_extra, 79 | 'Amortização Extra': amortizacoes_extras, 80 | 'Juros': juros_extra, 81 | 'Valor da Parcela': prestacoes_extra, 82 | 'Saldo Devedor Final': np.roll(saldos_devedores_extra, -1) 83 | }) 84 | 85 | # Exclusão da última linha, que contém dados incorretos devido ao deslocamento 86 | tabela_sac_amortizada = tabela_sac_extra[:-1] 87 | 88 | return tabela_sac_amortizada 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tabela-sac 2 | 3 | 4 | 5 | ## Install 6 | 7 | ``` sh 8 | pip install tabela_sac 9 | ``` 10 | 11 | ## How to use 12 | 13 | ``` python 14 | from tabela_sac.core import SACCalculator 15 | ``` 16 | 17 | ``` python 18 | sac = SACCalculator(valor_financiado=200000, 19 | prazo=360, 20 | taxa_anual=9.99) 21 | ``` 22 | 23 | ``` python 24 | tabela = sac.tabela() 25 | tabela 26 | ``` 27 | 28 |
29 | 40 | 41 | | | Parcela | Amortização | Juros | Valor da Parcela | Saldo Devedor | 42 | |-----|---------|-------------|---------|------------------|---------------| 43 | | 0 | 1 | 555.56 | 1593.30 | 2148.86 | 199444.44 | 44 | | 1 | 2 | 555.56 | 1588.87 | 2144.43 | 198888.89 | 45 | | 2 | 3 | 555.56 | 1584.45 | 2140.00 | 198333.33 | 46 | | 3 | 4 | 555.56 | 1580.02 | 2135.58 | 197777.78 | 47 | | 4 | 5 | 555.56 | 1575.60 | 2131.15 | 197222.22 | 48 | | ... | ... | ... | ... | ... | ... | 49 | | 355 | 356 | 555.56 | 22.13 | 577.68 | 2222.22 | 50 | | 356 | 357 | 555.56 | 17.70 | 573.26 | 1666.67 | 51 | | 357 | 358 | 555.56 | 13.28 | 568.83 | 1111.11 | 52 | | 358 | 359 | 555.56 | 8.85 | 564.41 | 555.56 | 53 | | 359 | 360 | 555.56 | 4.43 | 559.98 | 0.00 | 54 | 55 |

360 rows × 5 columns

56 |
57 | 58 | Existe uma resolução que nos garante amortização extra, ou seja, podemos 59 | realizar pagamentos a mais que será totalmente utilizado para amortecer 60 | o saldo devedor e não será utilizado para juros. Com isso, podemos 61 | diminuir o prazo do financiamento e também a quantidade de juros total 62 | pago. Imaginando um cenário em que mensalmente, além do pagamento da 63 | parcela, podemos amortizar de forma extra R\$ 5 mil do saldo devedor, 64 | temos que o prazo do financiamento se reduz de 360 meses para 35 meses: 65 | 66 | ``` python 67 | tabela_amortizacao_extra = sac.amortizacao_extra_mensal(valor_amortizado_extra_mensal=5000) 68 | tabela_amortizacao_extra 69 | ``` 70 | 71 |
72 | 83 | 84 | | | Parcela | Saldo Devedor Inicial | Amortização | Amortização Extra | Juros | Valor da Parcela | Saldo Devedor Final | 85 | |-----|---------|-----------------------|-------------|-------------------|-------------|------------------|---------------------| 86 | | 0 | 1 | 200000.000000 | 555.555556 | 5000.0 | 1593.300789 | 2148.856344 | 194444.444444 | 87 | | 1 | 2 | 194444.444444 | 555.555556 | 5000.0 | 1549.042433 | 2104.597989 | 188888.888889 | 88 | | 2 | 3 | 188888.888889 | 555.555556 | 5000.0 | 1504.784078 | 2060.339634 | 183333.333333 | 89 | | 3 | 4 | 183333.333333 | 555.555556 | 5000.0 | 1460.525723 | 2016.081278 | 177777.777778 | 90 | | 4 | 5 | 177777.777778 | 555.555556 | 5000.0 | 1416.267368 | 1971.822923 | 172222.222222 | 91 | | 5 | 6 | 172222.222222 | 555.555556 | 5000.0 | 1372.009012 | 1927.564568 | 166666.666667 | 92 | | 6 | 7 | 166666.666667 | 555.555556 | 5000.0 | 1327.750657 | 1883.306213 | 161111.111111 | 93 | | 7 | 8 | 161111.111111 | 555.555556 | 5000.0 | 1283.492302 | 1839.047857 | 155555.555556 | 94 | | 8 | 9 | 155555.555556 | 555.555556 | 5000.0 | 1239.233947 | 1794.789502 | 150000.000000 | 95 | | 9 | 10 | 150000.000000 | 555.555556 | 5000.0 | 1194.975591 | 1750.531147 | 144444.444444 | 96 | | 10 | 11 | 144444.444444 | 555.555556 | 5000.0 | 1150.717236 | 1706.272792 | 138888.888889 | 97 | | 11 | 12 | 138888.888889 | 555.555556 | 5000.0 | 1106.458881 | 1662.014437 | 133333.333333 | 98 | | 12 | 13 | 133333.333333 | 555.555556 | 5000.0 | 1062.200526 | 1617.756081 | 127777.777778 | 99 | | 13 | 14 | 127777.777778 | 555.555556 | 5000.0 | 1017.942170 | 1573.497726 | 122222.222222 | 100 | | 14 | 15 | 122222.222222 | 555.555556 | 5000.0 | 973.683815 | 1529.239371 | 116666.666667 | 101 | | 15 | 16 | 116666.666667 | 555.555556 | 5000.0 | 929.425460 | 1484.981016 | 111111.111111 | 102 | | 16 | 17 | 111111.111111 | 555.555556 | 5000.0 | 885.167105 | 1440.722660 | 105555.555556 | 103 | | 17 | 18 | 105555.555556 | 555.555556 | 5000.0 | 840.908750 | 1396.464305 | 100000.000000 | 104 | | 18 | 19 | 100000.000000 | 555.555556 | 5000.0 | 796.650394 | 1352.205950 | 94444.444444 | 105 | | 19 | 20 | 94444.444444 | 555.555556 | 5000.0 | 752.392039 | 1307.947595 | 88888.888889 | 106 | | 20 | 21 | 88888.888889 | 555.555556 | 5000.0 | 708.133684 | 1263.689239 | 83333.333333 | 107 | | 21 | 22 | 83333.333333 | 555.555556 | 5000.0 | 663.875329 | 1219.430884 | 77777.777778 | 108 | | 22 | 23 | 77777.777778 | 555.555556 | 5000.0 | 619.616973 | 1175.172529 | 72222.222222 | 109 | | 23 | 24 | 72222.222222 | 555.555556 | 5000.0 | 575.358618 | 1130.914174 | 66666.666667 | 110 | | 24 | 25 | 66666.666667 | 555.555556 | 5000.0 | 531.100263 | 1086.655818 | 61111.111111 | 111 | | 25 | 26 | 61111.111111 | 555.555556 | 5000.0 | 486.841908 | 1042.397463 | 55555.555556 | 112 | | 26 | 27 | 55555.555556 | 555.555556 | 5000.0 | 442.583552 | 998.139108 | 50000.000000 | 113 | | 27 | 28 | 50000.000000 | 555.555556 | 5000.0 | 398.325197 | 953.880753 | 44444.444444 | 114 | | 28 | 29 | 44444.444444 | 555.555556 | 5000.0 | 354.066842 | 909.622397 | 38888.888889 | 115 | | 29 | 30 | 38888.888889 | 555.555556 | 5000.0 | 309.808487 | 865.364042 | 33333.333333 | 116 | | 30 | 31 | 33333.333333 | 555.555556 | 5000.0 | 265.550131 | 821.105687 | 27777.777778 | 117 | | 31 | 32 | 27777.777778 | 555.555556 | 5000.0 | 221.291776 | 776.847332 | 22222.222222 | 118 | | 32 | 33 | 22222.222222 | 555.555556 | 5000.0 | 177.033421 | 732.588977 | 16666.666667 | 119 | | 33 | 34 | 16666.666667 | 555.555556 | 5000.0 | 132.775066 | 688.330621 | 11111.111111 | 120 | | 34 | 35 | 11111.111111 | 555.555556 | 5000.0 | 88.516710 | 644.072266 | 5555.555556 | 121 | 122 |
123 | 124 | ``` python 125 | len(tabela.index), len(tabela_amortizacao_extra.index) 126 | ``` 127 | 128 | (360, 35) 129 | 130 | ``` python 131 | # Comparação de juros pago. 132 | # Sem amortização, pagamos R$ 287 mil de juros sobre um financiamento de R$ 200 mil. 133 | # Com a amortização, pagamos apenas R$ 29 mil de juros. 134 | tabela['Juros'].sum(), tabela_amortizacao_extra['Juros'].sum() 135 | ``` 136 | 137 | (287590.8, 29431.806233791034) 138 | 139 | ``` python 140 | # Comparação de valor total pago. 141 | # Sem amortização, pagamos mais que o dobro. 142 | # Com amortização, pagamos um pouco mais que 10% do valor financiado. 143 | tabela['Valor da Parcela'].sum(), tabela_amortizacao_extra['Saldo Devedor Inicial'].loc[0] + tabela_amortizacao_extra['Juros'].sum() 144 | ``` 145 | 146 | (487590.79, 229431.80623379102) 147 | 148 | # CLI Interface 149 | 150 | The nbdev cli system uses `fastcore.script` to build command line 151 | interfaces. For further information, go to 152 | 153 | 154 | ``` sh 155 | $ gerar_tabela_sac --help 156 | 157 | usage: gerar_tabela_sac [-h] [--path PATH] valor_financiado prazo taxa_juros 158 | 159 | Gera a tabela SAC para o valor financiado, prazo e taxa de juros informados. 160 | 161 | positional arguments: 162 | valor_financiado Valor financiado 163 | prazo Prazo em meses 164 | taxa_juros Taxa de juros ao ano (ex: 12 para uma taxa de 12% ao ano) 165 | 166 | optional arguments: 167 | -h, --help show this help message and exit 168 | --path PATH (default: .) 169 | ``` 170 | 171 | Usage: 172 | 173 | ``` sh 174 | $ gerar_tabela_sac 100000 360 12 175 | ``` 176 | -------------------------------------------------------------------------------- /nbs/01_what_is_sac.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# O que é a Tabela SAC? " 9 | ] 10 | }, 11 | { 12 | "attachments": {}, 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "Tabela SAC é um tipo de financiando com Sistema de Amortização Constante. A cada parcela paga, um valor constante é amortizado do saldo devedor.\n", 17 | "\n", 18 | "Vamos simular um financiamento de uma casa no valor de R$ 200 mil em 360 meses (30 anos), com uma taxa de juros mensal de 1% ao mês.\n", 19 | "\n", 20 | "Antes de tudo, precisamos saber o valor da amortização, ou seja, quanto irá diminuir o saldo devedor a cada parcela paga:\n", 21 | "\n", 22 | "> R$ 200.000,00 / 360 meses = R$ 555,56\n", 23 | "\n", 24 | "Independente do valor que você pagar na parcela, apenas R$ 555,56 será de fato descontado do saldo devedor.\n", 25 | "\n", 26 | "Agora para descobrir o valor da primeira parcela, temos que aplicar os juros sobre o saldo devedor:\n", 27 | "\n", 28 | "> R$ 200.000,00 * 1% = R$ 2.000,00\n", 29 | "\n", 30 | "Com o valor da amortização e o valor pago em juros em mãos, o valor da primeira parcela é a soma desses dois valores:\n", 31 | "\n", 32 | "> R$ 555,56 + R$ 2.000,00 = R$ 2.555,56\n", 33 | "\n", 34 | "O valor da primeira parcela do financiamento é de R$ 2.555,56.\n", 35 | "\n", 36 | "Após pagar a primeira parcela, como a amortização foi de R$ 555,56 (isso mesmo, R$ 2 mil foi só de juros), você ainda estará devendo R$ 199.444,44 (saldo devedor após a primeira parcela).\n", 37 | "\n", 38 | "Em 12 meses, você pagará R$ 30.300,05 em parcelas e irá abater apenas R$ 6.666,72 do saldo devedor.\n", 39 | "\n", 40 | "Para calcular a tabela SAC completa, podemos utilizar o pacote `tabela-sac`" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "from tabela_sac.core import SACCalculator" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "sac = SACCalculator(\n", 59 | " valor_financiado=200000,\n", 60 | " prazo=360,\n", 61 | " taxa_anual=9.99\n", 62 | ")" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "tabela = sac.tabela()" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": {}, 78 | "outputs": [ 79 | { 80 | "data": { 81 | "text/html": [ 82 | "
\n", 83 | "\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 | " \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 | "
ParcelaJurosAmortizaçãoValor da ParcelaSaldo Devedor
012000.00555.562555.56199444.44
121994.44555.562550.00198888.89
231988.89555.562544.44198333.33
341983.33555.562538.89197777.78
451977.78555.562533.33197222.22
561972.22555.562527.78196666.67
671966.67555.562522.22196111.11
781961.11555.562516.67195555.56
891955.56555.562511.11195000.00
9101950.00555.562505.56194444.44
10111944.44555.562500.00193888.89
11121938.89555.562494.44193333.33
\n", 206 | "
" 207 | ], 208 | "text/plain": [ 209 | " Parcela Juros Amortização Valor da Parcela Saldo Devedor\n", 210 | "0 1 2000.00 555.56 2555.56 199444.44\n", 211 | "1 2 1994.44 555.56 2550.00 198888.89\n", 212 | "2 3 1988.89 555.56 2544.44 198333.33\n", 213 | "3 4 1983.33 555.56 2538.89 197777.78\n", 214 | "4 5 1977.78 555.56 2533.33 197222.22\n", 215 | "5 6 1972.22 555.56 2527.78 196666.67\n", 216 | "6 7 1966.67 555.56 2522.22 196111.11\n", 217 | "7 8 1961.11 555.56 2516.67 195555.56\n", 218 | "8 9 1955.56 555.56 2511.11 195000.00\n", 219 | "9 10 1950.00 555.56 2505.56 194444.44\n", 220 | "10 11 1944.44 555.56 2500.00 193888.89\n", 221 | "11 12 1938.89 555.56 2494.44 193333.33" 222 | ] 223 | }, 224 | "execution_count": null, 225 | "metadata": {}, 226 | "output_type": "execute_result" 227 | } 228 | ], 229 | "source": [ 230 | "tabela.head(12)" 231 | ] 232 | }, 233 | { 234 | "attachments": {}, 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "Só no primeiro ano, teremos pago R$ 30.300,00:" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": null, 244 | "metadata": {}, 245 | "outputs": [ 246 | { 247 | "data": { 248 | "text/plain": [ 249 | "30300.0" 250 | ] 251 | }, 252 | "execution_count": null, 253 | "metadata": {}, 254 | "output_type": "execute_result" 255 | } 256 | ], 257 | "source": [ 258 | "tabela.head(12)['Valor da Parcela'].sum().round(2)" 259 | ] 260 | }, 261 | { 262 | "attachments": {}, 263 | "cell_type": "markdown", 264 | "metadata": {}, 265 | "source": [ 266 | "Onde desse valor, 78% são juros (R$ 23.633,33) e apenas 22% (R$ 6.666,72) serão de fato utilizados para abater o saldo devedor" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": null, 272 | "metadata": {}, 273 | "outputs": [ 274 | { 275 | "data": { 276 | "text/plain": [ 277 | "23633.33" 278 | ] 279 | }, 280 | "execution_count": null, 281 | "metadata": {}, 282 | "output_type": "execute_result" 283 | } 284 | ], 285 | "source": [ 286 | "tabela.head(12)['Juros'].sum().round(2)" 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": null, 292 | "metadata": {}, 293 | "outputs": [ 294 | { 295 | "data": { 296 | "text/plain": [ 297 | "6666.72" 298 | ] 299 | }, 300 | "execution_count": null, 301 | "metadata": {}, 302 | "output_type": "execute_result" 303 | } 304 | ], 305 | "source": [ 306 | "tabela.head(12)['Amortização'].sum().round(2)" 307 | ] 308 | }, 309 | { 310 | "attachments": {}, 311 | "cell_type": "markdown", 312 | "metadata": {}, 313 | "source": [ 314 | "Assim, uma estratégia possível para pagar menos juros e reduzir o tempo de financiamento, é pagar sempre as primeiras e últimas parcelas, pois nas últimas parcelas o valor amortizador é maior que os juros incididos, dessa forma reduzindo bastante o valor do saldo devedor que fará incidir menos juros." 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": null, 320 | "metadata": {}, 321 | "outputs": [], 322 | "source": [] 323 | } 324 | ], 325 | "metadata": { 326 | "kernelspec": { 327 | "display_name": "python3", 328 | "language": "python", 329 | "name": "python3" 330 | } 331 | }, 332 | "nbformat": 4, 333 | "nbformat_minor": 2 334 | } 335 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022, fastai 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /nbs/00_core.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# core\n", 9 | "\n", 10 | "> Code documentation" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "#| default_exp core" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": null, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "#| hide\n", 29 | "from nbdev.showdoc import *" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "#| export\n", 39 | "import numpy as np\n", 40 | "import pandas as pd\n", 41 | "\n", 42 | "class SACCalculator:\n", 43 | " \"A simple calculator class\"\n", 44 | " def __init__(self, \n", 45 | " valor_financiado: float, # Valor financiado\n", 46 | " prazo: int, # Prazo em meses \n", 47 | " taxa_anual: float # Taxa de juros anual\n", 48 | " ):\n", 49 | " self.valor_financiado = valor_financiado\n", 50 | " self.prazo = prazo\n", 51 | " self.taxa_juros = (1 + taxa_anual/100)**(1/12) - 1\n", 52 | " self.amortizacao = self.valor_financiado / self.prazo\n", 53 | "\n", 54 | " def tabela(self):\n", 55 | " \"\"\"\n", 56 | " Gera a tabela SAC\n", 57 | " \"\"\"\n", 58 | " parcelas = np.array([p for p in range(1, self.prazo+1)])\n", 59 | " juros = np.array([self.taxa_juros * (self.valor_financiado - p * self.amortizacao) for p in range(self.prazo)])\n", 60 | " amortizacao = np.array([self.amortizacao for p in range(1, self.prazo+1)])\n", 61 | " valor_da_parcela = juros + amortizacao\n", 62 | " saldo_devedor = np.array([self.valor_financiado - p * self.amortizacao for p in range(1, self.prazo+1)])\n", 63 | " \n", 64 | " return (\n", 65 | " pd.DataFrame({\n", 66 | " 'Parcela': parcelas,\n", 67 | " 'Amortização': amortizacao,\n", 68 | " 'Juros': juros,\n", 69 | " 'Valor da Parcela': valor_da_parcela,\n", 70 | " 'Saldo Devedor': saldo_devedor\n", 71 | " }).round(decimals=2) \n", 72 | " )\n", 73 | " \n", 74 | " def amortizacao_extra_mensal(self, valor_amortizado_extra_mensal: float):\n", 75 | " \n", 76 | " amortizacao = self.valor_financiado / self.prazo\n", 77 | " taxa_mensal = self.taxa_juros\n", 78 | " \n", 79 | " # Listas para armazenar os dados da tabela\n", 80 | " meses_extra = []\n", 81 | " saldos_devedores_extra = []\n", 82 | " amortizacoes_extra = []\n", 83 | " juros_extra = []\n", 84 | " prestacoes_extra = []\n", 85 | " amortizacoes_extras = []\n", 86 | "\n", 87 | " # Saldo devedor inicial é o valor financiado\n", 88 | " saldo_devedor = self.valor_financiado\n", 89 | "\n", 90 | " # Cálculo da tabela SAC com amortização extra\n", 91 | " mes = 0\n", 92 | " while saldo_devedor >= 0:\n", 93 | " mes += 1\n", 94 | " meses_extra.append(mes)\n", 95 | " saldos_devedores_extra.append(saldo_devedor)\n", 96 | " amortizacoes_extra.append(amortizacao)\n", 97 | " juro = saldo_devedor * taxa_mensal\n", 98 | " juros_extra.append(juro)\n", 99 | " prestacao = amortizacao + juro\n", 100 | " prestacoes_extra.append(prestacao)\n", 101 | " \n", 102 | " # Abate a amortização extra do saldo devedor\n", 103 | " saldo_devedor -= (amortizacao + min(valor_amortizado_extra_mensal, saldo_devedor))\n", 104 | " amortizacoes_extras.append(min(valor_amortizado_extra_mensal, saldo_devedor))\n", 105 | "\n", 106 | " # Criação da tabela SAC com amortização extra\n", 107 | " tabela_sac_extra = pd.DataFrame({\n", 108 | " 'Parcela': meses_extra,\n", 109 | " 'Saldo Devedor Inicial': saldos_devedores_extra,\n", 110 | " 'Amortização': amortizacoes_extra,\n", 111 | " 'Amortização Extra': amortizacoes_extras,\n", 112 | " 'Juros': juros_extra,\n", 113 | " 'Valor da Parcela': prestacoes_extra,\n", 114 | " 'Saldo Devedor Final': np.roll(saldos_devedores_extra, -1)\n", 115 | " })\n", 116 | "\n", 117 | " # Exclusão da última linha, que contém dados incorretos devido ao deslocamento\n", 118 | " tabela_sac_amortizada = tabela_sac_extra[:-1]\n", 119 | "\n", 120 | " return tabela_sac_amortizada" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": null, 126 | "metadata": {}, 127 | "outputs": [], 128 | "source": [ 129 | "sac = SACCalculator(205385.45, 420, 9.99)" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": null, 135 | "metadata": {}, 136 | "outputs": [ 137 | { 138 | "data": { 139 | "text/html": [ 140 | "
\n", 141 | "\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 | "
ParcelaAmortizaçãoJurosValor da ParcelaSaldo Devedor
01489.011636.202125.22204896.44
12489.011632.312121.32204407.42
23489.011628.412117.43203918.41
34489.011624.522113.53203429.40
45489.011620.622109.63202940.39
\n", 208 | "
" 209 | ], 210 | "text/plain": [ 211 | " Parcela Amortização Juros Valor da Parcela Saldo Devedor\n", 212 | "0 1 489.01 1636.20 2125.22 204896.44\n", 213 | "1 2 489.01 1632.31 2121.32 204407.42\n", 214 | "2 3 489.01 1628.41 2117.43 203918.41\n", 215 | "3 4 489.01 1624.52 2113.53 203429.40\n", 216 | "4 5 489.01 1620.62 2109.63 202940.39" 217 | ] 218 | }, 219 | "execution_count": null, 220 | "metadata": {}, 221 | "output_type": "execute_result" 222 | } 223 | ], 224 | "source": [ 225 | "tabela = sac.tabela()\n", 226 | "tabela.head()" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": null, 232 | "metadata": {}, 233 | "outputs": [ 234 | { 235 | "data": { 236 | "text/html": [ 237 | "
\n", 238 | "\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 | "
ParcelaSaldo Devedor InicialAmortizaçãoAmortização ExtraJurosValor da ParcelaSaldo Devedor Final
01205385.450000489.0129765000.01636.2039972125.216973199896.437024
12199896.437024489.0129765000.01592.4757542081.488730194407.424048
23194407.424048489.0129765000.01548.7475102037.760486188918.411071
34188918.411071489.0129765000.01505.0192671994.032243183429.398095
45183429.398095489.0129765000.01461.2910231950.303999177940.385119
\n", 317 | "
" 318 | ], 319 | "text/plain": [ 320 | " Parcela Saldo Devedor Inicial Amortização Amortização Extra \\\n", 321 | "0 1 205385.450000 489.012976 5000.0 \n", 322 | "1 2 199896.437024 489.012976 5000.0 \n", 323 | "2 3 194407.424048 489.012976 5000.0 \n", 324 | "3 4 188918.411071 489.012976 5000.0 \n", 325 | "4 5 183429.398095 489.012976 5000.0 \n", 326 | "\n", 327 | " Juros Valor da Parcela Saldo Devedor Final \n", 328 | "0 1636.203997 2125.216973 199896.437024 \n", 329 | "1 1592.475754 2081.488730 194407.424048 \n", 330 | "2 1548.747510 2037.760486 188918.411071 \n", 331 | "3 1505.019267 1994.032243 183429.398095 \n", 332 | "4 1461.291023 1950.303999 177940.385119 " 333 | ] 334 | }, 335 | "execution_count": null, 336 | "metadata": {}, 337 | "output_type": "execute_result" 338 | } 339 | ], 340 | "source": [ 341 | "tabela_amortizacao_extra = sac.amortizacao_extra_mensal(valor_amortizado_extra_mensal=5000)\n", 342 | "tabela_amortizacao_extra.head()" 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": null, 348 | "metadata": {}, 349 | "outputs": [ 350 | { 351 | "data": { 352 | "text/plain": [ 353 | "(420, 37)" 354 | ] 355 | }, 356 | "execution_count": null, 357 | "metadata": {}, 358 | "output_type": "execute_result" 359 | } 360 | ], 361 | "source": [ 362 | "len(tabela.index), len(tabela_amortizacao_extra)" 363 | ] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": null, 368 | "metadata": {}, 369 | "outputs": [ 370 | { 371 | "data": { 372 | "text/plain": [ 373 | "(549806.39, 236801.98771555116)" 374 | ] 375 | }, 376 | "execution_count": null, 377 | "metadata": {}, 378 | "output_type": "execute_result" 379 | } 380 | ], 381 | "source": [ 382 | "tabela['Valor da Parcela'].sum(), tabela_amortizacao_extra['Saldo Devedor Inicial'].loc[0] + tabela_amortizacao_extra['Juros'].sum()" 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": null, 388 | "metadata": {}, 389 | "outputs": [ 390 | { 391 | "data": { 392 | "text/plain": [ 393 | "(344420.94, 31416.53771555116)" 394 | ] 395 | }, 396 | "execution_count": null, 397 | "metadata": {}, 398 | "output_type": "execute_result" 399 | } 400 | ], 401 | "source": [ 402 | "tabela['Juros'].sum(), tabela_amortizacao_extra['Juros'].sum()" 403 | ] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "execution_count": null, 408 | "metadata": {}, 409 | "outputs": [], 410 | "source": [ 411 | "assert SACCalculator(200000, 360, 0.01).tabela().shape[0] == 360" 412 | ] 413 | }, 414 | { 415 | "cell_type": "code", 416 | "execution_count": null, 417 | "metadata": {}, 418 | "outputs": [], 419 | "source": [ 420 | "assert SACCalculator(200000, 12, 0.01).tabela().shape[0] == 12" 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": null, 426 | "metadata": {}, 427 | "outputs": [], 428 | "source": [ 429 | "assert SACCalculator(200000, 24, 0.01).tabela().shape[0] == 24" 430 | ] 431 | }, 432 | { 433 | "cell_type": "code", 434 | "execution_count": null, 435 | "metadata": {}, 436 | "outputs": [], 437 | "source": [ 438 | "assert SACCalculator(200000, 5, 0.01).tabela().shape[0] == 5" 439 | ] 440 | }, 441 | { 442 | "cell_type": "code", 443 | "execution_count": null, 444 | "metadata": {}, 445 | "outputs": [], 446 | "source": [ 447 | "#| hide\n", 448 | "import nbdev; nbdev.nbdev_export()" 449 | ] 450 | }, 451 | { 452 | "cell_type": "code", 453 | "execution_count": null, 454 | "metadata": {}, 455 | "outputs": [], 456 | "source": [] 457 | } 458 | ], 459 | "metadata": { 460 | "kernelspec": { 461 | "display_name": "python3", 462 | "language": "python", 463 | "name": "python3" 464 | } 465 | }, 466 | "nbformat": 4, 467 | "nbformat_minor": 4 468 | } 469 | -------------------------------------------------------------------------------- /nbs/index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "#| hide\n", 10 | "from tabela_sac.core import *" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "# tabela-sac\n", 18 | "\n", 19 | "> Forma Simples de Gerar uma Tabela SAC" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "## Install" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "```sh\n", 34 | "pip install tabela_sac\n", 35 | "```" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "## How to use" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "from tabela_sac.core import SACCalculator" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "sac = SACCalculator(valor_financiado=200000, \n", 61 | " prazo=360, \n", 62 | " taxa_anual=9.99)" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": {}, 69 | "outputs": [ 70 | { 71 | "data": { 72 | "text/html": [ 73 | "
\n", 74 | "\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 | " \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 | "
ParcelaAmortizaçãoJurosValor da ParcelaSaldo Devedor
01555.561593.302148.86199444.44
12555.561588.872144.43198888.89
23555.561584.452140.00198333.33
34555.561580.022135.58197777.78
45555.561575.602131.15197222.22
..................
355356555.5622.13577.682222.22
356357555.5617.70573.261666.67
357358555.5613.28568.831111.11
358359555.568.85564.41555.56
359360555.564.43559.980.00
\n", 189 | "

360 rows × 5 columns

\n", 190 | "
" 191 | ], 192 | "text/plain": [ 193 | " Parcela Amortização Juros Valor da Parcela Saldo Devedor\n", 194 | "0 1 555.56 1593.30 2148.86 199444.44\n", 195 | "1 2 555.56 1588.87 2144.43 198888.89\n", 196 | "2 3 555.56 1584.45 2140.00 198333.33\n", 197 | "3 4 555.56 1580.02 2135.58 197777.78\n", 198 | "4 5 555.56 1575.60 2131.15 197222.22\n", 199 | ".. ... ... ... ... ...\n", 200 | "355 356 555.56 22.13 577.68 2222.22\n", 201 | "356 357 555.56 17.70 573.26 1666.67\n", 202 | "357 358 555.56 13.28 568.83 1111.11\n", 203 | "358 359 555.56 8.85 564.41 555.56\n", 204 | "359 360 555.56 4.43 559.98 0.00\n", 205 | "\n", 206 | "[360 rows x 5 columns]" 207 | ] 208 | }, 209 | "execution_count": null, 210 | "metadata": {}, 211 | "output_type": "execute_result" 212 | } 213 | ], 214 | "source": [ 215 | "tabela = sac.tabela()\n", 216 | "tabela" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "metadata": {}, 222 | "source": [ 223 | "Existe uma resolução que nos garante amortização extra, ou seja, podemos realizar pagamentos a mais que será totalmente utilizado para amortecer o saldo devedor e não será utilizado para juros. Com isso, podemos diminuir o prazo do financiamento e também a quantidade de juros total pago. Imaginando um cenário em que mensalmente, além do pagamento da parcela, podemos amortizar de forma extra R$ 5 mil do saldo devedor, temos que o prazo do financiamento se reduz de 360 meses para 35 meses:" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "metadata": {}, 230 | "outputs": [ 231 | { 232 | "data": { 233 | "text/html": [ 234 | "
\n", 235 | "\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 | " \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 | " \n", 442 | " \n", 443 | " \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 | " \n", 582 | " \n", 583 | " \n", 584 | " \n", 585 | " \n", 586 | " \n", 587 | " \n", 588 | " \n", 589 | " \n", 590 | " \n", 591 | " \n", 592 | " \n", 593 | " \n", 594 | " \n", 595 | " \n", 596 | " \n", 597 | " \n", 598 | " \n", 599 | " \n", 600 | " \n", 601 | " \n", 602 | " \n", 603 | " \n", 604 | " \n", 605 | " \n", 606 | " \n", 607 | " \n", 608 | " \n", 609 | " \n", 610 | " \n", 611 | " \n", 612 | " \n", 613 | "
ParcelaSaldo Devedor InicialAmortizaçãoAmortização ExtraJurosValor da ParcelaSaldo Devedor Final
01200000.000000555.5555565000.01593.3007892148.856344194444.444444
12194444.444444555.5555565000.01549.0424332104.597989188888.888889
23188888.888889555.5555565000.01504.7840782060.339634183333.333333
34183333.333333555.5555565000.01460.5257232016.081278177777.777778
45177777.777778555.5555565000.01416.2673681971.822923172222.222222
56172222.222222555.5555565000.01372.0090121927.564568166666.666667
67166666.666667555.5555565000.01327.7506571883.306213161111.111111
78161111.111111555.5555565000.01283.4923021839.047857155555.555556
89155555.555556555.5555565000.01239.2339471794.789502150000.000000
910150000.000000555.5555565000.01194.9755911750.531147144444.444444
1011144444.444444555.5555565000.01150.7172361706.272792138888.888889
1112138888.888889555.5555565000.01106.4588811662.014437133333.333333
1213133333.333333555.5555565000.01062.2005261617.756081127777.777778
1314127777.777778555.5555565000.01017.9421701573.497726122222.222222
1415122222.222222555.5555565000.0973.6838151529.239371116666.666667
1516116666.666667555.5555565000.0929.4254601484.981016111111.111111
1617111111.111111555.5555565000.0885.1671051440.722660105555.555556
1718105555.555556555.5555565000.0840.9087501396.464305100000.000000
1819100000.000000555.5555565000.0796.6503941352.20595094444.444444
192094444.444444555.5555565000.0752.3920391307.94759588888.888889
202188888.888889555.5555565000.0708.1336841263.68923983333.333333
212283333.333333555.5555565000.0663.8753291219.43088477777.777778
222377777.777778555.5555565000.0619.6169731175.17252972222.222222
232472222.222222555.5555565000.0575.3586181130.91417466666.666667
242566666.666667555.5555565000.0531.1002631086.65581861111.111111
252661111.111111555.5555565000.0486.8419081042.39746355555.555556
262755555.555556555.5555565000.0442.583552998.13910850000.000000
272850000.000000555.5555565000.0398.325197953.88075344444.444444
282944444.444444555.5555565000.0354.066842909.62239738888.888889
293038888.888889555.5555565000.0309.808487865.36404233333.333333
303133333.333333555.5555565000.0265.550131821.10568727777.777778
313227777.777778555.5555565000.0221.291776776.84733222222.222222
323322222.222222555.5555565000.0177.033421732.58897716666.666667
333416666.666667555.5555565000.0132.775066688.33062111111.111111
343511111.111111555.5555565000.088.516710644.0722665555.555556
\n", 614 | "
" 615 | ], 616 | "text/plain": [ 617 | " Parcela Saldo Devedor Inicial Amortização Amortização Extra \\\n", 618 | "0 1 200000.000000 555.555556 5000.0 \n", 619 | "1 2 194444.444444 555.555556 5000.0 \n", 620 | "2 3 188888.888889 555.555556 5000.0 \n", 621 | "3 4 183333.333333 555.555556 5000.0 \n", 622 | "4 5 177777.777778 555.555556 5000.0 \n", 623 | "5 6 172222.222222 555.555556 5000.0 \n", 624 | "6 7 166666.666667 555.555556 5000.0 \n", 625 | "7 8 161111.111111 555.555556 5000.0 \n", 626 | "8 9 155555.555556 555.555556 5000.0 \n", 627 | "9 10 150000.000000 555.555556 5000.0 \n", 628 | "10 11 144444.444444 555.555556 5000.0 \n", 629 | "11 12 138888.888889 555.555556 5000.0 \n", 630 | "12 13 133333.333333 555.555556 5000.0 \n", 631 | "13 14 127777.777778 555.555556 5000.0 \n", 632 | "14 15 122222.222222 555.555556 5000.0 \n", 633 | "15 16 116666.666667 555.555556 5000.0 \n", 634 | "16 17 111111.111111 555.555556 5000.0 \n", 635 | "17 18 105555.555556 555.555556 5000.0 \n", 636 | "18 19 100000.000000 555.555556 5000.0 \n", 637 | "19 20 94444.444444 555.555556 5000.0 \n", 638 | "20 21 88888.888889 555.555556 5000.0 \n", 639 | "21 22 83333.333333 555.555556 5000.0 \n", 640 | "22 23 77777.777778 555.555556 5000.0 \n", 641 | "23 24 72222.222222 555.555556 5000.0 \n", 642 | "24 25 66666.666667 555.555556 5000.0 \n", 643 | "25 26 61111.111111 555.555556 5000.0 \n", 644 | "26 27 55555.555556 555.555556 5000.0 \n", 645 | "27 28 50000.000000 555.555556 5000.0 \n", 646 | "28 29 44444.444444 555.555556 5000.0 \n", 647 | "29 30 38888.888889 555.555556 5000.0 \n", 648 | "30 31 33333.333333 555.555556 5000.0 \n", 649 | "31 32 27777.777778 555.555556 5000.0 \n", 650 | "32 33 22222.222222 555.555556 5000.0 \n", 651 | "33 34 16666.666667 555.555556 5000.0 \n", 652 | "34 35 11111.111111 555.555556 5000.0 \n", 653 | "\n", 654 | " Juros Valor da Parcela Saldo Devedor Final \n", 655 | "0 1593.300789 2148.856344 194444.444444 \n", 656 | "1 1549.042433 2104.597989 188888.888889 \n", 657 | "2 1504.784078 2060.339634 183333.333333 \n", 658 | "3 1460.525723 2016.081278 177777.777778 \n", 659 | "4 1416.267368 1971.822923 172222.222222 \n", 660 | "5 1372.009012 1927.564568 166666.666667 \n", 661 | "6 1327.750657 1883.306213 161111.111111 \n", 662 | "7 1283.492302 1839.047857 155555.555556 \n", 663 | "8 1239.233947 1794.789502 150000.000000 \n", 664 | "9 1194.975591 1750.531147 144444.444444 \n", 665 | "10 1150.717236 1706.272792 138888.888889 \n", 666 | "11 1106.458881 1662.014437 133333.333333 \n", 667 | "12 1062.200526 1617.756081 127777.777778 \n", 668 | "13 1017.942170 1573.497726 122222.222222 \n", 669 | "14 973.683815 1529.239371 116666.666667 \n", 670 | "15 929.425460 1484.981016 111111.111111 \n", 671 | "16 885.167105 1440.722660 105555.555556 \n", 672 | "17 840.908750 1396.464305 100000.000000 \n", 673 | "18 796.650394 1352.205950 94444.444444 \n", 674 | "19 752.392039 1307.947595 88888.888889 \n", 675 | "20 708.133684 1263.689239 83333.333333 \n", 676 | "21 663.875329 1219.430884 77777.777778 \n", 677 | "22 619.616973 1175.172529 72222.222222 \n", 678 | "23 575.358618 1130.914174 66666.666667 \n", 679 | "24 531.100263 1086.655818 61111.111111 \n", 680 | "25 486.841908 1042.397463 55555.555556 \n", 681 | "26 442.583552 998.139108 50000.000000 \n", 682 | "27 398.325197 953.880753 44444.444444 \n", 683 | "28 354.066842 909.622397 38888.888889 \n", 684 | "29 309.808487 865.364042 33333.333333 \n", 685 | "30 265.550131 821.105687 27777.777778 \n", 686 | "31 221.291776 776.847332 22222.222222 \n", 687 | "32 177.033421 732.588977 16666.666667 \n", 688 | "33 132.775066 688.330621 11111.111111 \n", 689 | "34 88.516710 644.072266 5555.555556 " 690 | ] 691 | }, 692 | "execution_count": null, 693 | "metadata": {}, 694 | "output_type": "execute_result" 695 | } 696 | ], 697 | "source": [ 698 | "tabela_amortizacao_extra = sac.amortizacao_extra_mensal(valor_amortizado_extra_mensal=5000)\n", 699 | "tabela_amortizacao_extra" 700 | ] 701 | }, 702 | { 703 | "cell_type": "code", 704 | "execution_count": null, 705 | "metadata": {}, 706 | "outputs": [ 707 | { 708 | "data": { 709 | "text/plain": [ 710 | "(360, 35)" 711 | ] 712 | }, 713 | "execution_count": null, 714 | "metadata": {}, 715 | "output_type": "execute_result" 716 | } 717 | ], 718 | "source": [ 719 | "len(tabela.index), len(tabela_amortizacao_extra.index)" 720 | ] 721 | }, 722 | { 723 | "cell_type": "code", 724 | "execution_count": null, 725 | "metadata": {}, 726 | "outputs": [ 727 | { 728 | "data": { 729 | "text/plain": [ 730 | "(287590.8, 29431.806233791034)" 731 | ] 732 | }, 733 | "execution_count": null, 734 | "metadata": {}, 735 | "output_type": "execute_result" 736 | } 737 | ], 738 | "source": [ 739 | "# Comparação de juros pago.\n", 740 | "# Sem amortização, pagamos R$ 287 mil de juros sobre um financiamento de R$ 200 mil.\n", 741 | "# Com a amortização, pagamos apenas R$ 29 mil de juros.\n", 742 | "tabela['Juros'].sum(), tabela_amortizacao_extra['Juros'].sum()" 743 | ] 744 | }, 745 | { 746 | "cell_type": "code", 747 | "execution_count": null, 748 | "metadata": {}, 749 | "outputs": [ 750 | { 751 | "data": { 752 | "text/plain": [ 753 | "(487590.79, 229431.80623379102)" 754 | ] 755 | }, 756 | "execution_count": null, 757 | "metadata": {}, 758 | "output_type": "execute_result" 759 | } 760 | ], 761 | "source": [ 762 | "# Comparação de valor total pago.\n", 763 | "# Sem amortização, pagamos mais que o dobro.\n", 764 | "# Com amortização, pagamos um pouco mais que 10% do valor financiado.\n", 765 | "tabela['Valor da Parcela'].sum(), tabela_amortizacao_extra['Saldo Devedor Inicial'].loc[0] + tabela_amortizacao_extra['Juros'].sum()" 766 | ] 767 | }, 768 | { 769 | "attachments": {}, 770 | "cell_type": "markdown", 771 | "metadata": {}, 772 | "source": [ 773 | "# CLI Interface\n", 774 | "\n", 775 | "The nbdev cli system uses `fastcore.script` to build command line interfaces. For further information, go to [https://fastcore.fast.ai/script.html](https://fastcore.fast.ai/script.html)" 776 | ] 777 | }, 778 | { 779 | "attachments": {}, 780 | "cell_type": "markdown", 781 | "metadata": {}, 782 | "source": [ 783 | "```sh\n", 784 | "$ gerar_tabela_sac --help\n", 785 | "\n", 786 | "usage: gerar_tabela_sac [-h] [--path PATH] valor_financiado prazo taxa_juros\n", 787 | "\n", 788 | "Gera a tabela SAC para o valor financiado, prazo e taxa de juros informados.\n", 789 | "\n", 790 | "positional arguments:\n", 791 | " valor_financiado Valor financiado\n", 792 | " prazo Prazo em meses\n", 793 | " taxa_juros Taxa de juros ao ano (ex: 12 para uma taxa de 12% ao ano)\n", 794 | "\n", 795 | "optional arguments:\n", 796 | " -h, --help show this help message and exit\n", 797 | " --path PATH (default: .)\n", 798 | "```" 799 | ] 800 | }, 801 | { 802 | "attachments": {}, 803 | "cell_type": "markdown", 804 | "metadata": {}, 805 | "source": [ 806 | "Usage:" 807 | ] 808 | }, 809 | { 810 | "attachments": {}, 811 | "cell_type": "markdown", 812 | "metadata": {}, 813 | "source": [ 814 | "```sh\n", 815 | "$ gerar_tabela_sac 100000 360 12\n", 816 | "```" 817 | ] 818 | }, 819 | { 820 | "cell_type": "code", 821 | "execution_count": null, 822 | "metadata": {}, 823 | "outputs": [], 824 | "source": [] 825 | } 826 | ], 827 | "metadata": { 828 | "kernelspec": { 829 | "display_name": "python3", 830 | "language": "python", 831 | "name": "python3" 832 | } 833 | }, 834 | "nbformat": 4, 835 | "nbformat_minor": 4 836 | } 837 | --------------------------------------------------------------------------------