Skip to main content

🔬 Quantitative analysis and management for financial applications.

Project description

🔎 Overview

The goal of finq is to provide an all-in-one Python library for quantitative portfolio analysis and optimization on historical and real-time financial data.

NOTE: Features are currently being determined and developed continuously. The repo is undergoing heavy modifications and could introduce breaking changes up until first major release. Current version is v0.4.0.

📦 Installation

Either clone this repository and perform a local install with poetry accordingly

git clone https://github.com/wilhelmagren/finq.git
cd finq
poetry install

or install the most recent release from the Python Package Index (PyPI).

pip install pyfinq

🚀 Example usage

finq supports a large number of major world indices which can be used through their respective Dataset implementation. To download all ticker OHLC data for a period and saving it locally for the OMXS30 index, you can do the following:

from finq.datasets import OMXS30

dataset = OMXS30(save=True)
dataset.run("2y")

The .run(period) function is a convenient wrapper for three other functions. The alternative way would be by running:

dataset.fetch_data("2y").fix_missing_data().verify_data()

and for a full list of all implemented indices, please take a look at the following link.

You can also define custom datasets, which may not be an already available major world index. To do that you need to use the CustomDataset and provide both a list of security names and their ticker symbols which are to be included in your dataset. Furthermore, you need to specify what market the ticker symbols are available on, e.g., NASDAQ or OMX. In code it can look like this:

from finq.datasets import CustomDataset

names = ["Alfa Laval", "Boliden", "SEB A", "Sv. Handelsbanken A"]
symbols = ["ALFA.ST", "BOL.ST", "SEB-A.ST", "SHB-A.ST"]

dataset = CustomDataset(names, symbols, market="OMX", save=False)
dataset = dataset.run("6mo")
...

The Dataset class supports visualizing any OHLC historical data for all considered tickers. Calling the .visualize(price_type="Close") function on the OMXS30 index would yield the following plot:

Show dataset plot

OMXS30 Visualization 6 months

and the majority of labels and styles for the plot can be customized regularly with matplotlib styling. You can also choose to visualize more advanced plots, but only for individual assets, through the mplfinance library. The below image is a candle plot of the BOL.ST ticker from the OMXS30 index, with three moving averages.

Show ticker plot

BOL.ST Candle plot


You can create a Portfolio in a large number of ways. The most convenient way is to first initialize a Dataset like above, and then pass that dataset to the portfolio class constructor. The class also supports passing in a list of Asset objects, or a np.ndarray, or a pd.DataFrame. But for the latter three alternatives you need to also provide the security names and ticker symbols from which the data came from. All different methods are showed in the snipper below:

from finq import Portfolio

# All four alternatives are equally viable.
# The latter three are implemented for whenever
# you preferably only want to work with local data.
from_dataset = Portfolio(dataset)
from_assets = Portfolio(assets, names=["SEB-A.ST", ...], symbols=...)
from_numpy = Portfolio(np_arr, names=["SEB-A.ST", ...], symbols=...)
from_pandas = Portfolio(pd_df, names=["SEB-A.ST", ...], symbols=...)
...

To optimize your portfolio against some objective function, you use the optimize(...) function. Optimizing the mean variance expression (maximizing sharpe ratio) requires you to specify the objective function that you want to minimize, the initial weights of your portfolio, optionally the bounds and constraints of the portfolio weights. You can do it in the following way:

from finq import Portfolio
from finq.datasets import OMXS30
from finq.formulas import mean_variance

dataset = OMXS30(save=True)
dataset = dataset.run("2y")

portfolio = Portfolio(dataset)
portfolio.initialize_random_weights(
    "lognormal",
    size=(len(dataset), 1),
)

risk_tolerance = 1

portfolio.set_objective_function(
    mean_variance,
    risk_tolerance * portfolio.daily_covariance(),
    portfolio.daily_returns_mean(),
)

portfolio.set_objective_bounds(
    [(0, 0.2) for _ in range(len(dataset))],
)

portfolio.optimize(
    method="COBYLA",
    options={"maxiter": 1000},
)

portfolio.plot_mean_variance(n_samples=10000, figsize=(8, 5))

The above code is directly taken from one of the scripts available in the examples directory in this repo. Running it can yield the following comparative plot of the sharpe ratios for: your optimized portfolio weights, and randomly sampled portfolio weights.

Show sharpe ratio plot

OMXS30 sharpe ratio plot

📋 License

All code is to be held under a general MIT license, please see LICENSE for specific information.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyfinq-0.4.0.tar.gz (29.2 kB view hashes)

Uploaded Source

Built Distribution

pyfinq-0.4.0-py3-none-any.whl (42.7 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page