filib 0.6.0
Factor Investing Library
License: Apache License 2.0
Requires Python: >=3.6

filib
=====

.. image:: https://img.shields.io/pypi/pyversions/filib
    :target: https://pypi.org/project/filib/
    :alt: PyPI - Python Version

.. image:: https://img.shields.io/pypi/v/filib
    :target: https://pypi.org/project/filib/
    :alt: PyPI

.. image:: https://img.shields.io/pypi/status/filib
    :target: https://pypi.org/project/filib/
    :alt: PyPI - Status

.. image:: https://img.shields.io/github/license/prmkowalski/filib
    :target: https://github.com/prmkowalski/filib/blob/master/LICENSE
    :alt: GitHub

.. image:: https://github.com/prmkowalski/filib/workflows/CI/badge.svg
    :target: https://github.com/prmkowalski/filib/actions?query=workflow%3ACI+branch%3Amaster
    :alt: CI - Status

.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
    :target: https://github.com/psf/black
    :alt: Black

`Factor Investing <https://en.wikipedia.org/wiki/Factor_investing>`_
LIBrary is a lightweight algorithmic trading Python library built for easy testing of
predictive factors and portfolio rebalance via
`Oanda <https://developer.oanda.com/rest-live-v20/introduction/>`_.
Inspired by and compatible with
`Quantopian Open Source <https://github.com/quantopian>`_.

    **NOTE**: This library is currently in alpha stage. Until it becomes stable
    I strongly recommend using practice account for testing and trading. You can also
    expect major changes without warnings, mostly responses to
    `Issues <https://github.com/prmkowalski/filib/issues>`_.

`Changelog » <https://github.com/prmkowalski/filib/releases>`_

Installation
------------

Install with `pip <https://pip.pypa.io/en/stable/>`_:

.. code:: bash

    $ pip install filib

Usage
-----

Proposed workflow contains three steps. Here's an example:

1. Assemble
^^^^^^^^^^^

Begin with imports, create hypotheses and write functions with predictive factors:

.. code:: python

    from filib.oanda import Oanda  # Currently only Oanda FOREX is available
    from filib.helpers import *  # Optional, useful for factor generation


    class MyFactors(Oanda):
        def momentum(self):  # THEORY: Persistence in asset performance
            factor = self.returns  # Write down your factor formula
            return factor  # By default split factor data to 3 quantiles

        @swap_sign  # Short high and long low factor values
        def relative_strenght_index(self):  # THEORY: Oversold / overbought indicator
            factor = rsi(self.close, 14)
            split = [0, 30, 70, 100]  # List of thresholds or int to split equally
            return factor, split  # Follow this order: factor, split

        def big_mac_index(self):  # THEORY: Simplified Purchasing Power Parity
            import quandl  # Financial, Economic and Alternative Data

            iso_codes = get_iso_codes(self.price_data)
            codes = [f"ECONOMIST/BIGMAC_{COUNTRY}.5" for COUNTRY in iso_codes]
            factor = quandl.get(codes).dropna(how="all", axis=1)
            factor.columns = [iso_codes[c.split("_")[1].split()[0]] for c in factor]
            factor.index = factor.index.tz_localize("UTC")  # Convert time zone to UTC
            return factor

2. Research
^^^^^^^^^^^

Initialize parameters (during the first run you will be asked to provide credentials):

.. code:: python

    model = MyFactors(
        instruments=["EUR_USD", "GBP_USD", "USD_JPY", "AUD_USD", "NZD_USD", "USD_CAD",
                     "USD_CHF", "USD_NOK", "USD_SEK"],  # Define universe
        symbol="USD",  # Optional, specify symbol to arrange price data
        granularity="D",  # Time period between each candle and between each rebalance
        count=500,  # Number of historical OHLCV candles to return for analysis
        periods=(1, 2, 3),  # Optional, specify periods for factor decay analysis
        split=3,  # Number of quantiles to split combined factor data
        long_short=True,  # Trade only top and bottom factor quantile
        combination="sum_of_weights",  # Formula for combining factors together
        leverage=3,  # Multiplier for the portfolio positions
    )

