robertmartin8 / PyPortfolioOpt

Financial portfolio optimisation in python, including classical efficient frontier, Black-Litterman, Hierarchical Risk Parity
https://pyportfolioopt.readthedocs.io/
MIT License
4.55k stars 959 forks source link

Incorrect File Extension Parsing in save_weights_to_file Method #600

Open janusson opened 3 months ago

janusson commented 3 months ago

Describe the bug The save_weights_to_file method incorrectly parses the file extension when the file path contains multiple periods. This results in a NotImplementedError even when a supported file extension (e.g., .txt, .json, .csv) is provided.

Expected behavior The weights should be saved to the file './exports/portfolio_weights.txt'

Code sample

import pandas as pd
from pypfopt.efficient_frontier import EfficientFrontier
from pypfopt.expected_returns import mean_historical_return
from pypfopt.risk_models import CovarianceShrinkage

# Define portfolio to optimize
PORTFOLIO_NAME = 'portfolio'

# Historical price data
portfolio_price_data = pd.read_csv(f'./exports/{PORTFOLIO_NAME}_collated.csv', parse_dates=True, index_col='Date')

# Calculate expected returns and covariance matrix
mu = mean_historical_return(portfolio_price_data)
S = CovarianceShrinkage(portfolio_price_data).ledoit_wolf()

# Create an EfficientFrontier object
ef = EfficientFrontier(mu, S)

# Optimize for maximum Sharpe ratio
weights = ef.max_sharpe()

# Clean weights
cleaned_weights = ef.clean_weights()

# Save optimized weights to file
ef.save_weights_to_file(f"./exports/{PORTFOLIO_NAME}_weights.txt")

Operating system, python version, PyPortfolioOpt version e.g Windows 11 Pro, python 3.11.3, PyPortfolioOpt 1.5.5

Additional context The issue comes about because the save_weights_to_file method incorrectly parses the file extension when the file path contains multiple periods. A more robust solution could be to use filename.split('.')[-1] to correctly extract the file extension. This change ensures that the method correctly identifies and handles the supported file extensions (.txt, .json, .csv).