Factor Investing Library
Project description
Factor Investing LIBrary is a lightweight algorithmic trading Python library built for easy testing of predictive factors and portfolio rebalance via Oanda. Inspired by and compatible with Quantopian Open Source.
Installation
Install with pip:
$ pip install filib
Usage
Proposed workflow contains three steps. Here’s an example:
1. Assemble
Begin with imports, then hypothesize and create predictive factors as class methods:
from filib.oanda import Oanda # Currently only Oanda is available
from filib.helpers import * # Optional functions, useful for factor generation
class MyFactors(Oanda):
def momentum(self): # HYPOTHESIS: there is persistence in an asset's performance
factor = self.returns
split = [-1, -.003, .003, 1] # List of thresholds or int to split equally
return factor, split # Always return at least factor and follow this order
def relative_strenght_index(self): # H: signal oversold or overbought assets
import pandas as pd
import pandas_ta as ta # Example Technical Analysis Library
factor = pd.DataFrame({
instrument: self.price_data[instrument].ta.rsi(length=14)
for instrument, _ in self.price_data
}) * -1 # Short low factor values and long high factor values
split = [-100, -70, -30, 0]
return factor, split
def big_mac_index(self): # H: simplified Purchasing Power Parity theory
import quandl # Example Financial, Economic and Alternative Data Library
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 # If not specified split = 3 by default
2. Research
Initialize parameters (during the first run you will be asked to provide credentials):
research = MyFactors(
instruments = ['EUR_USD', 'GBP_USD', 'USD_JPY', 'AUD_USD', 'NZD_USD',
'USD_CAD', 'USD_CHF', 'USD_NOK', 'USD_SEK'], # Define universe
granularity = 'D', # Time range between rebalancing and between each candle
count = 500, # Number of historical candles to return for analysis
symbol = 'USD', # Optional, specify symbol to arrange your price data
periods = (1, 2, 3), # Optional, specify periods to analyze factor decay
split = 3, # Number of quantiles to split your combined factor data
long_short = True, # Trade only top and bottom quantile of combined factor
combination = 'sum_of_weights') # Select factor combination method
Check the performance of factors combined together:
>>> research.performance()
...
MyFactors - INFO - Factor `MyFactors_combined` Analytics:
Min Max Mean Size Returns (bps)
factor factor factor factor 1D 2D 3D
factor_quantile
1.0 -1.131 0.009 -0.238 1299 -0.551 -1.292 -0.845
2.0 -0.206 0.331 0.004 1213 -1.411 -2.811 -3.009
3.0 0.000 1.125 0.247 1232 -0.663 -1.289 -3.189
1D 2D 3D
- Information Coefficient: 0.005 -0.001 -0.007
- Factor Rank Autocorrelation: 0.09
- Annualized Sharpe Ratio: -0.46
- Annualized Alpha (Beta): -0.011 (0.119)
- Win Rate: 48.32%
- Risk / Reward: 0.99
- Profit Factor: 0.92
- Start Date: 2018-08-07
- End Date: 2020-03-10
- Duration: 581 days 00:00:00 (1.6 years)
- Rebalance every: 1D
- Compound Annual Growth Rate: -1.39%
- Annualized Volatility: 2.94%
- Maximum Drawdown: -4.09%
- Maximum Drawdown Duration: 23 days 00:00:00
...
Alternatively set selection rules with a query string to evaluate. Available metrics are:
ic: Information Coefficient based on Spearman’s 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:
>>> research.select(
... rules = 'abs(ic) > .01 or profit > 1', # Example query expression
... swap = 'cagr') # Align the signs of selected factors to specified metric
...
MyFactors - INFO - Factors with signs that meet the rules `abs(ic) > .01 or profit > 1`:
momentum -1.0
relative_strenght_index 1.0
MyFactors - INFO - Factor `MyFactors_selected` Analytics:
Min Max Mean Size Returns (bps)
factor factor factor factor 1D 2D 3D
factor_quantile
1.0 -1.000 0.026 -0.107 1815 -1.972 -3.022 -4.282
2.0 -0.152 1.000 0.095 757 2.189 3.523 3.425
3.0 0.000 0.880 0.222 551 1.257 -0.077 1.388
1D 2D 3D
- Information Coefficient: 0.017 0.01 0.016
- Factor Rank Autocorrelation: 0.04
- Annualized Sharpe Ratio: 0.30
- Annualized Alpha (Beta): 0.011 (0.025)
- Win Rate: 44.71%
- Risk / Reward: 0.92
- Profit Factor: 1.06
- Start Date: 2018-08-07
- End Date: 2020-03-10
- Duration: 581 days 00:00:00 (1.6 years)
- Rebalance every: 1D
- Compound Annual Growth Rate: 1.02%
- Annualized Volatility: 3.61%
- Maximum Drawdown: -4.34%
- Maximum Drawdown Duration: 371 days 00:00:00
...
3. Trade
Execute or schedule a script to rebalance your portfolio based on selected factors:
PLEASE USE AT YOUR OWN RISK - THIS CAN TRADE REAL MONEY - NO WARRANTY IS GIVEN
# strategy.py
from filib.oanda import Oanda
class SelectedFactors(Oanda):
def momentum(self):
factor = self.returns * -1.0 # Sign from the research
split = [-1, -.003, .003, 1]
return factor, split
def relative_strenght_index(self):
import pandas as pd
import pandas_ta as ta
factor = pd.DataFrame({
instrument: self.price_data[instrument].ta.rsi(length=14)
for instrument, _ in self.price_data
}) * -1
split = [-100, -70, -30, 0]
return factor, split
if __name__ == "__main__":
strategy = SelectedFactors(
instruments = ['EUR_USD', 'GBP_USD', 'USD_JPY', 'AUD_USD', 'NZD_USD',
'USD_CAD', 'USD_CHF', 'USD_NOK', 'USD_SEK'],
granularity = 'D',
count = 250,
symbol = 'USD',
split = 3,
accountID = '', # Your Oanda's account ID for creating orders
leverage = 7, # Set the leverage for the portfolio positions
long_short = True,
combination = 'sum_of_weights')
strategy.rebalance(live=True) # Actually place orders
Check portfolio positions and generated orders in a log file or by dry run:
>>> strategy.rebalance()
SelectedFactors - INFO - Portfolio from `2020-03-11 00:00:00+00:00`:
CHF -38.4%
SEK -8.1%
EUR -3.5%
GBP 0.0%
NOK 0.0%
NZD 0.0%
AUD 13.9%
CAD 15.7%
JPY 20.4%
- Account NAV: 10000.00 EUR
- Position Value: 0.00
- Needed Orders:
USD_CHF 30410
USD_SEK 6430
EUR_USD -2430
AUD_USD 16860
USD_CAD -12450
USD_JPY -16140
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.