Skip to content

Commit efe145e

Browse files
committed
towards testing README.md
1 parent 8f16e10 commit efe145e

File tree

3 files changed

+45
-45
lines changed

3 files changed

+45
-45
lines changed

README.md

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -94,25 +94,31 @@ demonstrating how easy it is to find the long-only portfolio
9494
that maximises the Sharpe ratio (a measure of risk-adjusted returns).
9595

9696
```python
97-
import pandas as pd
98-
from pypfopt import EfficientFrontier
99-
from pypfopt import risk_models
100-
from pypfopt import expected_returns
97+
>>> import pandas as pd
98+
>>> from pypfopt import EfficientFrontier
99+
>>> from pypfopt import risk_models
100+
>>> from pypfopt import expected_returns
101101

102102
# Read in price data
103-
df = pd.read_csv("tests/resources/stock_prices.csv", parse_dates=True, index_col="date")
103+
>>> df = pd.read_csv("tests/resources/stock_prices.csv", parse_dates=True, index_col="date")
104104

105105
# Calculate expected returns and sample covariance
106-
mu = expected_returns.mean_historical_return(df)
107-
S = risk_models.sample_cov(df)
106+
>>> mu = expected_returns.mean_historical_return(df)
107+
>>> S = risk_models.sample_cov(df)
108108

109109
# Optimize for maximal Sharpe ratio
110-
ef = EfficientFrontier(mu, S)
111-
raw_weights = ef.max_sharpe()
112-
cleaned_weights = ef.clean_weights()
113-
ef.save_weights_to_file("weights.csv") # saves to file
114-
print(cleaned_weights)
115-
ef.portfolio_performance(verbose=True)
110+
>>> ef = EfficientFrontier(mu, S)
111+
>>> raw_weights = ef.max_sharpe()
112+
>>> cleaned_weights = ef.clean_weights()
113+
>>> ef.save_weights_to_file("weights.csv") # saves to file
114+
>>> cleaned_weights
115+
OrderedDict({'GOOG': 0.0458, 'AAPL': 0.06743, 'FB': 0.2008, 'BABA': 0.08494, 'AMZN': 0.03525, 'GE': 0.0, 'AMD': 0.0, 'WMT': 0.0, 'BAC': 0.0, 'GM': 0.0, 'T': 0.0, 'UAA': 0.0, 'SHLD': 0.0, 'XOM': 0.0, 'RRC': 0.0, 'BBY': 0.01587, 'MA': 0.3287, 'PFE': 0.20394, 'JPM': 0.0, 'SBUX': 0.01726})
116+
>>> ef.portfolio_performance(verbose=True)
117+
Expected annual return: 29.9%
118+
Annual volatility: 21.8%
119+
Sharpe Ratio: 1.38
120+
(0.29944709161230304, 0.21764331681393406, 1.375861643701672)
121+
116122
```
117123

118124
This outputs the following weights:
@@ -150,22 +156,17 @@ convert the above continuous weights to an actual allocation
150156
that you could buy. Just enter the most recent prices, and the desired portfolio size ($10,000 in this example):
151157

152158
```python
153-
from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices
159+
>>> from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices
154160

161+
>>> latest_prices = get_latest_prices(df)
155162

156-
latest_prices = get_latest_prices(df)
163+
>>> da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=10000)
164+
>>> allocation, leftover = da.greedy_portfolio()
165+
>>> print("Discrete allocation:", allocation)
166+
Discrete allocation: {'MA': 19, 'PFE': 57, 'FB': 12, 'BABA': 4, 'AAPL': 4, 'GOOG': 1, 'SBUX': 2, 'BBY': 2}
167+
>>> print("Funds remaining: ${:.2f}".format(leftover))
168+
Funds remaining: $17.46
157169

158-
da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=10000)
159-
allocation, leftover = da.greedy_portfolio()
160-
print("Discrete allocation:", allocation)
161-
print("Funds remaining: ${:.2f}".format(leftover))
162-
```
163-
164-
```txt
165-
12 out of 20 tickers were removed
166-
Discrete allocation: {'GOOG': 1, 'AAPL': 4, 'FB': 12, 'BABA': 4, 'BBY': 2,
167-
'MA': 20, 'PFE': 54, 'SBUX': 1}
168-
Funds remaining: $11.89
169170
```
170171

171172
_Disclaimer: nothing about this project constitues investment advice,

pypfopt/base_optimizer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,11 +571,11 @@ def portfolio_performance(
571571
print("Expected annual return: {:.1f}%".format(100 * mu))
572572
print("Annual volatility: {:.1f}%".format(100 * sigma))
573573
print("Sharpe Ratio: {:.2f}".format(sharpe))
574-
return mu, sigma, sharpe
574+
return float(mu), float(sigma), float(sharpe)
575575
else:
576576
if verbose:
577577
print("Annual volatility: {:.1f}%".format(100 * sigma))
578-
return None, sigma, None
578+
return None, float(sigma), None
579579

580580

581581
def _get_all_args(expression: cp.Expression) -> List[cp.Expression]:
Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1-
"""Tests for doctest examples in the project documentation.
1+
"""Tests that README.md Python code blocks execute without errors.
22
3-
This module contains tests that verify that the code examples in the project's
4-
documentation (specifically in the README file) can be executed successfully
5-
using Python's doctest module.
3+
This test extracts all fenced code blocks labeled as Python from README.md and
4+
executes them sequentially in a shared namespace. This ensures the examples in
5+
our documentation stay correct as the code evolves.
66
"""
77

8-
import doctest
8+
import os
9+
import re
10+
import textwrap
11+
import warnings
912
from pathlib import Path
1013

14+
import numpy as np
1115
import pytest
1216

17+
18+
import doctest
19+
20+
1321
@pytest.fixture()
1422
def readme_path() -> Path:
1523
"""Provide the path to the project's README.md file.
@@ -38,15 +46,6 @@ def readme_path() -> Path:
3846

3947

4048
def test_doc(readme_path):
41-
"""Test that the README file's code examples work correctly.
42-
43-
This test runs doctest on the project's README file to verify that all
44-
code examples in the file execute correctly and produce the expected output.
45-
46-
Parameters
47-
----------
48-
readme_path : Path
49-
Path to the README file to test
50-
51-
"""
52-
doctest.testfile(str(readme_path), module_relative=False, verbose=True, optionflags=doctest.ELLIPSIS)
49+
"""Test the README file with doctest."""
50+
result = doctest.testfile(str(readme_path), module_relative=False, verbose=True, optionflags=doctest.ELLIPSIS)
51+
assert result.failed == 0

0 commit comments

Comments
 (0)