mirror of
https://github.com/wassname/catalyst.git
synced 2026-09-12 12:12:04 +08:00
TST: Update to empyrical, increase test coverage
ENH: Resolve rebase conflict by using updated example_data.tar TST: Increase test coverage for risk portion of zipline
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
{"names": ["open", "high", "low", "close", "volume", "day", "id"]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
{"nbytes": 98584, "shape": [24646], "cbytes": 131072}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"chunklen": 32768, "dtype": "uint32", "expectedlen": 24646, "dflt": 0, "cparams": {"shuffle": true, "clevel": 5}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
{"nbytes": 98584, "shape": [24646], "cbytes": 131072}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"chunklen": 32768, "dtype": "uint32", "expectedlen": 24646, "dflt": 0, "cparams": {"shuffle": true, "clevel": 5}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
{"nbytes": 98584, "shape": [24646], "cbytes": 131072}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"chunklen": 32768, "dtype": "uint32", "expectedlen": 24646, "dflt": 0, "cparams": {"shuffle": true, "clevel": 5}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
{"nbytes": 98584, "shape": [24646], "cbytes": 131072}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"chunklen": 32768, "dtype": "uint32", "expectedlen": 24646, "dflt": 0, "cparams": {"shuffle": true, "clevel": 5}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
{"nbytes": 98584, "shape": [24646], "cbytes": 131072}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"chunklen": 32768, "dtype": "uint32", "expectedlen": 24646, "dflt": 0, "cparams": {"shuffle": true, "clevel": 5}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
{"nbytes": 98584, "shape": [24646], "cbytes": 131072}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"chunklen": 32768, "dtype": "uint32", "expectedlen": 24646, "dflt": 0, "cparams": {"shuffle": true, "clevel": 5}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
{"nbytes": 98584, "shape": [24646], "cbytes": 131072}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"chunklen": 32768, "dtype": "uint32", "expectedlen": 24646, "dflt": 0, "cparams": {"shuffle": true, "clevel": 5}}
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -17,15 +17,11 @@ import numpy as np
|
||||
import pandas as pd
|
||||
import zipline.finance.risk as risk
|
||||
from zipline.utils import factory
|
||||
import pandas as pd
|
||||
|
||||
from zipline.testing.fixtures import WithTradingEnvironment, ZiplineTestCase
|
||||
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
|
||||
from . import answer_key
|
||||
ANSWER_KEY = answer_key.ANSWER_KEY
|
||||
|
||||
RETURNS_BASE = 0.01
|
||||
RETURNS = [RETURNS_BASE] * 251
|
||||
|
||||
@@ -38,16 +34,10 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
|
||||
def init_instance_fixtures(self):
|
||||
super(TestRisk, self).init_instance_fixtures()
|
||||
<<<<<<< 30f5a8fcfa4a194f05d58f50cf0a2b06dd8085cc
|
||||
|
||||
|
||||
start_session = pd.Timestamp("2006-01-01", tz='UTC')
|
||||
end_session = pd.Timestamp("2006-12-29", tz='UTC')
|
||||
|
||||
=======
|
||||
start_date = pd.Timestamp('2006-01-01', tz=pytz.utc)
|
||||
end_date = pd.Timestamp('2006-12-29', tz=pytz.utc)
|
||||
>>>>>>> ENH: Change datetime.datetime to pd.Timestamp in tests
|
||||
self.sim_params = SimulationParameters(
|
||||
start_session=start_session,
|
||||
end_session=end_session,
|
||||
@@ -150,3 +140,7 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.max_drawdowns),
|
||||
True)
|
||||
|
||||
def test_representation(self):
|
||||
assert all([metric in self.cumulative_metrics.__repr__() for metric in
|
||||
self.cumulative_metrics.METRIC_NAMES])
|
||||
|
||||
+147
-72
@@ -17,8 +17,6 @@ import datetime
|
||||
import calendar
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import pytz
|
||||
import pandas as pd
|
||||
|
||||
import zipline.finance.risk as risk
|
||||
from zipline.utils import factory
|
||||
@@ -26,6 +24,8 @@ from zipline.utils import factory
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.testing.fixtures import WithTradingEnvironment, ZiplineTestCase
|
||||
|
||||
from zipline.finance.risk.period import RiskMetricsPeriod
|
||||
|
||||
RETURNS_BASE = 0.01
|
||||
RETURNS = [RETURNS_BASE] * 251
|
||||
|
||||
@@ -38,17 +38,14 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
|
||||
def init_instance_fixtures(self):
|
||||
super(TestRisk, self).init_instance_fixtures()
|
||||
|
||||
start_session = pd.Timestamp("2006-01-01", tz='UTC')
|
||||
|
||||
end_session = self.trading_calendar.minute_to_session_label(
|
||||
self.start_session = pd.Timestamp("2006-01-01", tz='UTC')
|
||||
self.end_session = self.trading_calendar.minute_to_session_label(
|
||||
pd.Timestamp("2006-12-31", tz='UTC'),
|
||||
direction="previous"
|
||||
)
|
||||
|
||||
self.sim_params = SimulationParameters(
|
||||
start_session=start_session,
|
||||
end_session=end_session,
|
||||
start_session=self.start_session,
|
||||
end_session=self.end_session,
|
||||
trading_calendar=self.trading_calendar,
|
||||
)
|
||||
self.algo_returns = factory.create_returns_from_list(
|
||||
@@ -63,16 +60,15 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
self.algo_returns,
|
||||
self.sim_params,
|
||||
benchmark_returns=self.benchmark_returns,
|
||||
trading_schedule=self.trading_schedule,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
|
||||
def test_factory(self):
|
||||
returns = [0.1] * 100
|
||||
r_objects = factory.create_returns_from_list(returns, self.sim_params)
|
||||
self.assertTrue(r_objects.index[-1] <= self.end_date)
|
||||
self.assertTrue(r_objects.index[0] >= self.start_date)
|
||||
self.assertTrue(r_objects.sample().values[0] == 0.1)
|
||||
self.assertTrue(r_objects.index[-1] <=
|
||||
pd.Timestamp('2006-12-31', tz='UTC'))
|
||||
|
||||
def test_drawdown(self):
|
||||
np.testing.assert_equal(
|
||||
@@ -123,7 +119,7 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
[20, 19, 23, 19, 22, 22, 20, 23, 20, 22, 21, 20])
|
||||
|
||||
def test_benchmark_volatility(self):
|
||||
# Volatility is calculated by a qrisk function so testing
|
||||
# Volatility is calculated by a empyrical function so testing
|
||||
# of period volatility will be limited to determine if the value is
|
||||
# numerical. This tests for its existence and format.
|
||||
np.testing.assert_equal(
|
||||
@@ -170,7 +166,7 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
DECIMAL_PLACES)
|
||||
|
||||
def test_algorithm_volatility(self):
|
||||
# Volatility is calculated by a qrisk function so testing
|
||||
# Volatility is calculated by a empyrical function so testing
|
||||
# of period volatility will be limited to determine if the value is
|
||||
# numerical. This tests for its existence and format.
|
||||
np.testing.assert_equal(
|
||||
@@ -191,7 +187,7 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
True)
|
||||
|
||||
def test_algorithm_sharpe(self):
|
||||
# The sharpe ratio is calculated by a qrisk function so testing
|
||||
# The sharpe ratio is calculated by a empyrical function so testing
|
||||
# of period sharpe ratios will be limited to determine if the value is
|
||||
# numerical. This tests for its existence and format.
|
||||
np.testing.assert_equal(
|
||||
@@ -212,7 +208,7 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
True)
|
||||
|
||||
def test_algorithm_downside_risk(self):
|
||||
# Downside risk is calculated by a qrisk function so testing
|
||||
# Downside risk is calculated by a empyrical function so testing
|
||||
# of period downside risk will be limited to determine if the value is
|
||||
# numerical. This tests for its existence and format.
|
||||
np.testing.assert_equal(
|
||||
@@ -233,7 +229,7 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
True)
|
||||
|
||||
def test_algorithm_sortino(self):
|
||||
# The sortino ratio is calculated by a qrisk function so testing
|
||||
# The sortino ratio is calculated by a empyrical function so testing
|
||||
# of period sortino ratios will be limited to determine if the value is
|
||||
# numerical. This tests for its existence and format.
|
||||
np.testing.assert_equal(
|
||||
@@ -254,9 +250,9 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
True)
|
||||
|
||||
def test_algorithm_information(self):
|
||||
# The information ratio is calculated by a qrisk function so testing
|
||||
# of period information ratio will be limited to determine if the value
|
||||
# is numerical. This tests for its existence and format.
|
||||
# The information ratio is calculated by a empyrical function
|
||||
# testing of period information ratio will be limited to determine
|
||||
# if the value is numerical. This tests for its existence and format.
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.information, float)
|
||||
for x in self.metrics.month_periods),
|
||||
@@ -275,7 +271,7 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
True)
|
||||
|
||||
def test_algorithm_beta(self):
|
||||
# Beta is calculated by a qrisk function so testing
|
||||
# Beta is calculated by a empyrical function so testing
|
||||
# of period beta will be limited to determine if the value is
|
||||
# numerical. This tests for its existence and format.
|
||||
np.testing.assert_equal(
|
||||
@@ -296,7 +292,7 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
True)
|
||||
|
||||
def test_algorithm_alpha(self):
|
||||
# Alpha is calculated by a qrisk function so testing
|
||||
# Alpha is calculated by a empyrical function so testing
|
||||
# of period alpha will be limited to determine if the value is
|
||||
# numerical. This tests for its existence and format.
|
||||
np.testing.assert_equal(
|
||||
@@ -316,49 +312,6 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
def test_algorithm_covariance(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_covariance for x in self.metrics.month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_covariance
|
||||
for x in self.metrics.three_month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_covariance
|
||||
for x in self.metrics.six_month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_covariance
|
||||
for x in self.metrics.year_periods],
|
||||
[0.0],
|
||||
DECIMAL_PLACES)
|
||||
|
||||
def test_benchmark_variance(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_variance
|
||||
for x in self.metrics.month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_variance
|
||||
for x in self.metrics.three_month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_variance
|
||||
for x in self.metrics.six_month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_variance
|
||||
for x in self.metrics.year_periods],
|
||||
[0.0],
|
||||
DECIMAL_PLACES)
|
||||
|
||||
def test_treasury_returns(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params,
|
||||
@@ -407,13 +360,33 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
[0.0500])
|
||||
|
||||
def test_benchmarkrange(self):
|
||||
self.check_year_range(
|
||||
pd.Timestamp('2008-01-01', tz=pytz.utc),
|
||||
2)
|
||||
start_session = self.trading_calendar.minute_to_session_label(
|
||||
pd.Timestamp("2008-01-01", tz='UTC')
|
||||
)
|
||||
|
||||
end_session = self.trading_calendar.minute_to_session_label(
|
||||
pd.Timestamp("2010-01-01", tz='UTC'), direction="previous"
|
||||
)
|
||||
|
||||
sim_params = SimulationParameters(
|
||||
start_session=start_session,
|
||||
end_session=end_session,
|
||||
trading_calendar=self.trading_calendar,
|
||||
)
|
||||
|
||||
returns = factory.create_returns_from_range(sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
|
||||
self.check_metrics(metrics, 24, start_session)
|
||||
|
||||
def test_partial_month(self):
|
||||
|
||||
start = pd.Timestamp('1991-01-01', tz=pytz.utc)
|
||||
start_session = self.trading_calendar.minute_to_session_label(
|
||||
pd.Timestamp("1991-01-01", tz='UTC')
|
||||
)
|
||||
|
||||
# 1992 and 1996 were leap years
|
||||
total_days = 365 * 5 + 2
|
||||
@@ -504,6 +477,108 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
end=col[-1]._end_session,
|
||||
actual=len(col))
|
||||
)
|
||||
self.assert_month(start_date.month, col[-1]._end_session.month)
|
||||
self.assert_last_day(col[-1]._end_session)
|
||||
|
||||
self.assert_month(start_date.month, col[-1].end_date.month)
|
||||
self.assert_last_day(col[-1].end_date)
|
||||
def test_algorithm_leverages(self):
|
||||
# Max leverage for an algorithm with 'None' as leverage is 0.
|
||||
np.testing.assert_equal(
|
||||
[x.max_leverage for x in self.metrics.month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
|
||||
np.testing.assert_equal(
|
||||
[x.max_leverage for x in self.metrics.three_month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
|
||||
np.testing.assert_equal(
|
||||
[x.max_leverage for x in self.metrics.six_month_periods],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
|
||||
np.testing.assert_equal(
|
||||
[x.max_leverage for x in self.metrics.year_periods],
|
||||
[0.0])
|
||||
|
||||
def test_returns_beyond_treasury(self):
|
||||
# The last treasury value is used when return dates go beyond
|
||||
# treasury curve data
|
||||
treasury_curves = self.env.treasury_curves
|
||||
treasury = treasury_curves[treasury_curves.index < self.start_session]
|
||||
|
||||
test_period = RiskMetricsPeriod(
|
||||
start_session=self.start_session,
|
||||
end_session=self.end_session,
|
||||
returns=self.algo_returns,
|
||||
benchmark_returns=self.benchmark_returns,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=treasury,
|
||||
algorithm_leverages=[.01, .02, .03]
|
||||
)
|
||||
assert test_period.treasury_curves.equals(treasury[-1:])
|
||||
# This return period has a list instead of None for algorithm_leverages
|
||||
# Confirm that max_leverage is set to the max of those values
|
||||
assert test_period.max_leverage == .03
|
||||
|
||||
def test_index_mismatch_exception(self):
|
||||
# An exception is raised when returns and benchmark returns
|
||||
# have indexes that do not match
|
||||
bench_params = SimulationParameters(
|
||||
start_session=pd.Timestamp("2006-02-01", tz='UTC'),
|
||||
end_session=pd.Timestamp("2006-02-28", tz='UTC'),
|
||||
trading_calendar=self.trading_calendar,
|
||||
)
|
||||
benchmark = factory.create_returns_from_list(
|
||||
[BENCHMARK_BASE]*19,
|
||||
bench_params
|
||||
)
|
||||
with np.testing.assert_raises(Exception):
|
||||
RiskMetricsPeriod(
|
||||
start_session=self.start_session,
|
||||
end_session=self.end_session,
|
||||
returns=self.algo_returns,
|
||||
benchmark_returns=benchmark,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
|
||||
def test_sharpe_value_when_null(self):
|
||||
# Sharpe is displayed as '0.0' instead of np.nan
|
||||
null_returns = factory.create_returns_from_list(
|
||||
[0.0]*251,
|
||||
self.sim_params
|
||||
)
|
||||
test_period = RiskMetricsPeriod(
|
||||
start_session=self.start_session,
|
||||
end_session=self.end_session,
|
||||
returns=null_returns,
|
||||
benchmark_returns=self.benchmark_returns,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
assert test_period.sharpe == 0.0
|
||||
|
||||
def test_representation(self):
|
||||
test_period = RiskMetricsPeriod(
|
||||
start_session=self.start_session,
|
||||
end_session=self.end_session,
|
||||
returns=self.algo_returns,
|
||||
benchmark_returns=self.benchmark_returns,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
metrics = [
|
||||
"algorithm_period_returns",
|
||||
"benchmark_period_returns",
|
||||
"excess_return",
|
||||
"num_trading_days",
|
||||
"benchmark_volatility",
|
||||
"algorithm_volatility",
|
||||
"sharpe",
|
||||
"sortino",
|
||||
"information",
|
||||
"beta",
|
||||
"alpha",
|
||||
"max_drawdown",
|
||||
"max_leverage",
|
||||
"algorithm_returns",
|
||||
"benchmark_returns",
|
||||
]
|
||||
representation = test_period.__repr__()
|
||||
|
||||
assert all([metric in representation for metric in metrics])
|
||||
|
||||
@@ -873,10 +873,10 @@ def before_trading_start(context, data):
|
||||
|
||||
res2 = algo2.run(self.data_portal)
|
||||
|
||||
# FIXME I think we are getting Nans due to fixed benchmark,
|
||||
# so dropping them for now.
|
||||
res1 = res1.fillna(method='ffill')
|
||||
res2 = res2.fillna(method='ffill')
|
||||
# There are some np.NaN values in the first row because there is not
|
||||
# enough data to calculate the metric, e.g. beta.
|
||||
res1 = res1.fillna(value=0)
|
||||
res2 = res2.fillna(value=0)
|
||||
|
||||
np.testing.assert_array_equal(res1, res2)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user