Skip to content

Commit

Permalink
Merge pull request #47 from hudson-and-thames/develop
Browse files Browse the repository at this point in the history
Update version to 0.4.0
  • Loading branch information
PanPip authored Apr 15, 2021
2 parents 8316547 + 11080b1 commit 5f886f9
Show file tree
Hide file tree
Showing 70 changed files with 13,661 additions and 20 deletions.
7 changes: 7 additions & 0 deletions arbitragelab/codependence/codependence_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from arbitragelab.codependence.correlation import distance_correlation
from arbitragelab.codependence.gnpr_distance import spearmans_rho, gpr_distance, gnpr_distance
from arbitragelab.codependence.optimal_transport import optimal_transport_dependence
from arbitragelab.util import devadarsh


# pylint: disable=invalid-name
Expand Down Expand Up @@ -49,6 +50,9 @@ def get_dependence_matrix(df: pd.DataFrame, dependence_method: str, theta: float
Sets the relative area of correlation in a copula. [from 0 to 1] (0.2 by default)
:return: (pd.DataFrame) Dependence matrix.
"""

devadarsh.track('get_dependence_matrix')

# Get the feature names.
features_cols = df.columns.values
n = df.shape[1]
Expand Down Expand Up @@ -110,6 +114,9 @@ def get_distance_matrix(X: pd.DataFrame, distance_metric: str = 'angular') -> pd
:param distance_metric: (str) The distance metric to be used for generating the distance matrix.
:return: (pd.DataFrame) Distance matrix.
"""

devadarsh.track('get_distance_matrix')

if distance_metric == 'angular':
distfun = lambda x: ((1 - x).round(5) / 2.) ** .5
elif distance_metric == 'abs_angular':
Expand Down
1 change: 1 addition & 0 deletions arbitragelab/cointegration_approach/coint_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def __init__(self, ts_num: int, ts_length: int):
self.ts_num = ts_num
self.ts_length = ts_length
self.__price_params, self.__coint_params = self.initialize_params()

devadarsh.track('CointegrationSimulation')

@staticmethod
Expand Down
3 changes: 3 additions & 0 deletions arbitragelab/cointegration_approach/multi_coint.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import pandas as pd

from arbitragelab.cointegration_approach.johansen import JohansenPortfolio
from arbitragelab.util import devadarsh


class MultivariateCointegration:
Expand All @@ -38,6 +39,8 @@ def __init__(self, asset_df: pd.DataFrame, trade_df: pd.DataFrame):
self.__trade_df = trade_df
self.__coint_vec = None

devadarsh.track('MultivariateCointegration')

@staticmethod
def _missing_impute(price_df: pd.DataFrame, nan_method: str = 'ffill', order: int = 3) -> pd.DataFrame:
"""
Expand Down
7 changes: 7 additions & 0 deletions arbitragelab/cointegration_approach/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import pandas as pd
from sklearn.linear_model import LinearRegression

from arbitragelab.util import devadarsh

def get_half_life_of_mean_reversion(data: pd.Series) -> float:
"""
Expand All @@ -19,6 +20,8 @@ def get_half_life_of_mean_reversion(data: pd.Series) -> float:
:return: (float) Half-life of mean reversion
"""

devadarsh.track('get_half_life_of_mean_reversion')

reg = LinearRegression(fit_intercept=True)

training_data = data.shift(1).dropna().values.reshape(-1, 1)
Expand Down Expand Up @@ -46,6 +49,8 @@ def linear_trading_strategy(portfolio_series: pd.Series, sma_window: int = None,
:return: (pd.DataFrame) Mean-reverting portfolio series and target allocation on each day.
"""

devadarsh.track('linear_trading_strategy')

if sma_window is None:
# The book suggests to use window = speed of reversion
sma_window = int(get_half_life_of_mean_reversion(portfolio_series))
Expand Down Expand Up @@ -83,6 +88,8 @@ def bollinger_bands_trading_strategy(portfolio_series: pd.Series, sma_window: in
:return: (pd.DataFrame) Mean-reverting portfolio series and target allocation on each day.
"""

devadarsh.track('bollinger_bands_trading_strategy')

if exit_z_score >= entry_z_score:
raise ValueError('Exit Z-score can not be bigger than entry Z-Score.')

Expand Down
3 changes: 3 additions & 0 deletions arbitragelab/cointegration_approach/sparse_mr_portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from sklearn.preprocessing import normalize, StandardScaler

from arbitragelab.optimal_mean_reversion import OrnsteinUhlenbeck
from arbitragelab.util import devadarsh


class SparseMeanReversionPortfolio:
Expand Down Expand Up @@ -58,6 +59,8 @@ def __init__(self, assets: pd.DataFrame):
self._standardized = standard_data
self._standardized.columns = self._assets.columns

devadarsh.track('SparseMeanReversionPortfolio')

@property
def assets(self) -> pd.DataFrame:
"""
Expand Down
5 changes: 4 additions & 1 deletion arbitragelab/copula_approach/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

from arbitragelab.copula_approach.copula_calculation import (
find_marginal_cdf, ml_theta_hat, log_ml, sic, aic, hqic, construct_ecdf_lin, fit_nu_for_t_copula, scad_penalty,
scad_derivative, adjust_weights)
scad_derivative, adjust_weights, to_quantile)
from arbitragelab.copula_approach.copula_generate import (
Copula, Gumbel, Frank, Clayton, Joe, N13, N14, Gaussian, Student, Switcher)
from arbitragelab.copula_approach.copula_strategy import CopulaStrategy
from arbitragelab.copula_approach.copula_strategy_basic import BasicCopulaStrategy
from arbitragelab.copula_approach.copula_strategy_mpi import CopulaStrategyMPI
from arbitragelab.copula_approach.copula_generate_mixedcopula import (MixedCopula, CFGMixCop, CTGMixCop)
from arbitragelab.copula_approach.vine_copula_partner_selection import PartnerSelection
from arbitragelab.copula_approach.vinecop_generate import (RVineCop, CVineCop)
from arbitragelab.copula_approach.vinecop_strategy import CVineCopStrat
33 changes: 32 additions & 1 deletion arbitragelab/copula_approach/copula_calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
<https://www.tandfonline.com/doi/pdf/10.1080/01621459.2013.873366?casa_token=sey8HrojSgYAAAAA:TEMBX8wLYdGFGyM78UXSYm6hXl1Qp_K6wiLgRJf6kPcqW4dYT8z3oA3I_odrAL48DNr3OSoqkQsEmQ>`__
"""
# pylint: disable = invalid-name
from typing import Callable
from typing import Callable, Tuple
import numpy as np
import pandas as pd
import scipy.stats as ss
from scipy.interpolate import interp1d
from scipy.optimize import minimize
Expand Down Expand Up @@ -102,6 +103,36 @@ def bounded_ecdf(x):
# Vectorize it to work with arrays.
return np.vectorize(bounded_ecdf)

def to_quantile(data: pd.DataFrame) -> Tuple[pd.DataFrame, list]:
"""
Convert the data frame to quantile by row.
Not in place. Also returns the marginal cdfs of each column. This can work with more than just 2 columns.
The method returns:
- quantile_data: (pd.DataFrame) The calculated quantile data in a data frame with the original indexing.
- cdf_list: (list) The list of marginal cumulative density functions.
:param data: (pd.DataFrame) The original data in DataFrame.
:return: (tuple)
quantile_data: (pd.DataFrame) The calculated quantile data in a data frame with the original indexing.
cdf_list: (list) The list of marginal cumulative density functions.
"""

column_count = len(data.columns) # Number of columns.
cdf_lst = [None] * column_count # List to store all marginal cdf functions.
quantile_data_lst = [None] * column_count # List to store all quantile data in pd.Series.

# Loop through all columns.
for i in range(column_count):
cdf_lst[i] = construct_ecdf_lin(data.iloc[:, i])
quantile_data_lst[i] = data.iloc[:, i].map(cdf_lst[i])

quantile_data = pd.concat(quantile_data_lst, axis=1) # Form the quantile DataFrame.

return quantile_data, cdf_lst

def ml_theta_hat(x: np.array, y: np.array, copula_name: str) -> float:
"""
Calculate empirical theta (theta_hat) for a type of copula by pseudo-maximum likelihood.
Expand Down
6 changes: 6 additions & 0 deletions arbitragelab/copula_approach/copula_generate_mixedcopula.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

import arbitragelab.copula_approach.copula_generate as cg
import arbitragelab.copula_approach.copula_calculation as ccalc
from arbitragelab.util import devadarsh


class MixedCopula(ABC):
Expand Down Expand Up @@ -225,6 +227,8 @@ def __init__(self, cop_params: tuple = None, weights: tuple = None):

self.copulas = [self.clayton_cop, self.t_cop, self.gumbel_cop]

devadarsh.track('CTGMixCop')

def fit(self, data: pd.DataFrame, max_iter: int = 25, gamma_scad: float = 0.6, a_scad: float = 6,
weight_margin: float = 1e-2) -> float:
"""
Expand Down Expand Up @@ -631,6 +635,8 @@ def __init__(self, cop_params: list = None, weights: list = None):

self.copulas = [self.clayton_cop, self.frank_cop, self.gumbel_cop]

devadarsh.track('CFGMixCop')

def fit(self, data: pd.DataFrame, max_iter: int = 25, gamma_scad: float = 0.6, a_scad: float = 6,
weight_margin: float = 1e-2) -> float:
"""
Expand Down
4 changes: 4 additions & 0 deletions arbitragelab/copula_approach/copula_strategy_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
import numpy as np
import pandas as pd
import scipy.stats as ss

import arbitragelab.copula_approach.copula_generate as cg
import arbitragelab.copula_approach.copula_calculation as ccalc
import arbitragelab.copula_approach.copula_generate_mixedcopula as cgmix
from arbitragelab.util import devadarsh


class BasicCopulaStrategy:
Expand Down Expand Up @@ -73,6 +75,8 @@ def __init__(self, copula: Union[cg.Copula, cgmix.MixedCopula] = None, open_thre
self._short_count = 0
self._exit_count = 0

devadarsh.track('BasicCopulaStrategy')

@staticmethod
def to_quantile(data: pd.DataFrame) -> Tuple[pd.DataFrame, list]:
"""
Expand Down
4 changes: 4 additions & 0 deletions arbitragelab/copula_approach/copula_strategy_mpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
from typing import Callable, Sequence, Union
import numpy as np
import pandas as pd

from arbitragelab.copula_approach.copula_strategy_basic import BasicCopulaStrategy
import arbitragelab.copula_approach.copula_generate as cg
import arbitragelab.copula_approach.copula_generate_mixedcopula as cgmix
from arbitragelab.util import devadarsh


class CopulaStrategyMPI(BasicCopulaStrategy):
Expand Down Expand Up @@ -62,6 +64,8 @@ def __init__(self, copula: Union[cg.Copula, cgmix.MixedCopula] = None,
self._short_count = 0
self._exit_count = 0

devadarsh.track('CopulaStrategyMPI')

@staticmethod
def to_returns(pair_prices: pd.DataFrame, fill_init_nan: Sequence[float] = (0, 0)) -> pd.DataFrame:
r"""
Expand Down
4 changes: 4 additions & 0 deletions arbitragelab/copula_approach/pairs_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import scipy.stats as ss
import pandas as pd

from arbitragelab.util import devadarsh


class PairsSelector:
r"""
Expand All @@ -27,6 +29,8 @@ def __init__(self):
Class initiation.
"""

devadarsh.track('PairsSelector')

def rank_pairs(self, stocks_universe: pd.DataFrame, method: str = 'kendall tau',
nan_option: Union[str, None] = 'forward fill',
keep_num_pairs: Union[int, None] = None) -> pd.Series:
Expand Down
Loading

0 comments on commit 5f886f9

Please sign in to comment.