mirror of
https://github.com/wassname/catalyst.git
synced 2026-08-13 12:00:16 +08:00
ENH: Use qrisk to calculate risk metrics in cumulative and period
TST: Remove metric correctness testing from period and cumulative tests ENH: Removed answer key and related files ENH: Update qrisk version
This commit is contained in:
@@ -1,87 +0,0 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "AnswerKeyAnnotations"
|
||||
},
|
||||
"nbformat": 3,
|
||||
"nbformat_minor": 0,
|
||||
"worksheets": [
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"#\n",
|
||||
"# Copyright 2013 Quantopian, Inc.\n",
|
||||
"#\n",
|
||||
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"# you may not use this file except in compliance with the License.\n",
|
||||
"# You may obtain a copy of the License at\n",
|
||||
"#\n",
|
||||
"# http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"#\n",
|
||||
"# Unless required by applicable law or agreed to in writing, software\n",
|
||||
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"# See the License for the specific language governing permissions and\n",
|
||||
"# limitations under the License."
|
||||
],
|
||||
"language": "python",
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"%load_ext autoreload\n",
|
||||
"%autoreload 2"
|
||||
],
|
||||
"language": "python",
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"import datetime\n",
|
||||
"import pandas as pd\n",
|
||||
"from IPython.display import HTML\n",
|
||||
"\n",
|
||||
"import answer_key\n",
|
||||
"ANSWER_KEY = answer_key.ANSWER_KEY"
|
||||
],
|
||||
"language": "python",
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"print 'Period Returns Index'\n",
|
||||
"print ANSWER_KEY.RETURNS"
|
||||
],
|
||||
"language": "python",
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"HTML(answer_key.RETURNS_DATA.to_html())"
|
||||
],
|
||||
"language": "python",
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"ANSWER_KEY.ALGORITHM_CUMULATIVE_SHARPE"
|
||||
],
|
||||
"language": "python",
|
||||
"outputs": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": ""
|
||||
},
|
||||
"nbformat": 3,
|
||||
"nbformat_minor": 0,
|
||||
"worksheets": [
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": true,
|
||||
"input": [
|
||||
"#\n",
|
||||
"# Copyright 2014 Quantopian, Inc.\n",
|
||||
"#\n",
|
||||
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"# you may not use this file except in compliance with the License.\n",
|
||||
"# You may obtain a copy of the License at\n",
|
||||
"#\n",
|
||||
"# http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"#\n",
|
||||
"# Unless required by applicable law or agreed to in writing, software\n",
|
||||
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"# See the License for the specific language governing permissions and\n",
|
||||
"# limitations under the License.\n",
|
||||
"\n",
|
||||
"from annotation_utils import Markdown\n",
|
||||
"import answer_key"
|
||||
],
|
||||
"language": "python",
|
||||
"outputs": [],
|
||||
"prompt_number": 1
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"Markdown(\"\"\"\n",
|
||||
"Download link for latest answer key: [{latest_answer_key_url}]({latest_answer_key_url})\n",
|
||||
"\"\"\".format(latest_answer_key_url=answer_key.LATEST_ANSWER_KEY_URL))"
|
||||
],
|
||||
"language": "python",
|
||||
"outputs": [
|
||||
{
|
||||
"html": [
|
||||
"<p>Download link for latest answer key: <a href=\"https://s3.amazonaws.com/zipline-test-data/risk/79d117cd4849745bf72ee1fd7442ef89/risk-answer-key.xlsx\">https://s3.amazonaws.com/zipline-test-data/risk/79d117cd4849745bf72ee1fd7442ef89/risk-answer-key.xlsx</a></p>"
|
||||
],
|
||||
"output_type": "pyout",
|
||||
"prompt_number": 2,
|
||||
"text": [
|
||||
"'\\nDownload link for latest answer key: [https://s3.amazonaws.com/zipline-test-data/risk/79d117cd4849745bf72ee1fd7442ef89/risk-answer-key.xlsx](https://s3.amazonaws.com/zipline-test-data/risk/79d117cd4849745bf72ee1fd7442ef89/risk-answer-key.xlsx)\\n'"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,341 +0,0 @@
|
||||
#
|
||||
# Copyright 2014 Quantopian, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import datetime
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pytz
|
||||
import xlrd
|
||||
import requests
|
||||
|
||||
from six.moves import map
|
||||
|
||||
|
||||
def col_letter_to_index(col_letter):
|
||||
# Only supports single letter,
|
||||
# but answer key doesn't need multi-letter, yet.
|
||||
index = 0
|
||||
for i, char in enumerate(reversed(col_letter)):
|
||||
index += ((ord(char) - 65) + 1) * pow(26, i)
|
||||
return index
|
||||
|
||||
DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
ANSWER_KEY_CHECKSUMS_PATH = os.path.join(DIR, 'risk-answer-key-checksums')
|
||||
ANSWER_KEY_CHECKSUMS = open(ANSWER_KEY_CHECKSUMS_PATH, 'r').read().splitlines()
|
||||
|
||||
ANSWER_KEY_FILENAME = 'risk-answer-key.xlsx'
|
||||
|
||||
ANSWER_KEY_PATH = os.path.join(DIR, ANSWER_KEY_FILENAME)
|
||||
|
||||
ANSWER_KEY_BUCKET_NAME = 'zipline-test_data'
|
||||
|
||||
ANSWER_KEY_DL_TEMPLATE = """
|
||||
https://s3.amazonaws.com/zipline-test-data/risk/{md5}/risk-answer-key.xlsx
|
||||
""".strip()
|
||||
|
||||
LATEST_ANSWER_KEY_URL = ANSWER_KEY_DL_TEMPLATE.format(
|
||||
md5=ANSWER_KEY_CHECKSUMS[-1])
|
||||
|
||||
|
||||
def answer_key_signature():
|
||||
with open(ANSWER_KEY_PATH, 'rb') as f:
|
||||
md5 = hashlib.md5()
|
||||
buf = f.read(1024)
|
||||
md5.update(buf)
|
||||
while buf != b"":
|
||||
buf = f.read(1024)
|
||||
md5.update(buf)
|
||||
return md5.hexdigest()
|
||||
|
||||
|
||||
def ensure_latest_answer_key():
|
||||
"""
|
||||
Get the latest answer key from a publically available location.
|
||||
|
||||
Logic for determining what and when to download is as such:
|
||||
|
||||
- If there is no local spreadsheet file, then get the lastest answer key,
|
||||
as defined by the last row in the checksum file.
|
||||
- If there is a local spreadsheet file:
|
||||
-- If the spreadsheet's checksum is in the checksum file:
|
||||
--- If the spreadsheet's checksum does not match the latest, then grab the
|
||||
the latest checksum and replace the local checksum file.
|
||||
--- If the spreadsheet's checksum matches the latest, then skip download,
|
||||
and use the local spreadsheet as a cached copy.
|
||||
-- If the spreadsheet's checksum is not in the checksum file, then leave
|
||||
the local file alone, assuming that the local xls's md5 is not in the list
|
||||
due to local modifications during development.
|
||||
|
||||
It is possible that md5's could collide, if that is ever case, we should
|
||||
then find an alternative naming scheme.
|
||||
|
||||
The spreadsheet answer sheet is not kept in SCM, as every edit would
|
||||
increase the repo size by the file size, since it is treated as a binary.
|
||||
"""
|
||||
|
||||
answer_key_dl_checksum = None
|
||||
|
||||
local_answer_key_exists = os.path.exists(ANSWER_KEY_PATH)
|
||||
if local_answer_key_exists:
|
||||
local_hash = answer_key_signature()
|
||||
|
||||
if local_hash in ANSWER_KEY_CHECKSUMS:
|
||||
# Assume previously downloaded version.
|
||||
# Check for latest.
|
||||
if local_hash != ANSWER_KEY_CHECKSUMS[-1]:
|
||||
# More recent checksum, download
|
||||
answer_key_dl_checksum = ANSWER_KEY_CHECKSUMS[-1]
|
||||
else:
|
||||
# Assume local copy that is being developed on
|
||||
answer_key_dl_checksum = None
|
||||
else:
|
||||
answer_key_dl_checksum = ANSWER_KEY_CHECKSUMS[-1]
|
||||
|
||||
if answer_key_dl_checksum:
|
||||
res = requests.get(
|
||||
ANSWER_KEY_DL_TEMPLATE.format(md5=answer_key_dl_checksum))
|
||||
with open(ANSWER_KEY_PATH, 'wb') as f:
|
||||
f.write(res.content)
|
||||
|
||||
# Get latest answer key on load.
|
||||
ensure_latest_answer_key()
|
||||
|
||||
|
||||
class DataIndex(object):
|
||||
"""
|
||||
Coordinates for the spreadsheet, using the values as seen in the notebook.
|
||||
The python-excel libraries use 0 index, while the spreadsheet in a GUI
|
||||
uses a 1 index.
|
||||
"""
|
||||
def __init__(self, sheet_name, col, row_start, row_end,
|
||||
value_type='float'):
|
||||
self.sheet_name = sheet_name
|
||||
self.col = col
|
||||
self.row_start = row_start
|
||||
self.row_end = row_end
|
||||
self.value_type = value_type
|
||||
|
||||
@property
|
||||
def col_index(self):
|
||||
return col_letter_to_index(self.col) - 1
|
||||
|
||||
@property
|
||||
def row_start_index(self):
|
||||
return self.row_start - 1
|
||||
|
||||
@property
|
||||
def row_end_index(self):
|
||||
return self.row_end - 1
|
||||
|
||||
def __str__(self):
|
||||
return "'{sheet_name}'!{col}{row_start}:{col}{row_end}".format(
|
||||
sheet_name=self.sheet_name,
|
||||
col=self.col,
|
||||
row_start=self.row_start,
|
||||
row_end=self.row_end
|
||||
)
|
||||
|
||||
|
||||
class AnswerKey(object):
|
||||
|
||||
INDEXES = {
|
||||
'RETURNS': DataIndex('Sim Period', 'D', 4, 255),
|
||||
|
||||
'BENCHMARK': {
|
||||
'Dates': DataIndex('s_p', 'A', 4, 254, value_type='date'),
|
||||
'Returns': DataIndex('s_p', 'H', 4, 254)
|
||||
},
|
||||
|
||||
# Below matches the inconsistent capitalization in spreadsheet
|
||||
'BENCHMARK_PERIOD_RETURNS': {
|
||||
'Monthly': DataIndex('s_p', 'R', 8, 19),
|
||||
'3-Month': DataIndex('s_p', 'S', 10, 19),
|
||||
'6-month': DataIndex('s_p', 'T', 13, 19),
|
||||
'year': DataIndex('s_p', 'U', 19, 19),
|
||||
},
|
||||
|
||||
'BENCHMARK_PERIOD_VOLATILITY': {
|
||||
'Monthly': DataIndex('s_p', 'V', 8, 19),
|
||||
'3-Month': DataIndex('s_p', 'W', 10, 19),
|
||||
'6-month': DataIndex('s_p', 'X', 13, 19),
|
||||
'year': DataIndex('s_p', 'Y', 19, 19),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_RETURNS': {
|
||||
'Monthly': DataIndex('Sim Period', 'Z', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'AA', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'AB', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'AC', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_VOLATILITY': {
|
||||
'Monthly': DataIndex('Sim Period', 'AH', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'AI', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'AJ', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'AK', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_SHARPE': {
|
||||
'Monthly': DataIndex('Sim Period', 'AL', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'AM', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'AN', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'AO', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_BETA': {
|
||||
'Monthly': DataIndex('Sim Period', 'AP', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'AQ', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'AR', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'AS', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_ALPHA': {
|
||||
'Monthly': DataIndex('Sim Period', 'AT', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'AU', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'AV', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'AW', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_BENCHMARK_VARIANCE': {
|
||||
'Monthly': DataIndex('Sim Period', 'BJ', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'BK', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'BL', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'BM', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_COVARIANCE': {
|
||||
'Monthly': DataIndex('Sim Period', 'BF', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'BG', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'BH', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'BI', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_DOWNSIDE_RISK': {
|
||||
'Monthly': DataIndex('Sim Period', 'BN', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'BO', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'BP', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'BQ', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_PERIOD_SORTINO': {
|
||||
'Monthly': DataIndex('Sim Period', 'BR', 23, 34),
|
||||
'3-Month': DataIndex('Sim Period', 'BS', 25, 34),
|
||||
'6-month': DataIndex('Sim Period', 'BT', 28, 34),
|
||||
'year': DataIndex('Sim Period', 'BU', 34, 34),
|
||||
},
|
||||
|
||||
'ALGORITHM_RETURN_VALUES': DataIndex(
|
||||
'Sim Cumulative', 'D', 4, 254),
|
||||
|
||||
'ALGORITHM_CUMULATIVE_VOLATILITY': DataIndex(
|
||||
'Sim Cumulative', 'P', 4, 254),
|
||||
|
||||
'ALGORITHM_CUMULATIVE_SHARPE': DataIndex(
|
||||
'Sim Cumulative', 'R', 4, 254),
|
||||
|
||||
'CUMULATIVE_DOWNSIDE_RISK': DataIndex(
|
||||
'Sim Cumulative', 'U', 4, 254),
|
||||
|
||||
'CUMULATIVE_SORTINO': DataIndex(
|
||||
'Sim Cumulative', 'V', 4, 254),
|
||||
|
||||
'CUMULATIVE_INFORMATION': DataIndex(
|
||||
'Sim Cumulative', 'AA', 4, 254),
|
||||
|
||||
'CUMULATIVE_BETA': DataIndex(
|
||||
'Sim Cumulative', 'AD', 4, 254),
|
||||
|
||||
'CUMULATIVE_ALPHA': DataIndex(
|
||||
'Sim Cumulative', 'AE', 4, 254),
|
||||
|
||||
'CUMULATIVE_MAX_DRAWDOWN': DataIndex(
|
||||
'Sim Cumulative', 'AH', 4, 254),
|
||||
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.workbook = xlrd.open_workbook(ANSWER_KEY_PATH)
|
||||
|
||||
self.sheets = {}
|
||||
self.sheets['Sim Period'] = self.workbook.sheet_by_name('Sim Period')
|
||||
self.sheets['Sim Cumulative'] = self.workbook.sheet_by_name(
|
||||
'Sim Cumulative')
|
||||
self.sheets['s_p'] = self.workbook.sheet_by_name('s_p')
|
||||
|
||||
for name, index in self.INDEXES.items():
|
||||
if isinstance(index, dict):
|
||||
subvalues = {}
|
||||
for subkey, subindex in index.items():
|
||||
subvalues[subkey] = self.get_values(subindex)
|
||||
setattr(self, name, subvalues)
|
||||
else:
|
||||
setattr(self, name, self.get_values(index))
|
||||
|
||||
def parse_date_value(self, value):
|
||||
return xlrd.xldate_as_tuple(value, 0)
|
||||
|
||||
def parse_float_value(self, value):
|
||||
return value if value != '' else np.nan
|
||||
|
||||
def get_raw_values(self, data_index):
|
||||
return self.sheets[data_index.sheet_name].col_values(
|
||||
data_index.col_index,
|
||||
data_index.row_start_index,
|
||||
data_index.row_end_index + 1)
|
||||
|
||||
@property
|
||||
def value_type_to_value_func(self):
|
||||
return {
|
||||
'float': self.parse_float_value,
|
||||
'date': self.parse_date_value,
|
||||
}
|
||||
|
||||
def get_values(self, data_index):
|
||||
value_parser = self.value_type_to_value_func[data_index.value_type]
|
||||
return [value for value in
|
||||
map(value_parser, self.get_raw_values(data_index))]
|
||||
|
||||
|
||||
ANSWER_KEY = AnswerKey()
|
||||
|
||||
BENCHMARK_DATES = ANSWER_KEY.BENCHMARK['Dates']
|
||||
BENCHMARK_RETURNS = ANSWER_KEY.BENCHMARK['Returns']
|
||||
DATES = [datetime.datetime(*x, tzinfo=pytz.UTC) for x in BENCHMARK_DATES]
|
||||
BENCHMARK = pd.Series(dict(zip(DATES, BENCHMARK_RETURNS)))
|
||||
ALGORITHM_RETURNS = pd.Series(
|
||||
dict(zip(DATES, ANSWER_KEY.ALGORITHM_RETURN_VALUES)))
|
||||
RETURNS_DATA = pd.DataFrame({'Benchmark Returns': BENCHMARK,
|
||||
'Algorithm Returns': ALGORITHM_RETURNS})
|
||||
RISK_CUMULATIVE = pd.DataFrame({
|
||||
'volatility': pd.Series(dict(zip(
|
||||
DATES, ANSWER_KEY.ALGORITHM_CUMULATIVE_VOLATILITY))),
|
||||
'sharpe': pd.Series(dict(zip(
|
||||
DATES, ANSWER_KEY.ALGORITHM_CUMULATIVE_SHARPE))),
|
||||
'downside_risk': pd.Series(dict(zip(
|
||||
DATES, ANSWER_KEY.CUMULATIVE_DOWNSIDE_RISK))),
|
||||
'sortino': pd.Series(dict(zip(
|
||||
DATES, ANSWER_KEY.CUMULATIVE_SORTINO))),
|
||||
'information': pd.Series(dict(zip(
|
||||
DATES, ANSWER_KEY.CUMULATIVE_INFORMATION))),
|
||||
'alpha': pd.Series(dict(zip(
|
||||
DATES, ANSWER_KEY.CUMULATIVE_ALPHA))),
|
||||
'beta': pd.Series(dict(zip(
|
||||
DATES, ANSWER_KEY.CUMULATIVE_BETA))),
|
||||
'max_drawdown': pd.Series(dict(zip(
|
||||
DATES, ANSWER_KEY.CUMULATIVE_MAX_DRAWDOWN))),
|
||||
})
|
||||
@@ -1,16 +0,0 @@
|
||||
3ac0773c4be4e9e5bacd9c6fa0e03e15
|
||||
3a5fae958c8bac684f1773fa8dff7810
|
||||
19d580890e211a122e9e746f07c80cbc
|
||||
70cfe3677a0ff401c801b8628e125d8f
|
||||
99b3855ef1b8963163c3cb8f7e05cb70
|
||||
97dfb557c3501179504926e4079e6446
|
||||
cc507b6fca18aabadac69657181edd4e
|
||||
5b48e6a70181d73ecb7f07df5a3092e2
|
||||
3343940379161143630503413627a53a
|
||||
820235c4157a3c55474836438019ef2e
|
||||
75c1b1441efbc2431215835a5079ccc6
|
||||
37e3ea4a1788f1aa6f3ee0986bc625ae
|
||||
651e611e723e2a58b1ded91d0cd39b66
|
||||
d62fce39ec78f032165d8f356bba5c2c
|
||||
97632f6f64dfc4a2de09882419a79421
|
||||
79d117cd4849745bf72ee1fd7442ef89
|
||||
@@ -17,107 +17,136 @@ 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
|
||||
|
||||
BENCHMARK_BASE = 0.005
|
||||
BENCHMARK = [BENCHMARK_BASE] * 251
|
||||
DECIMAL_PLACES = 8
|
||||
|
||||
|
||||
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,
|
||||
trading_calendar=self.trading_calendar,
|
||||
)
|
||||
|
||||
self.algo_returns_06 = factory.create_returns_from_list(
|
||||
answer_key.ALGORITHM_RETURNS.values,
|
||||
self.algo_returns = factory.create_returns_from_list(
|
||||
RETURNS,
|
||||
self.sim_params
|
||||
)
|
||||
|
||||
self.cumulative_metrics_06 = risk.RiskMetricsCumulative(
|
||||
self.cumulative_metrics = risk.RiskMetricsCumulative(
|
||||
self.sim_params,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
trading_calendar=self.trading_calendar,
|
||||
)
|
||||
for dt, returns in self.algo_returns.iteritems():
|
||||
self.cumulative_metrics.update(
|
||||
dt,
|
||||
returns,
|
||||
BENCHMARK_BASE,
|
||||
0.0
|
||||
)
|
||||
|
||||
for dt, returns in answer_key.RETURNS_DATA.iterrows():
|
||||
self.cumulative_metrics_06.update(dt,
|
||||
returns['Algorithm Returns'],
|
||||
returns['Benchmark Returns'],
|
||||
0.0)
|
||||
def test_algorithm_volatility(self):
|
||||
np.testing.assert_equal(
|
||||
len(self.algo_returns),
|
||||
len(self.cumulative_metrics.algorithm_volatility)
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.algorithm_volatility),
|
||||
True
|
||||
)
|
||||
|
||||
def test_algorithm_volatility_06(self):
|
||||
algo_vol_answers = answer_key.RISK_CUMULATIVE.volatility
|
||||
for dt, value in algo_vol_answers.iteritems():
|
||||
dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt)
|
||||
np.testing.assert_almost_equal(
|
||||
self.cumulative_metrics_06.algorithm_volatility[dt_loc],
|
||||
value,
|
||||
err_msg="Mismatch at %s" % (dt,))
|
||||
def test_sharpe(self):
|
||||
np.testing.assert_equal(
|
||||
len(self.algo_returns),
|
||||
len(self.cumulative_metrics.sharpe)
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.sharpe),
|
||||
True)
|
||||
|
||||
def test_sharpe_06(self):
|
||||
for dt, value in answer_key.RISK_CUMULATIVE.sharpe.iteritems():
|
||||
dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt)
|
||||
np.testing.assert_almost_equal(
|
||||
self.cumulative_metrics_06.sharpe[dt_loc],
|
||||
value,
|
||||
err_msg="Mismatch at %s" % (dt,))
|
||||
def test_downside_risk(self):
|
||||
np.testing.assert_equal(
|
||||
len(self.algo_returns),
|
||||
len(self.cumulative_metrics.downside_risk)
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.downside_risk),
|
||||
True)
|
||||
|
||||
def test_downside_risk_06(self):
|
||||
for dt, value in answer_key.RISK_CUMULATIVE.downside_risk.iteritems():
|
||||
dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt)
|
||||
np.testing.assert_almost_equal(
|
||||
value,
|
||||
self.cumulative_metrics_06.downside_risk[dt_loc],
|
||||
err_msg="Mismatch at %s" % (dt,))
|
||||
def test_sortino(self):
|
||||
np.testing.assert_equal(
|
||||
len(self.algo_returns),
|
||||
len(self.cumulative_metrics.sortino)
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.sortino),
|
||||
True)
|
||||
|
||||
def test_sortino_06(self):
|
||||
for dt, value in answer_key.RISK_CUMULATIVE.sortino.iteritems():
|
||||
dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt)
|
||||
np.testing.assert_almost_equal(
|
||||
self.cumulative_metrics_06.sortino[dt_loc],
|
||||
value,
|
||||
decimal=4,
|
||||
err_msg="Mismatch at %s" % (dt,))
|
||||
def test_information(self):
|
||||
np.testing.assert_equal(
|
||||
len(self.algo_returns),
|
||||
len(self.cumulative_metrics.information)
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.information),
|
||||
True)
|
||||
|
||||
def test_information_06(self):
|
||||
for dt, value in answer_key.RISK_CUMULATIVE.information.iteritems():
|
||||
dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt)
|
||||
np.testing.assert_almost_equal(
|
||||
value,
|
||||
self.cumulative_metrics_06.information[dt_loc],
|
||||
err_msg="Mismatch at %s" % (dt,))
|
||||
def test_alpha(self):
|
||||
np.testing.assert_equal(
|
||||
len(self.algo_returns),
|
||||
len(self.cumulative_metrics.alpha)
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.alpha),
|
||||
True)
|
||||
|
||||
def test_alpha_06(self):
|
||||
for dt, value in answer_key.RISK_CUMULATIVE.alpha.iteritems():
|
||||
dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt)
|
||||
np.testing.assert_almost_equal(
|
||||
self.cumulative_metrics_06.alpha[dt_loc],
|
||||
value,
|
||||
err_msg="Mismatch at %s" % (dt,))
|
||||
def test_beta(self):
|
||||
np.testing.assert_equal(
|
||||
len(self.algo_returns),
|
||||
len(self.cumulative_metrics.beta)
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.beta),
|
||||
True)
|
||||
|
||||
def test_beta_06(self):
|
||||
for dt, value in answer_key.RISK_CUMULATIVE.beta.iteritems():
|
||||
dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt)
|
||||
np.testing.assert_almost_equal(
|
||||
value,
|
||||
self.cumulative_metrics_06.beta[dt_loc],
|
||||
err_msg="Mismatch at %s" % (dt,))
|
||||
|
||||
def test_max_drawdown_06(self):
|
||||
for dt, value in answer_key.RISK_CUMULATIVE.max_drawdown.iteritems():
|
||||
dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt)
|
||||
np.testing.assert_almost_equal(
|
||||
self.cumulative_metrics_06.max_drawdowns[dt_loc],
|
||||
value,
|
||||
err_msg="Mismatch at %s" % (dt,))
|
||||
def test_max_drawdown(self):
|
||||
np.testing.assert_equal(
|
||||
len(self.algo_returns),
|
||||
len(self.cumulative_metrics.max_drawdowns)
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x, float)
|
||||
for x in self.cumulative_metrics.max_drawdowns),
|
||||
True)
|
||||
|
||||
+270
-403
@@ -18,21 +18,20 @@ import calendar
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import pytz
|
||||
|
||||
from itertools import chain
|
||||
from six import itervalues
|
||||
import pandas as pd
|
||||
|
||||
import zipline.finance.risk as risk
|
||||
from zipline.utils import factory
|
||||
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.testing.fixtures import WithTradingEnvironment, ZiplineTestCase
|
||||
from . import answer_key
|
||||
from . answer_key import AnswerKey
|
||||
|
||||
ANSWER_KEY = AnswerKey()
|
||||
RETURNS_BASE = 0.01
|
||||
RETURNS = [RETURNS_BASE] * 251
|
||||
|
||||
RETURNS = ANSWER_KEY.RETURNS
|
||||
BENCHMARK_BASE = 0.005
|
||||
BENCHMARK = [BENCHMARK_BASE] * 251
|
||||
DECIMAL_PLACES = 8
|
||||
|
||||
|
||||
class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
@@ -52,409 +51,315 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
end_session=end_session,
|
||||
trading_calendar=self.trading_calendar,
|
||||
)
|
||||
|
||||
self.algo_returns_06 = factory.create_returns_from_list(
|
||||
self.algo_returns = factory.create_returns_from_list(
|
||||
RETURNS,
|
||||
self.sim_params
|
||||
)
|
||||
|
||||
self.benchmark_returns_06 = \
|
||||
answer_key.RETURNS_DATA['Benchmark Returns']
|
||||
|
||||
self.metrics_06 = risk.RiskReport(
|
||||
self.algo_returns_06,
|
||||
self.sim_params,
|
||||
benchmark_returns=self.benchmark_returns_06,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
self.benchmark_returns = factory.create_returns_from_list(
|
||||
BENCHMARK,
|
||||
self.sim_params
|
||||
)
|
||||
|
||||
self.sim_params08 = SimulationParameters(
|
||||
start_session=pd.Timestamp("2008-01-01", tz='UTC'),
|
||||
end_session=pd.Timestamp("2008-12-31", tz='UTC'),
|
||||
trading_calendar=self.trading_calendar,
|
||||
self.metrics = risk.RiskReport(
|
||||
self.algo_returns,
|
||||
self.sim_params,
|
||||
benchmark_returns=self.benchmark_returns,
|
||||
trading_schedule=self.trading_schedule,
|
||||
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] <=
|
||||
datetime.datetime(
|
||||
year=2006, month=12, day=31, tzinfo=pytz.utc))
|
||||
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)
|
||||
|
||||
def test_drawdown(self):
|
||||
returns = factory.create_returns_from_list(
|
||||
[1.0, -0.5, 0.8, .17, 1.0, -0.1, -0.45], self.sim_params)
|
||||
# 200, 100, 180, 210.6, 421.2, 379.8, 208.494
|
||||
metrics = risk.RiskMetricsPeriod(
|
||||
returns.index[0],
|
||||
returns.index[-1],
|
||||
returns,
|
||||
trading_calendar=self.trading_calendar,
|
||||
benchmark_returns=self.env.benchmark_returns,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
self.assertEqual(metrics.max_drawdown, 0.505)
|
||||
np.testing.assert_equal(
|
||||
all(x.max_drawdown == 0 for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(x.max_drawdown == 0 for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(x.max_drawdown == 0 for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(x.max_drawdown == 0 for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
def test_benchmark_returns_06(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_period_returns
|
||||
for x in self.metrics.month_periods],
|
||||
[(1 + BENCHMARK_BASE) ** len(x.benchmark_returns) - 1
|
||||
for x in self.metrics.month_periods],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_period_returns
|
||||
for x in self.metrics.three_month_periods],
|
||||
[(1 + BENCHMARK_BASE) ** len(x.benchmark_returns) - 1
|
||||
for x in self.metrics.three_month_periods],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_period_returns
|
||||
for x in self.metrics.six_month_periods],
|
||||
[(1 + BENCHMARK_BASE) ** len(x.benchmark_returns) - 1
|
||||
for x in self.metrics.six_month_periods],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_period_returns
|
||||
for x in self.metrics.year_periods],
|
||||
[(1 + BENCHMARK_BASE) ** len(x.benchmark_returns) - 1
|
||||
for x in self.metrics.year_periods],
|
||||
DECIMAL_PLACES)
|
||||
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_period_returns
|
||||
for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.BENCHMARK_PERIOD_RETURNS['Monthly'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_period_returns
|
||||
for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.BENCHMARK_PERIOD_RETURNS['3-Month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_period_returns
|
||||
for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.BENCHMARK_PERIOD_RETURNS['6-month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_period_returns
|
||||
for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.BENCHMARK_PERIOD_RETURNS['year'])
|
||||
|
||||
def test_trading_days_06(self):
|
||||
returns = factory.create_returns_from_range(self.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.assertEqual([x.num_trading_days for x in metrics.year_periods],
|
||||
def test_trading_days(self):
|
||||
self.assertEqual([x.num_trading_days
|
||||
for x in self.metrics.year_periods],
|
||||
[251])
|
||||
self.assertEqual([x.num_trading_days for x in metrics.month_periods],
|
||||
self.assertEqual([x.num_trading_days
|
||||
for x in self.metrics.month_periods],
|
||||
[20, 19, 23, 19, 22, 22, 20, 23, 20, 22, 21, 20])
|
||||
|
||||
def test_benchmark_volatility_06(self):
|
||||
def test_benchmark_volatility(self):
|
||||
# Volatility is calculated by a qrisk 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(
|
||||
all(isinstance(x.benchmark_volatility, float)
|
||||
for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.benchmark_volatility, float)
|
||||
for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.benchmark_volatility, float)
|
||||
for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.benchmark_volatility, float)
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_volatility
|
||||
for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.BENCHMARK_PERIOD_VOLATILITY['Monthly'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_volatility
|
||||
for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.BENCHMARK_PERIOD_VOLATILITY['3-Month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_volatility
|
||||
for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.BENCHMARK_PERIOD_VOLATILITY['6-month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_volatility
|
||||
for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.BENCHMARK_PERIOD_VOLATILITY['year'])
|
||||
|
||||
def test_algorithm_returns_06(self):
|
||||
def test_algorithm_returns(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_period_returns
|
||||
for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_RETURNS['Monthly'])
|
||||
for x in self.metrics.month_periods],
|
||||
[(1 + RETURNS_BASE) ** len(x.algorithm_returns) - 1
|
||||
for x in self.metrics.month_periods],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_period_returns
|
||||
for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_RETURNS['3-Month'])
|
||||
for x in self.metrics.three_month_periods],
|
||||
[(1 + RETURNS_BASE) ** len(x.algorithm_returns) - 1
|
||||
for x in self.metrics.three_month_periods],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_period_returns
|
||||
for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_RETURNS['6-month'])
|
||||
for x in self.metrics.six_month_periods],
|
||||
[(1 + RETURNS_BASE) ** len(x.algorithm_returns) - 1
|
||||
for x in self.metrics.six_month_periods],
|
||||
DECIMAL_PLACES)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_period_returns
|
||||
for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_RETURNS['year'])
|
||||
for x in self.metrics.year_periods],
|
||||
[(1 + RETURNS_BASE) ** len(x.algorithm_returns) - 1
|
||||
for x in self.metrics.year_periods],
|
||||
DECIMAL_PLACES)
|
||||
|
||||
def test_algorithm_volatility_06(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_volatility
|
||||
for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_VOLATILITY['Monthly'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_volatility
|
||||
for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_VOLATILITY['3-Month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_volatility
|
||||
for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_VOLATILITY['6-month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_volatility
|
||||
for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_VOLATILITY['year'])
|
||||
def test_algorithm_volatility(self):
|
||||
# Volatility is calculated by a qrisk 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(
|
||||
all(isinstance(x.algorithm_volatility, float)
|
||||
for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.algorithm_volatility, float)
|
||||
for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.algorithm_volatility, float)
|
||||
for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.algorithm_volatility, float)
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
def test_algorithm_sharpe_06(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.sharpe for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_SHARPE['Monthly'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.sharpe for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_SHARPE['3-Month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.sharpe for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_SHARPE['6-month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.sharpe for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_SHARPE['year'])
|
||||
def test_algorithm_sharpe(self):
|
||||
# The sharpe ratio is calculated by a qrisk 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(
|
||||
all(isinstance(x.sharpe, float)
|
||||
for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.sharpe, float)
|
||||
for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.sharpe, float)
|
||||
for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.sharpe, float)
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
def test_algorithm_downside_risk_06(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.downside_risk for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_DOWNSIDE_RISK['Monthly'],
|
||||
decimal=4)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.downside_risk for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_DOWNSIDE_RISK['3-Month'],
|
||||
decimal=4)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.downside_risk for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_DOWNSIDE_RISK['6-month'],
|
||||
decimal=4)
|
||||
np.testing.assert_almost_equal(
|
||||
[x.downside_risk for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_DOWNSIDE_RISK['year'],
|
||||
decimal=4)
|
||||
def test_algorithm_downside_risk(self):
|
||||
# Downside risk is calculated by a qrisk 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(
|
||||
all(isinstance(x.downside_risk, float)
|
||||
for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.downside_risk, float)
|
||||
for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.downside_risk, float)
|
||||
for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.downside_risk, float)
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
def test_algorithm_sortino_06(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.sortino for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_SORTINO['Monthly'],
|
||||
decimal=3)
|
||||
def test_algorithm_sortino(self):
|
||||
# The sortino ratio is calculated by a qrisk 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(
|
||||
all(isinstance(x.sortino, float)
|
||||
for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.sortino, float)
|
||||
for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.sortino, float)
|
||||
for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.sortino, float)
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
np.testing.assert_almost_equal(
|
||||
[x.sortino for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_SORTINO['3-Month'],
|
||||
decimal=3)
|
||||
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.
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.information, float)
|
||||
for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.information, float)
|
||||
for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.information, float)
|
||||
for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.information, float)
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
np.testing.assert_almost_equal(
|
||||
[x.sortino for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_SORTINO['6-month'],
|
||||
decimal=3)
|
||||
def test_algorithm_beta(self):
|
||||
# Beta is calculated by a qrisk 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(
|
||||
all(isinstance(x.beta, float)
|
||||
for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.beta, float)
|
||||
for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.beta, float)
|
||||
for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.beta, float)
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
np.testing.assert_almost_equal(
|
||||
[x.sortino for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_SORTINO['year'],
|
||||
decimal=3)
|
||||
def test_algorithm_alpha(self):
|
||||
# Alpha is calculated by a qrisk 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(
|
||||
all(isinstance(x.alpha, float)
|
||||
for x in self.metrics.month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.alpha, float)
|
||||
for x in self.metrics.three_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.alpha, float)
|
||||
for x in self.metrics.six_month_periods),
|
||||
True)
|
||||
np.testing.assert_equal(
|
||||
all(isinstance(x.alpha, float)
|
||||
for x in self.metrics.year_periods),
|
||||
True)
|
||||
|
||||
def test_algorithm_information_06(self):
|
||||
self.assertEqual([round(x.information, 3)
|
||||
for x in self.metrics_06.month_periods],
|
||||
[0.131,
|
||||
-0.11,
|
||||
-0.067,
|
||||
0.136,
|
||||
0.301,
|
||||
-0.387,
|
||||
0.107,
|
||||
-0.032,
|
||||
-0.058,
|
||||
0.069,
|
||||
0.095,
|
||||
-0.123])
|
||||
self.assertEqual([round(x.information, 3)
|
||||
for x in self.metrics_06.three_month_periods],
|
||||
[-0.013,
|
||||
-0.009,
|
||||
0.111,
|
||||
-0.014,
|
||||
-0.017,
|
||||
-0.108,
|
||||
0.011,
|
||||
-0.004,
|
||||
0.032,
|
||||
0.011])
|
||||
self.assertEqual([round(x.information, 3)
|
||||
for x in self.metrics_06.six_month_periods],
|
||||
[-0.013,
|
||||
-0.014,
|
||||
-0.003,
|
||||
-0.002,
|
||||
-0.011,
|
||||
-0.041,
|
||||
0.011])
|
||||
self.assertEqual([round(x.information, 3)
|
||||
for x in self.metrics_06.year_periods],
|
||||
[-0.001])
|
||||
|
||||
def test_algorithm_beta_06(self):
|
||||
def test_algorithm_covariance(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.beta for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BETA['Monthly'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.beta for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BETA['3-Month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.beta for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BETA['6-month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.beta for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BETA['year'])
|
||||
|
||||
def test_algorithm_alpha_06(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.alpha for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_ALPHA['Monthly'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.alpha for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_ALPHA['3-Month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.alpha for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_ALPHA['6-month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.alpha for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_ALPHA['year'])
|
||||
|
||||
# FIXME: Covariance is not matching excel precisely enough to run the test.
|
||||
# Month 4 seems to be the problem. Variance is disabled
|
||||
# just to avoid distraction - it is much closer than covariance
|
||||
# and can probably pass with 6 significant digits instead of 7.
|
||||
# re-enable variance, alpha, and beta tests once this is resolved
|
||||
def test_algorithm_covariance_06(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_covariance for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_COVARIANCE['Monthly'])
|
||||
[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_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_COVARIANCE['3-Month'])
|
||||
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_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_COVARIANCE['6-month'])
|
||||
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_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_COVARIANCE['year'])
|
||||
for x in self.metrics.year_periods],
|
||||
[0.0],
|
||||
DECIMAL_PLACES)
|
||||
|
||||
def test_benchmark_variance_06(self):
|
||||
def test_benchmark_variance(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_variance
|
||||
for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BENCHMARK_VARIANCE['Monthly'])
|
||||
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_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BENCHMARK_VARIANCE['3-Month'])
|
||||
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_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BENCHMARK_VARIANCE['6-month'])
|
||||
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_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BENCHMARK_VARIANCE['year'])
|
||||
for x in self.metrics.year_periods],
|
||||
[0.0],
|
||||
DECIMAL_PLACES)
|
||||
|
||||
def test_benchmark_returns_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
|
||||
self.assertEqual([round(x.benchmark_period_returns, 3)
|
||||
for x in metrics.month_periods],
|
||||
[-0.061,
|
||||
-0.035,
|
||||
-0.006,
|
||||
0.048,
|
||||
0.011,
|
||||
-0.086,
|
||||
-0.01,
|
||||
0.012,
|
||||
-0.091,
|
||||
-0.169,
|
||||
-0.075,
|
||||
0.008])
|
||||
|
||||
self.assertEqual([round(x.benchmark_period_returns, 3)
|
||||
for x in metrics.three_month_periods],
|
||||
[-0.099,
|
||||
0.005,
|
||||
0.052,
|
||||
-0.032,
|
||||
-0.085,
|
||||
-0.084,
|
||||
-0.089,
|
||||
-0.236,
|
||||
-0.301,
|
||||
-0.226])
|
||||
|
||||
self.assertEqual([round(x.benchmark_period_returns, 3)
|
||||
for x in metrics.six_month_periods],
|
||||
[-0.128,
|
||||
-0.081,
|
||||
-0.036,
|
||||
-0.118,
|
||||
-0.301,
|
||||
-0.36,
|
||||
-0.294])
|
||||
|
||||
self.assertEqual([round(x.benchmark_period_returns, 3)
|
||||
for x in metrics.year_periods],
|
||||
[-0.385])
|
||||
|
||||
def test_trading_days_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
self.assertEqual([x.num_trading_days for x in metrics.year_periods],
|
||||
[253])
|
||||
|
||||
self.assertEqual([x.num_trading_days for x in metrics.month_periods],
|
||||
[21, 20, 20, 22, 21, 21, 22, 21, 21, 23, 19, 22])
|
||||
|
||||
def test_benchmark_volatility_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
|
||||
self.assertEqual([round(x.benchmark_volatility, 3)
|
||||
for x in metrics.month_periods],
|
||||
[0.07,
|
||||
0.058,
|
||||
0.082,
|
||||
0.054,
|
||||
0.041,
|
||||
0.057,
|
||||
0.068,
|
||||
0.06,
|
||||
0.157,
|
||||
0.244,
|
||||
0.195,
|
||||
0.145])
|
||||
|
||||
self.assertEqual([round(x.benchmark_volatility, 3)
|
||||
for x in metrics.three_month_periods],
|
||||
[0.12,
|
||||
0.113,
|
||||
0.105,
|
||||
0.09,
|
||||
0.098,
|
||||
0.107,
|
||||
0.179,
|
||||
0.293,
|
||||
0.344,
|
||||
0.34])
|
||||
|
||||
self.assertEqual([round(x.benchmark_volatility, 3)
|
||||
for x in metrics.six_month_periods],
|
||||
[0.15,
|
||||
0.149,
|
||||
0.15,
|
||||
0.2,
|
||||
0.308,
|
||||
0.36,
|
||||
0.383])
|
||||
# TODO: ugly, but I can't get the rounded float to match.
|
||||
# maybe we need a different test that checks the
|
||||
# difference between the numbers
|
||||
self.assertEqual([round(x.benchmark_volatility, 3)
|
||||
for x in metrics.year_periods],
|
||||
[0.411])
|
||||
|
||||
def test_treasury_returns_06(self):
|
||||
def test_treasury_returns(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params,
|
||||
trading_calendar=self.trading_calendar,
|
||||
@@ -502,37 +407,13 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
[0.0500])
|
||||
|
||||
def test_benchmarkrange(self):
|
||||
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)
|
||||
# self.check_year_range(
|
||||
# datetime.datetime(
|
||||
# year=2008, month=1, day=1, tzinfo=pytz.utc),
|
||||
# 2)
|
||||
self.check_year_range(
|
||||
pd.Timestamp('2008-01-01', tz=pytz.utc),
|
||||
2)
|
||||
|
||||
def test_partial_month(self):
|
||||
|
||||
start_session = self.trading_calendar.minute_to_session_label(
|
||||
pd.Timestamp("1991-01-01", tz='UTC')
|
||||
)
|
||||
start = pd.Timestamp('1991-01-01', tz=pytz.utc)
|
||||
|
||||
# 1992 and 1996 were leap years
|
||||
total_days = 365 * 5 + 2
|
||||
@@ -623,20 +504,6 @@ 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)
|
||||
|
||||
def test_sparse_benchmark(self):
|
||||
benchmark_returns = self.benchmark_returns_06.copy()
|
||||
# Set every other day to nan.
|
||||
benchmark_returns.iloc[::2] = np.nan
|
||||
|
||||
report = risk.RiskReport(
|
||||
self.algo_returns_06,
|
||||
self.sim_params,
|
||||
benchmark_returns=benchmark_returns,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
for risk_period in chain.from_iterable(itervalues(report.to_dict())):
|
||||
self.assertIsNone(risk_period['beta'])
|
||||
self.assert_month(start_date.month, col[-1].end_date.month)
|
||||
self.assert_last_day(col[-1].end_date)
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2013 Quantopian, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
Utility script for maintainer use to upload current version of the answer key
|
||||
spreadsheet to S3.
|
||||
"""
|
||||
import hashlib
|
||||
|
||||
import boto
|
||||
|
||||
from . import answer_key
|
||||
|
||||
BUCKET_NAME = 'zipline-test-data'
|
||||
|
||||
|
||||
def main():
|
||||
with open(answer_key.ANSWER_KEY_PATH, 'r') as f:
|
||||
md5 = hashlib.md5()
|
||||
while True:
|
||||
buf = f.read(1024)
|
||||
if not buf:
|
||||
break
|
||||
md5.update(buf)
|
||||
local_hash = md5.hexdigest()
|
||||
|
||||
s3_conn = boto.connect_s3()
|
||||
|
||||
bucket = s3_conn.get_bucket(BUCKET_NAME)
|
||||
key = boto.s3.key.Key(bucket)
|
||||
|
||||
key.key = "risk/{local_hash}/risk-answer-key.xlsx".format(
|
||||
local_hash=local_hash)
|
||||
key.set_contents_from_filename(answer_key.ANSWER_KEY_PATH)
|
||||
key.set_acl('public-read')
|
||||
|
||||
download_link = "http://s3.amazonaws.com/{bucket_name}/{key}".format(
|
||||
bucket_name=BUCKET_NAME,
|
||||
key=key.key)
|
||||
|
||||
print("Uploaded to key: {key}".format(key=key.key))
|
||||
print("Download link: {download_link}".format(download_link=download_link))
|
||||
|
||||
# Now update checksum file with the recently added answer key.
|
||||
# checksum file update will be then need to be commited via git.
|
||||
with open(answer_key.ANSWER_KEY_CHECKSUMS_PATH, 'a') as checksum_file:
|
||||
checksum_file.write(local_hash)
|
||||
checksum_file.write("\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user