Skip to content

Commit

Permalink
Chore/consistent type hints (#122)
Browse files Browse the repository at this point in the history
Using type hints throughout FinQuant and introducing type checks in
functions/methods that raise appropriate error messages if an argument
is of an unexpected type.
This commit also introduces custom data types, e.g. `FLOAT` as
`Union[np.floating, float]` and more to simplify type hints. Moreover,
type validation is now done with a new module/function `type_validation`
that also simplifies type validations.
Finally, the documentation for all modules in `finquant` has been
updated.
This closes  #94 and also closes #118.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
fmilthaler and github-actions[bot] authored Aug 15, 2023
1 parent 8a25d0a commit 2ca498c
Show file tree
Hide file tree
Showing 35 changed files with 1,999 additions and 1,040 deletions.
25 changes: 22 additions & 3 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,28 @@ jobs:
python -m pip install .[test]
- name: Run tests
id: tests
run: make test
continue-on-error: true

- name: Analysing the code with pylint
if: ${{ matrix.python-version }} == '3.10'
- name: Pylint analysis
id: pylint_analysis
run: |
pylint --fail-under=9 $(git ls-files '*.py')
python -m pylint --fail-under=10 $(git ls-files '*.py')
continue-on-error: true

- name: mypy analysis
id: mypy_analysis
run: |
python -m mypy *.py finquant
continue-on-error: true

- name: Check for Failures
run: |
if [[ "${{ steps.tests.outcome }}" != "success" || "${{ steps.pylint_analysis.outcome }}" != "success" || "${{ steps.mypy_analysis.outcome }}" != "success" ]]; then
echo "Pipeline failed due to errors in the following steps:"
echo "Tests: ${{ steps.tests.outcome }}"
echo "Pylint: ${{ steps.pylint_analysis.outcome }}"
echo "mypy: ${{ steps.mypy_analysis.outcome }}"
exit 1
fi
7 changes: 7 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[MASTER]
# Ignore certain files or directories during analysis
ignore-paths=tests/,docs/,example/
extension-pkg-whitelist=pydantic

[REPORTS]
# Set the output format for `pylint` messages (text, colorized, json, etc.)
Expand All @@ -14,11 +15,17 @@ max-line-length=120
disable=
C0114, # Missing module docstring
C0116, # Missing function docstring
R0902, # Too many instance attributes
R0903, # Too few public methods
R0913, # Too many arguments
R0914, # Too many local variables
R1705, # Unnecessary "else" after "return"
W1514, # Unspecified encoding,

# Include additional pylint messages or message categories
#enable=
# C0114, # Missing module, function, class docstring
# R0903, # Too few public methods

[FORMAT]
good-names = pf, df, ef, mc, mu
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@ your branch name should be something like bugfix/print-statement-portfolio-prope
For the automated versioning to work, the branch name is required to start with `bugfix/` or one of the other
above mentioned patterns.

### Custom data types
[FinQuant defines a number of custom data types](https://finquant.readthedocs.io/en/latest/developers.html#data-types)
in the module `finquant.data_types`.

These data types are useful as lots of functions/methods in FinQuant allow arguments to be of different data types.
For example:
- `data` is often accepted as either a `pandas.Series` or `pandas.DataFrame`, or
- `risk_free_rate` could be a Python `float` or a `numpy.float64` among others.

To accommodate and simplify this, custom data types are defined in the module `finquant.data_types`.
Please familiarize yourself with those and add more if your code requires them.

### Data type validation
[FinQuant provides a module/function for type validation](https://finquant.readthedocs.io/en/latest/developers.html#type-validation),
which is used throughout the code base for type validation purposes. Said function simplifies checking an argument
against its expected type and reduces the amount of copy-pasted `if` and `raise` statements.
You can check out the source code in `finquant.type_utilities`.

### Commit your changes
Make your changes to the code, and write sensible commit messages.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<img src="https://img.shields.io/github/stars/fmilthaler/FinQuant.svg?style=social&label=Star" alt='pypi'>
</a>
<a href="https://pypi.org/project/FinQuant">
<img src="https://img.shields.io/badge/pypi-v0.6.1-brightgreen.svg?style=popout" alt='pypi'>
<img src="https://img.shields.io/badge/pypi-v0.6.2-brightgreen.svg?style=popout" alt='pypi'>
</a>
<a href="https://github.com/fmilthaler/FinQuant">
<img src="https://github.com/fmilthaler/finquant/actions/workflows/pytest.yml/badge.svg?branch=master" alt='GitHub Actions'>
Expand Down
2 changes: 1 addition & 1 deletion README.tex.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<img src="https://img.shields.io/github/stars/fmilthaler/FinQuant.svg?style=social&label=Star" alt='pypi'>
</a>
<a href="https://pypi.org/project/FinQuant">
<img src="https://img.shields.io/badge/pypi-v0.6.1-brightgreen.svg?style=popout" alt='pypi'>
<img src="https://img.shields.io/badge/pypi-v0.6.2-brightgreen.svg?style=popout" alt='pypi'>
</a>
<a href="https://github.com/fmilthaler/FinQuant">
<img src="https://github.com/fmilthaler/finquant/actions/workflows/pytest.yml/badge.svg?branch=master" alt='GitHub Actions'>
Expand Down
36 changes: 36 additions & 0 deletions docs/assets.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.. _assets:

#################
Individual Assets
#################
FinQuant provides classes for individual assets, such as stocks or funds. These are explained below.

Asset
=====
.. automodule:: finquant.asset
.. autoclass:: finquant.asset.Asset
:members:

.. automethod:: __init__


Stock
=====
Inherits from ``Asset``.

.. automodule:: finquant.stock
.. autoclass:: finquant.stock.Stock
:members:

.. automethod:: __init__


Market
======
Inherits from ``Asset``.

.. automodule:: finquant.market
.. autoclass:: finquant.market.Market
:members:

.. automethod:: __init__
11 changes: 9 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,14 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ["sphinx.ext.autodoc", "sphinx.ext.githubpages"]
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.githubpages",
"sphinx_autodoc_typehints",
]

# Make sure the 'members' flag is included
autodoc_default_flags = ["members"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["ntemplates"]
Expand All @@ -63,7 +70,7 @@
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = "en"

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
Expand Down
78 changes: 78 additions & 0 deletions docs/developers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
.. _developers:

####################
Notes for Developers
####################

.. note:: Contributions are welcome. If you want to add new functionality please

1. read through `CONTRIBUTIONS.md` in the root directory of the repository, and
2. familiarize yourself with the custom data types defined in FinQuant, and how type validation is achieved. You find relevant information below.

**********
Data Types
**********

Various custom data types are defined in ``finquant.data_types`` and used in FinQuant as type hints.

Description
###########

.. automodule:: finquant.data_types



Code Definitions
################

Array/List-Like Types
---------------------

.. autodata:: finquant.data_types.ARRAY_OR_LIST
:annotation:

.. autodata:: finquant.data_types.ARRAY_OR_DATAFRAME
:annotation:

.. autodata:: finquant.data_types.ARRAY_OR_SERIES
:annotation:

.. autodata:: finquant.data_types.SERIES_OR_DATAFRAME
:annotation:

List of Dict keys
-----------------

.. autodata:: finquant.data_types.LIST_DICT_KEYS
:annotation:

Numeric Types
-------------

.. autodata:: finquant.data_types.FLOAT
:annotation:

.. autodata:: finquant.data_types.INT
:annotation:

.. autodata:: finquant.data_types.NUMERIC
:annotation:


***************
Type validation
***************

This module provides a function ``type_validation`` that allow to effortlessly implement type validation.

Description
###########

.. automodule:: finquant.type_utilities


Code Definitions
################

.. autodata:: finquant.type_utilities.type_validation
:annotation:
8 changes: 5 additions & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

.. _PyPI: https://pypi.org/project/FinQuant/

#####################################
###################################
Welcome to FinQuant's documentation
#####################################
###################################

*FinQuant* is a program for financial portfolio management, analysis and optimisation. It is designed to generate an object that holds your data, e.g. stock prices of different stocks, which automatically computes the most common quantities, such as *Expected annual Return*, *Volatility* and *Sharpe Ratio*. Moreover, it provides a library for computing different kinds of *Returns* and visualising *Moving Averages* and *Bollinger Bands*. Finally, given a set of stocks, it also allows for finding optimised portfolios.

Expand Down Expand Up @@ -74,13 +74,15 @@ Table of Contents
:maxdepth: 2

quickstart
examples
portfolio
assets
quants
returns
movingaverage
efficientfrontier
montecarlo
examples
developers
license
about

Expand Down
14 changes: 4 additions & 10 deletions docs/portfolio.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,15 @@
Portfolio Management
####################

As mentioned above, *FinQuant* is a program for financial portfolio management, among others. The module ``finquant.portfolio`` does exactly that.
As mentioned above, *FinQuant* is a program for financial portfolio management, among others.
The module ``finquant.portfolio`` does exactly that.

.. note:: The impatient reader who simply wants to jump in and start using *FinQuant* is advised to jump to `build_portfolio`_ and have a look at and play around with the :ref:`examples`.
.. note:: The impatient reader who simply wants to jump in and start using *FinQuant* is advised
to jump to `build_portfolio`_ and have a look at and play around with the :ref:`examples`.

.. automodule:: finquant.portfolio


Stock
=====
.. autoclass:: finquant.stock.Stock
:members:

.. automethod:: __init__


Portfolio
=========
.. autoclass:: finquant.portfolio.Portfolio
Expand Down
14 changes: 7 additions & 7 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Building a Portfolio

Getting an object of ``Portfolio`` that holds stock prices of four different stocks, as well as its properties and interfaces to optimisation methods is as simple as:

.. code:: python
.. code-block:: python
from finquant.portfolio import build_portfolio
names = ['GOOG', 'AMZN', 'MCD', 'DIS']
Expand All @@ -25,15 +25,15 @@ The above uses *Quandl* in the background to download the requested data. For mo

If preferred, *FinQuant* also allows to fetch stock price data from |yahoofinance|_. The code snippet below is the equivalent to the above, but using yfinance_ instead (default value for ``data_api`` is ``"quandl"``):

.. code:: python
.. code-block:: python
from finquant.portfolio import build_portfolio
names = ['GOOG', 'AMZN', 'MCD', 'DIS']
pf = build_portfolio(names=names, data_api="yfinance")
Alternatively, if you already are in possession of stock prices you want to analyse/optimise, you can do the following.

.. code:: python
.. code-block:: python
import pathlib
from finquant.portfolio import build_portfolio
Expand All @@ -50,13 +50,13 @@ Properties of the Portfolio

The portfolio's properties are automatically computed as it is being built. One can have a look at them with

.. code:: python
.. code-block:: python
pf.properties()
which shows

.. code::
.. code-block:: python
----------------------------------------------------------------------
Stocks: GOOG, AMZN, MCD, DIS
Expand Down Expand Up @@ -89,7 +89,7 @@ Moving Averages

.. note:: When computing/visualising a *band* of Moving Averages, ``compute_ma`` automatically finds the buy/sell signals based on the minimum/maximum *Moving Average* that were computed and highlights those with arrow up/down markers.

.. code:: python
.. code-block:: python
from finquant.moving_average import compute_ma, ema
# get stock data for Disney
Expand Down Expand Up @@ -120,7 +120,7 @@ Portfolio Optimisation
======================
*FinQuant* allows the optimisation of financial portfolios along the *Efficient Frontier* by minimising a cost/objective function. *FinQuant* uses the Python package ``scipy`` for the minimisation. Alternatively, a *Monte Carlo* approach is implemented as well. The below demonstrates how *FinQuant* performs such an optimisation and visualisation of the results.

.. code::
.. code-block:: python
# Monte Carlo optimisation
opt_w, opt_res = pf.mc_optimisation(num_trials=5000)
Expand Down
Loading

0 comments on commit 2ca498c

Please sign in to comment.