Check the performance of factors combined together:

.. code::

    >>> model.performance()
    Collecting price data: |██████████████████████████████| 9/9 [100%] in 4.0 s
    Preparing factor data: |██████████████████████████████| 3/3 [100%] in 12.0 s

    MyFactors - INFO - Factor `MyFactors_combined` Analytics:

                    Min    Max    Mean   Size    Returns (bps)
                    factor factor factor factor            1D     2D     3D
    factor_quantile
    1.0             -1.003  0.000 -0.237   1499        -1.337 -2.068 -2.320
    2.0             -0.243  0.210  0.005   1461        -2.582 -3.299 -5.138
    3.0             -0.027  0.973  0.238   1459         0.892 -0.835 -2.266

                                1D     2D     3D
    - Information Coefficient:  0.037  0.001  0.0
    - Factor Rank Autocorrelation: 0.05

    - Annualized Sharpe Ratio: 0.76
    - Annualized Alpha (Beta): 0.080 (0.042)
    - Win Rate: 52.55%
    - Risk / Reward: 1.02
    - Profit Factor: 1.15

    - Start Date: 2018-07-11
    - End Date: 2020-05-27
    - Duration: 686 days 00:00:00 (1.9 years)
    - Rebalance every: 1D

    - Compound Annual Growth Rate: 7.78%
    - Annualized Volatility: 10.44%
    - Maximum Drawdown: -11.49%
    - Maximum Drawdown Duration: 434 days 00:00:00
    ...

Alternatively set selection rules with a
`query <https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.query.html>`_
string to evaluate. Available metrics:

- **ic**:       Information Coefficient based on Spearman Rank Correlation
- **autocorr**: Factor Rank Autocorrelation
- **sharpe**:   Annualized Sharpe Ratio
- **beta**:     Annualized Beta as exposure to trading universe
- **alpha**:    Annualized Alpha as excess returns over trading universe
- **win**:      Win Rate
- **rr**:       Risk / Reward Ratio
- **profit**:   Profit Factor = (sum of earnings) / (sum of losses)
- **cagr**:     Compound Annual Growth Rate

Then analyze the performance of individual factors and select those that meet the rules:

.. code::

    >>> model.select(
    ...     rules="abs(ic) > .01 or profit > 1",  # Example query expression
    ...     swap_to="cagr",  # Align the signs of selected factors to specified metric
    ...     inplace=True,  # Modify model to contain only selected factors
    ... )
    Preparing performance: |██████████████████████████████| 3/3 [100%] in 6.2 s

    MyFactors - INFO - Factors with signs that meet the rules `abs(ic) > .01 or profit > 1`:

    big_mac_index             -1.0
    momentum                   1.0
    relative_strenght_index    1.0

3. Trade
^^^^^^^^

Check portfolio positions based on selected factors and generated submitted orders:

**PLEASE USE AT YOUR OWN RISK - THIS CAN TRADE REAL MONEY - NO WARRANTY IS GIVEN**

.. code::

    >>> model.rebalance(
    ...     accountID="",  # Your Oanda Account Identifier
    ...     live=True,  # Actually place orders
    ... )
    MyFactors - INFO - Portfolio from `2020-05-28 00:00:00+00:00`:

    NOK    -19.5%
    SEK    -15.3%
    CHF    -15.2%
    AUD      0.0%
    EUR      0.0%
    GBP      0.0%
    NZD      9.0%
    CAD     15.3%
    JPY     25.8%

    - Account NAV: 8423.77 EUR
    - Position Value: 25382.12
    - Submitted Orders:

    USD_JPY   -7240
    NZD_USD    4050
    USD_CAD   -4280
    USD_CHF    4260
    USD_NOK    5490
    USD_SEK    4280

Contributing
------------

Pull requests are welcome. For major changes, please open an issue first to discuss
what you would like to change.