├── 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 | " Parcela | \n",
101 | " Juros | \n",
102 | " Amortização | \n",
103 | " Valor da Parcela | \n",
104 | " Saldo Devedor | \n",
105 | "
\n",
106 | " \n",
107 | " \n",
108 | " \n",
109 | " | 0 | \n",
110 | " 1 | \n",
111 | " 2000.00 | \n",
112 | " 555.56 | \n",
113 | " 2555.56 | \n",
114 | " 199444.44 | \n",
115 | "
\n",
116 | " \n",
117 | " | 1 | \n",
118 | " 2 | \n",
119 | " 1994.44 | \n",
120 | " 555.56 | \n",
121 | " 2550.00 | \n",
122 | " 198888.89 | \n",
123 | "
\n",
124 | " \n",
125 | " | 2 | \n",
126 | " 3 | \n",
127 | " 1988.89 | \n",
128 | " 555.56 | \n",
129 | " 2544.44 | \n",
130 | " 198333.33 | \n",
131 | "
\n",
132 | " \n",
133 | " | 3 | \n",
134 | " 4 | \n",
135 | " 1983.33 | \n",
136 | " 555.56 | \n",
137 | " 2538.89 | \n",
138 | " 197777.78 | \n",
139 | "
\n",
140 | " \n",
141 | " | 4 | \n",
142 | " 5 | \n",
143 | " 1977.78 | \n",
144 | " 555.56 | \n",
145 | " 2533.33 | \n",
146 | " 197222.22 | \n",
147 | "
\n",
148 | " \n",
149 | " | 5 | \n",
150 | " 6 | \n",
151 | " 1972.22 | \n",
152 | " 555.56 | \n",
153 | " 2527.78 | \n",
154 | " 196666.67 | \n",
155 | "
\n",
156 | " \n",
157 | " | 6 | \n",
158 | " 7 | \n",
159 | " 1966.67 | \n",
160 | " 555.56 | \n",
161 | " 2522.22 | \n",
162 | " 196111.11 | \n",
163 | "
\n",
164 | " \n",
165 | " | 7 | \n",
166 | " 8 | \n",
167 | " 1961.11 | \n",
168 | " 555.56 | \n",
169 | " 2516.67 | \n",
170 | " 195555.56 | \n",
171 | "
\n",
172 | " \n",
173 | " | 8 | \n",
174 | " 9 | \n",
175 | " 1955.56 | \n",
176 | " 555.56 | \n",
177 | " 2511.11 | \n",
178 | " 195000.00 | \n",
179 | "
\n",
180 | " \n",
181 | " | 9 | \n",
182 | " 10 | \n",
183 | " 1950.00 | \n",
184 | " 555.56 | \n",
185 | " 2505.56 | \n",
186 | " 194444.44 | \n",
187 | "
\n",
188 | " \n",
189 | " | 10 | \n",
190 | " 11 | \n",
191 | " 1944.44 | \n",
192 | " 555.56 | \n",
193 | " 2500.00 | \n",
194 | " 193888.89 | \n",
195 | "
\n",
196 | " \n",
197 | " | 11 | \n",
198 | " 12 | \n",
199 | " 1938.89 | \n",
200 | " 555.56 | \n",
201 | " 2494.44 | \n",
202 | " 193333.33 | \n",
203 | "
\n",
204 | " \n",
205 | "
\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 | " Parcela | \n",
159 | " Amortização | \n",
160 | " Juros | \n",
161 | " Valor da Parcela | \n",
162 | " Saldo Devedor | \n",
163 | "
\n",
164 | " \n",
165 | " \n",
166 | " \n",
167 | " | 0 | \n",
168 | " 1 | \n",
169 | " 489.01 | \n",
170 | " 1636.20 | \n",
171 | " 2125.22 | \n",
172 | " 204896.44 | \n",
173 | "
\n",
174 | " \n",
175 | " | 1 | \n",
176 | " 2 | \n",
177 | " 489.01 | \n",
178 | " 1632.31 | \n",
179 | " 2121.32 | \n",
180 | " 204407.42 | \n",
181 | "
\n",
182 | " \n",
183 | " | 2 | \n",
184 | " 3 | \n",
185 | " 489.01 | \n",
186 | " 1628.41 | \n",
187 | " 2117.43 | \n",
188 | " 203918.41 | \n",
189 | "
\n",
190 | " \n",
191 | " | 3 | \n",
192 | " 4 | \n",
193 | " 489.01 | \n",
194 | " 1624.52 | \n",
195 | " 2113.53 | \n",
196 | " 203429.40 | \n",
197 | "
\n",
198 | " \n",
199 | " | 4 | \n",
200 | " 5 | \n",
201 | " 489.01 | \n",
202 | " 1620.62 | \n",
203 | " 2109.63 | \n",
204 | " 202940.39 | \n",
205 | "
\n",
206 | " \n",
207 | "
\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 | " Parcela | \n",
256 | " Saldo Devedor Inicial | \n",
257 | " Amortização | \n",
258 | " Amortização Extra | \n",
259 | " Juros | \n",
260 | " Valor da Parcela | \n",
261 | " Saldo Devedor Final | \n",
262 | "
\n",
263 | " \n",
264 | " \n",
265 | " \n",
266 | " | 0 | \n",
267 | " 1 | \n",
268 | " 205385.450000 | \n",
269 | " 489.012976 | \n",
270 | " 5000.0 | \n",
271 | " 1636.203997 | \n",
272 | " 2125.216973 | \n",
273 | " 199896.437024 | \n",
274 | "
\n",
275 | " \n",
276 | " | 1 | \n",
277 | " 2 | \n",
278 | " 199896.437024 | \n",
279 | " 489.012976 | \n",
280 | " 5000.0 | \n",
281 | " 1592.475754 | \n",
282 | " 2081.488730 | \n",
283 | " 194407.424048 | \n",
284 | "
\n",
285 | " \n",
286 | " | 2 | \n",
287 | " 3 | \n",
288 | " 194407.424048 | \n",
289 | " 489.012976 | \n",
290 | " 5000.0 | \n",
291 | " 1548.747510 | \n",
292 | " 2037.760486 | \n",
293 | " 188918.411071 | \n",
294 | "
\n",
295 | " \n",
296 | " | 3 | \n",
297 | " 4 | \n",
298 | " 188918.411071 | \n",
299 | " 489.012976 | \n",
300 | " 5000.0 | \n",
301 | " 1505.019267 | \n",
302 | " 1994.032243 | \n",
303 | " 183429.398095 | \n",
304 | "
\n",
305 | " \n",
306 | " | 4 | \n",
307 | " 5 | \n",
308 | " 183429.398095 | \n",
309 | " 489.012976 | \n",
310 | " 5000.0 | \n",
311 | " 1461.291023 | \n",
312 | " 1950.303999 | \n",
313 | " 177940.385119 | \n",
314 | "
\n",
315 | " \n",
316 | "
\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 | " Parcela | \n",
92 | " Amortização | \n",
93 | " Juros | \n",
94 | " Valor da Parcela | \n",
95 | " Saldo Devedor | \n",
96 | "
\n",
97 | " \n",
98 | " \n",
99 | " \n",
100 | " | 0 | \n",
101 | " 1 | \n",
102 | " 555.56 | \n",
103 | " 1593.30 | \n",
104 | " 2148.86 | \n",
105 | " 199444.44 | \n",
106 | "
\n",
107 | " \n",
108 | " | 1 | \n",
109 | " 2 | \n",
110 | " 555.56 | \n",
111 | " 1588.87 | \n",
112 | " 2144.43 | \n",
113 | " 198888.89 | \n",
114 | "
\n",
115 | " \n",
116 | " | 2 | \n",
117 | " 3 | \n",
118 | " 555.56 | \n",
119 | " 1584.45 | \n",
120 | " 2140.00 | \n",
121 | " 198333.33 | \n",
122 | "
\n",
123 | " \n",
124 | " | 3 | \n",
125 | " 4 | \n",
126 | " 555.56 | \n",
127 | " 1580.02 | \n",
128 | " 2135.58 | \n",
129 | " 197777.78 | \n",
130 | "
\n",
131 | " \n",
132 | " | 4 | \n",
133 | " 5 | \n",
134 | " 555.56 | \n",
135 | " 1575.60 | \n",
136 | " 2131.15 | \n",
137 | " 197222.22 | \n",
138 | "
\n",
139 | " \n",
140 | " | ... | \n",
141 | " ... | \n",
142 | " ... | \n",
143 | " ... | \n",
144 | " ... | \n",
145 | " ... | \n",
146 | "
\n",
147 | " \n",
148 | " | 355 | \n",
149 | " 356 | \n",
150 | " 555.56 | \n",
151 | " 22.13 | \n",
152 | " 577.68 | \n",
153 | " 2222.22 | \n",
154 | "
\n",
155 | " \n",
156 | " | 356 | \n",
157 | " 357 | \n",
158 | " 555.56 | \n",
159 | " 17.70 | \n",
160 | " 573.26 | \n",
161 | " 1666.67 | \n",
162 | "
\n",
163 | " \n",
164 | " | 357 | \n",
165 | " 358 | \n",
166 | " 555.56 | \n",
167 | " 13.28 | \n",
168 | " 568.83 | \n",
169 | " 1111.11 | \n",
170 | "
\n",
171 | " \n",
172 | " | 358 | \n",
173 | " 359 | \n",
174 | " 555.56 | \n",
175 | " 8.85 | \n",
176 | " 564.41 | \n",
177 | " 555.56 | \n",
178 | "
\n",
179 | " \n",
180 | " | 359 | \n",
181 | " 360 | \n",
182 | " 555.56 | \n",
183 | " 4.43 | \n",
184 | " 559.98 | \n",
185 | " 0.00 | \n",
186 | "
\n",
187 | " \n",
188 | "
\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 | " Parcela | \n",
253 | " Saldo Devedor Inicial | \n",
254 | " Amortização | \n",
255 | " Amortização Extra | \n",
256 | " Juros | \n",
257 | " Valor da Parcela | \n",
258 | " Saldo Devedor Final | \n",
259 | "
\n",
260 | " \n",
261 | " \n",
262 | " \n",
263 | " | 0 | \n",
264 | " 1 | \n",
265 | " 200000.000000 | \n",
266 | " 555.555556 | \n",
267 | " 5000.0 | \n",
268 | " 1593.300789 | \n",
269 | " 2148.856344 | \n",
270 | " 194444.444444 | \n",
271 | "
\n",
272 | " \n",
273 | " | 1 | \n",
274 | " 2 | \n",
275 | " 194444.444444 | \n",
276 | " 555.555556 | \n",
277 | " 5000.0 | \n",
278 | " 1549.042433 | \n",
279 | " 2104.597989 | \n",
280 | " 188888.888889 | \n",
281 | "
\n",
282 | " \n",
283 | " | 2 | \n",
284 | " 3 | \n",
285 | " 188888.888889 | \n",
286 | " 555.555556 | \n",
287 | " 5000.0 | \n",
288 | " 1504.784078 | \n",
289 | " 2060.339634 | \n",
290 | " 183333.333333 | \n",
291 | "
\n",
292 | " \n",
293 | " | 3 | \n",
294 | " 4 | \n",
295 | " 183333.333333 | \n",
296 | " 555.555556 | \n",
297 | " 5000.0 | \n",
298 | " 1460.525723 | \n",
299 | " 2016.081278 | \n",
300 | " 177777.777778 | \n",
301 | "
\n",
302 | " \n",
303 | " | 4 | \n",
304 | " 5 | \n",
305 | " 177777.777778 | \n",
306 | " 555.555556 | \n",
307 | " 5000.0 | \n",
308 | " 1416.267368 | \n",
309 | " 1971.822923 | \n",
310 | " 172222.222222 | \n",
311 | "
\n",
312 | " \n",
313 | " | 5 | \n",
314 | " 6 | \n",
315 | " 172222.222222 | \n",
316 | " 555.555556 | \n",
317 | " 5000.0 | \n",
318 | " 1372.009012 | \n",
319 | " 1927.564568 | \n",
320 | " 166666.666667 | \n",
321 | "
\n",
322 | " \n",
323 | " | 6 | \n",
324 | " 7 | \n",
325 | " 166666.666667 | \n",
326 | " 555.555556 | \n",
327 | " 5000.0 | \n",
328 | " 1327.750657 | \n",
329 | " 1883.306213 | \n",
330 | " 161111.111111 | \n",
331 | "
\n",
332 | " \n",
333 | " | 7 | \n",
334 | " 8 | \n",
335 | " 161111.111111 | \n",
336 | " 555.555556 | \n",
337 | " 5000.0 | \n",
338 | " 1283.492302 | \n",
339 | " 1839.047857 | \n",
340 | " 155555.555556 | \n",
341 | "
\n",
342 | " \n",
343 | " | 8 | \n",
344 | " 9 | \n",
345 | " 155555.555556 | \n",
346 | " 555.555556 | \n",
347 | " 5000.0 | \n",
348 | " 1239.233947 | \n",
349 | " 1794.789502 | \n",
350 | " 150000.000000 | \n",
351 | "
\n",
352 | " \n",
353 | " | 9 | \n",
354 | " 10 | \n",
355 | " 150000.000000 | \n",
356 | " 555.555556 | \n",
357 | " 5000.0 | \n",
358 | " 1194.975591 | \n",
359 | " 1750.531147 | \n",
360 | " 144444.444444 | \n",
361 | "
\n",
362 | " \n",
363 | " | 10 | \n",
364 | " 11 | \n",
365 | " 144444.444444 | \n",
366 | " 555.555556 | \n",
367 | " 5000.0 | \n",
368 | " 1150.717236 | \n",
369 | " 1706.272792 | \n",
370 | " 138888.888889 | \n",
371 | "
\n",
372 | " \n",
373 | " | 11 | \n",
374 | " 12 | \n",
375 | " 138888.888889 | \n",
376 | " 555.555556 | \n",
377 | " 5000.0 | \n",
378 | " 1106.458881 | \n",
379 | " 1662.014437 | \n",
380 | " 133333.333333 | \n",
381 | "
\n",
382 | " \n",
383 | " | 12 | \n",
384 | " 13 | \n",
385 | " 133333.333333 | \n",
386 | " 555.555556 | \n",
387 | " 5000.0 | \n",
388 | " 1062.200526 | \n",
389 | " 1617.756081 | \n",
390 | " 127777.777778 | \n",
391 | "
\n",
392 | " \n",
393 | " | 13 | \n",
394 | " 14 | \n",
395 | " 127777.777778 | \n",
396 | " 555.555556 | \n",
397 | " 5000.0 | \n",
398 | " 1017.942170 | \n",
399 | " 1573.497726 | \n",
400 | " 122222.222222 | \n",
401 | "
\n",
402 | " \n",
403 | " | 14 | \n",
404 | " 15 | \n",
405 | " 122222.222222 | \n",
406 | " 555.555556 | \n",
407 | " 5000.0 | \n",
408 | " 973.683815 | \n",
409 | " 1529.239371 | \n",
410 | " 116666.666667 | \n",
411 | "
\n",
412 | " \n",
413 | " | 15 | \n",
414 | " 16 | \n",
415 | " 116666.666667 | \n",
416 | " 555.555556 | \n",
417 | " 5000.0 | \n",
418 | " 929.425460 | \n",
419 | " 1484.981016 | \n",
420 | " 111111.111111 | \n",
421 | "
\n",
422 | " \n",
423 | " | 16 | \n",
424 | " 17 | \n",
425 | " 111111.111111 | \n",
426 | " 555.555556 | \n",
427 | " 5000.0 | \n",
428 | " 885.167105 | \n",
429 | " 1440.722660 | \n",
430 | " 105555.555556 | \n",
431 | "
\n",
432 | " \n",
433 | " | 17 | \n",
434 | " 18 | \n",
435 | " 105555.555556 | \n",
436 | " 555.555556 | \n",
437 | " 5000.0 | \n",
438 | " 840.908750 | \n",
439 | " 1396.464305 | \n",
440 | " 100000.000000 | \n",
441 | "
\n",
442 | " \n",
443 | " | 18 | \n",
444 | " 19 | \n",
445 | " 100000.000000 | \n",
446 | " 555.555556 | \n",
447 | " 5000.0 | \n",
448 | " 796.650394 | \n",
449 | " 1352.205950 | \n",
450 | " 94444.444444 | \n",
451 | "
\n",
452 | " \n",
453 | " | 19 | \n",
454 | " 20 | \n",
455 | " 94444.444444 | \n",
456 | " 555.555556 | \n",
457 | " 5000.0 | \n",
458 | " 752.392039 | \n",
459 | " 1307.947595 | \n",
460 | " 88888.888889 | \n",
461 | "
\n",
462 | " \n",
463 | " | 20 | \n",
464 | " 21 | \n",
465 | " 88888.888889 | \n",
466 | " 555.555556 | \n",
467 | " 5000.0 | \n",
468 | " 708.133684 | \n",
469 | " 1263.689239 | \n",
470 | " 83333.333333 | \n",
471 | "
\n",
472 | " \n",
473 | " | 21 | \n",
474 | " 22 | \n",
475 | " 83333.333333 | \n",
476 | " 555.555556 | \n",
477 | " 5000.0 | \n",
478 | " 663.875329 | \n",
479 | " 1219.430884 | \n",
480 | " 77777.777778 | \n",
481 | "
\n",
482 | " \n",
483 | " | 22 | \n",
484 | " 23 | \n",
485 | " 77777.777778 | \n",
486 | " 555.555556 | \n",
487 | " 5000.0 | \n",
488 | " 619.616973 | \n",
489 | " 1175.172529 | \n",
490 | " 72222.222222 | \n",
491 | "
\n",
492 | " \n",
493 | " | 23 | \n",
494 | " 24 | \n",
495 | " 72222.222222 | \n",
496 | " 555.555556 | \n",
497 | " 5000.0 | \n",
498 | " 575.358618 | \n",
499 | " 1130.914174 | \n",
500 | " 66666.666667 | \n",
501 | "
\n",
502 | " \n",
503 | " | 24 | \n",
504 | " 25 | \n",
505 | " 66666.666667 | \n",
506 | " 555.555556 | \n",
507 | " 5000.0 | \n",
508 | " 531.100263 | \n",
509 | " 1086.655818 | \n",
510 | " 61111.111111 | \n",
511 | "
\n",
512 | " \n",
513 | " | 25 | \n",
514 | " 26 | \n",
515 | " 61111.111111 | \n",
516 | " 555.555556 | \n",
517 | " 5000.0 | \n",
518 | " 486.841908 | \n",
519 | " 1042.397463 | \n",
520 | " 55555.555556 | \n",
521 | "
\n",
522 | " \n",
523 | " | 26 | \n",
524 | " 27 | \n",
525 | " 55555.555556 | \n",
526 | " 555.555556 | \n",
527 | " 5000.0 | \n",
528 | " 442.583552 | \n",
529 | " 998.139108 | \n",
530 | " 50000.000000 | \n",
531 | "
\n",
532 | " \n",
533 | " | 27 | \n",
534 | " 28 | \n",
535 | " 50000.000000 | \n",
536 | " 555.555556 | \n",
537 | " 5000.0 | \n",
538 | " 398.325197 | \n",
539 | " 953.880753 | \n",
540 | " 44444.444444 | \n",
541 | "
\n",
542 | " \n",
543 | " | 28 | \n",
544 | " 29 | \n",
545 | " 44444.444444 | \n",
546 | " 555.555556 | \n",
547 | " 5000.0 | \n",
548 | " 354.066842 | \n",
549 | " 909.622397 | \n",
550 | " 38888.888889 | \n",
551 | "
\n",
552 | " \n",
553 | " | 29 | \n",
554 | " 30 | \n",
555 | " 38888.888889 | \n",
556 | " 555.555556 | \n",
557 | " 5000.0 | \n",
558 | " 309.808487 | \n",
559 | " 865.364042 | \n",
560 | " 33333.333333 | \n",
561 | "
\n",
562 | " \n",
563 | " | 30 | \n",
564 | " 31 | \n",
565 | " 33333.333333 | \n",
566 | " 555.555556 | \n",
567 | " 5000.0 | \n",
568 | " 265.550131 | \n",
569 | " 821.105687 | \n",
570 | " 27777.777778 | \n",
571 | "
\n",
572 | " \n",
573 | " | 31 | \n",
574 | " 32 | \n",
575 | " 27777.777778 | \n",
576 | " 555.555556 | \n",
577 | " 5000.0 | \n",
578 | " 221.291776 | \n",
579 | " 776.847332 | \n",
580 | " 22222.222222 | \n",
581 | "
\n",
582 | " \n",
583 | " | 32 | \n",
584 | " 33 | \n",
585 | " 22222.222222 | \n",
586 | " 555.555556 | \n",
587 | " 5000.0 | \n",
588 | " 177.033421 | \n",
589 | " 732.588977 | \n",
590 | " 16666.666667 | \n",
591 | "
\n",
592 | " \n",
593 | " | 33 | \n",
594 | " 34 | \n",
595 | " 16666.666667 | \n",
596 | " 555.555556 | \n",
597 | " 5000.0 | \n",
598 | " 132.775066 | \n",
599 | " 688.330621 | \n",
600 | " 11111.111111 | \n",
601 | "
\n",
602 | " \n",
603 | " | 34 | \n",
604 | " 35 | \n",
605 | " 11111.111111 | \n",
606 | " 555.555556 | \n",
607 | " 5000.0 | \n",
608 | " 88.516710 | \n",
609 | " 644.072266 | \n",
610 | " 5555.555556 | \n",
611 | "
\n",
612 | " \n",
613 | "
\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 |
--------------------------------------------------------------------------------