mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-24 13:00:57 +08:00
Merge pull request #1322 from quantopian/move_risk_calculations
Move risk calculations
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.
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
@@ -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
|
||||
@@ -21,8 +21,13 @@ from zipline.utils import factory
|
||||
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):
|
||||
@@ -38,86 +43,104 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
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(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)
|
||||
|
||||
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_representation(self):
|
||||
assert all([metric in self.cumulative_metrics.__repr__() for metric in
|
||||
self.cumulative_metrics.METRIC_NAMES])
|
||||
|
||||
+337
-395
@@ -17,444 +17,302 @@ import datetime
|
||||
import calendar
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import pytz
|
||||
|
||||
from itertools import chain
|
||||
from six import itervalues
|
||||
|
||||
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()
|
||||
from zipline.finance.risk.period import RiskMetricsPeriod
|
||||
|
||||
RETURNS = ANSWER_KEY.RETURNS
|
||||
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()
|
||||
|
||||
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_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.benchmark_returns = factory.create_returns_from_list(
|
||||
BENCHMARK,
|
||||
self.sim_params
|
||||
)
|
||||
self.metrics = risk.RiskReport(
|
||||
self.algo_returns,
|
||||
self.sim_params,
|
||||
benchmark_returns=self.benchmark_returns_06,
|
||||
benchmark_returns=self.benchmark_returns,
|
||||
trading_calendar=self.trading_calendar,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
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))
|
||||
pd.Timestamp('2006-12-31', tz='UTC'))
|
||||
|
||||
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 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(
|
||||
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 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(
|
||||
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 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(
|
||||
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 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(
|
||||
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 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(
|
||||
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 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),
|
||||
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 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(
|
||||
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 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(
|
||||
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):
|
||||
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'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_covariance
|
||||
for x in self.metrics_06.three_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_COVARIANCE['3-Month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_covariance
|
||||
for x in self.metrics_06.six_month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_COVARIANCE['6-month'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.algorithm_covariance
|
||||
for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_COVARIANCE['year'])
|
||||
|
||||
def test_benchmark_variance_06(self):
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_variance
|
||||
for x in self.metrics_06.month_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BENCHMARK_VARIANCE['Monthly'])
|
||||
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'])
|
||||
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'])
|
||||
np.testing.assert_almost_equal(
|
||||
[x.benchmark_variance
|
||||
for x in self.metrics_06.year_periods],
|
||||
ANSWER_KEY.ALGORITHM_PERIOD_BENCHMARK_VARIANCE['year'])
|
||||
|
||||
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,
|
||||
@@ -523,10 +381,6 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
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)
|
||||
|
||||
def test_partial_month(self):
|
||||
|
||||
@@ -626,17 +480,105 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
||||
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
|
||||
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])
|
||||
|
||||
report = risk.RiskReport(
|
||||
self.algo_returns_06,
|
||||
self.sim_params,
|
||||
benchmark_returns=benchmark_returns,
|
||||
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,
|
||||
)
|
||||
for risk_period in chain.from_iterable(itervalues(report.to_dict())):
|
||||
self.assertIsNone(risk_period['beta'])
|
||||
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])
|
||||
|
||||
@@ -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()
|
||||
@@ -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