Skip to content

Commit

Permalink
Updated tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Divasco committed Oct 8, 2024
1 parent 4165fe3 commit 43a9161
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 8 deletions.
6 changes: 4 additions & 2 deletions garpar/datasets/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ def load_MERVAL(imputation="ffill", first=None, last=None):
# pd.to_datetime(None) -> None
first, last = pd.to_datetime(first), pd.to_datetime(last)

if imputation in ("backfill", "bfill", "pad", "ffill"):
df.fillna(method=imputation, inplace=True)
if imputation in ("backfill", "bfill"):
df.bfill(inplace=True)
elif imputation in ("pad", "ffill"):
df.ffill(inplace=True)
else:
df.fillna(value=imputation, inplace=True)

Expand Down
53 changes: 49 additions & 4 deletions tests/optimize/test_mean_variance.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from garpar import Portfolio

from garpar.optimize import mean_variance
from garpar.optimize.mean_variance import MVOptimizer, Markowitz

from garpar import datasets

Expand All @@ -23,6 +23,52 @@

import pytest

# =============================================================================
# TESTS MV
# =============================================================================

def test_MVOptimizer_default_initialization():
optimizer = MVOptimizer()
assert optimizer.method == "max_sharpe"
assert optimizer.weight_bounds == (0, 1)
assert optimizer.market_neutral is False

def test_MVOptimizer_custom_initialization():
optimizer = MVOptimizer(method="min_volatility", weight_bounds=(-1, 1))
assert optimizer.method == "min_volatility"
assert optimizer.weight_bounds == (-1, 1)

@pytest.mark.parametrize("price_distribution", pytest.DISTRIBUTIONS)
def test_MVOptimizer_calculate_weights_max_sharpe(risso_portfolio, price_distribution):
pf = risso_portfolio(random_state=42, distribution=price_distribution)
optimizer = MVOptimizer(risk_free_rate=0.001)
weights, meta = optimizer._calculate_weights(pf)
assert len(weights) == len(pf.stocks)
assert meta["name"] == "max_sharpe"
assert meta["risk_free_rate"] == 0.001

@pytest.mark.parametrize("price_distribution", pytest.DISTRIBUTIONS)
def test_MVOptimizer_min_volatility(risso_portfolio, price_distribution):
pf = risso_portfolio(random_state=42, distribution=price_distribution)
optimizer = MVOptimizer(method="min_volatility")
weights, meta = optimizer._calculate_weights(pf)
assert len(weights) == len(pf.stocks)
assert meta["name"] == "min_volatility"

@pytest.mark.parametrize("price_distribution", pytest.DISTRIBUTIONS)
def test_MVOptimizer_invalid_method(risso_portfolio, price_distribution):
pf = risso_portfolio(random_state=42, distribution=price_distribution)
optimizer = MVOptimizer(method="unknown_method")
with pytest.raises(ValueError):
optimizer._calculate_weights(pf)

@pytest.mark.parametrize("price_distribution", pytest.DISTRIBUTIONS)
def test_MVOptimizer_coerce_target_return(risso_portfolio, price_distribution):
pf = risso_portfolio(random_state=42, distribution=price_distribution)
optimizer = MVOptimizer(target_return=None)
coerced_return = optimizer._coerce_target_return(pf)
assert coerced_return == 0.05 # The minimum absolute return from mock portfolio

# =============================================================================
# MARKOWITZ TEST
# =============================================================================
Expand All @@ -39,7 +85,7 @@ def test_Markowitz_optimize():
)

# Instance
markowitz = mean_variance.Markowitz(target_return=1.0)
markowitz = Markowitz(target_return=1.0)

# Tested method
result = markowitz.optimize(pf)
Expand Down Expand Up @@ -71,7 +117,7 @@ def test_Markowitz_optimize_default_target_return():
)

# Instance
markowitz = mean_variance.Markowitz()
markowitz = Markowitz()

# Tested method
result = markowitz.optimize(pf)
Expand All @@ -91,4 +137,3 @@ def test_Markowitz_optimize_default_target_return():

assert isinstance(result.weights, pd.Series)
pd.testing.assert_series_equal(result.weights, expected_weights)

33 changes: 31 additions & 2 deletions tests/optimize/test_opt_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from garpar import Portfolio

from garpar.optimize import opt_base as base
from garpar.optimize.opt_base import OptimizerABC, MeanVarianceFamilyMixin

import numpy as np

Expand All @@ -30,9 +30,38 @@
def test_OptimizerABC__calculate_weights_not_implementhed(risso_portfolio):
pf = risso_portfolio(random_state=42, stocks=2)

class FooOptimizer(base.MeanVarianceFamilyMixin, base.OptimizerABC):
class FooOptimizer(MeanVarianceFamilyMixin, OptimizerABC):
def _calculate_weights(self, pf):
return super()._calculate_weights(pf)

with pytest.raises(NotImplementedError):
FooOptimizer().optimize(pf)


def test_optimizerabc_family_not_string():
"""Test that an error is raised if 'family' is not a string."""

with pytest.raises(TypeError, match="'InvalidOptimizer.family' must be redefined as string"):
class InvalidOptimizer(OptimizerABC):
family = 123 # Not a string

def test_optimizerabc_family_undefined():
"""Test that an error is raised if 'family' is not defined."""

with pytest.raises(TypeError, match="'UndefinedFamilyOptimizer.family' must be redefined as string"):
class UndefinedFamilyOptimizer(OptimizerABC):
pass

def test_optimizerabc_family_valid():
"""Test that no error is raised when 'family' is a valid string."""

class ValidOptimizer(OptimizerABC):
family = "MeanVariance"

assert ValidOptimizer.family == "MeanVariance"

def test_OptimizerABC_get_family():
class TestMeanVarianceFamily(MeanVarianceFamilyMixin, OptimizerABC):
pass

assert TestMeanVarianceFamily.get_optimizer_family() == "mean-variance"
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ envlist =
py311,
py312,
coverage,
report


# =============================================================================
Expand Down

0 comments on commit 43a9161

Please sign in to comment.