fixed dates front to back to be proper market open/close, and to use start/end first_open/last_close from the TradingEnvironment.

This commit is contained in:
fawce
2012-04-06 20:49:56 -04:00
parent 70d32f1bbc
commit 30dfc86ba9
9 changed files with 288 additions and 127 deletions
+23 -12
View File
@@ -118,6 +118,7 @@ Performance Period
"""
import datetime
import pytz
import msgpack
import pandas
import math
@@ -146,11 +147,11 @@ class PerformanceTracker():
self.trading_environment = trading_environment
self.trading_day = datetime.timedelta(hours = 6, minutes = 30)
self.calendar_day = datetime.timedelta(hours = 24)
self.started_at = datetime.datetime.utcnow()
self.started_at = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
self.period_start = self.trading_environment.period_start
self.period_end = self.trading_environment.period_end
self.market_open = self.period_start
self.market_open = self.trading_environment.first_open
self.market_close = self.market_open + self.trading_day
self.progress = 0.0
self.total_days = self.trading_environment.days_in_period
@@ -266,6 +267,16 @@ class PerformanceTracker():
returns=self.returns,
trading_environment=self.trading_environment
)
# increment the day counter before we move markers forward.
self.day_count += 1.0
# calculate progress of test
self.progress = self.day_count / self.total_days
# Output results
if self.result_stream:
msg = zp.PERF_FRAME(self.to_dict())
self.result_stream.send(msg)
#move the market day markers forward
self.market_open = self.market_open + self.calendar_day
@@ -276,16 +287,7 @@ class PerformanceTracker():
self.market_open = self.market_open + self.calendar_day
self.market_close = self.market_open + self.trading_day
self.day_count += 1.0
#calculate progress of test
self.progress = self.day_count / self.total_days
# Output Results
if self.result_stream:
msg = zp.PERF_FRAME(self.to_dict())
self.result_stream.send(msg)
# Roll over positions to current day.
self.todays_performance.calculate_performance()
self.todays_performance = PerformancePeriod(
@@ -299,6 +301,15 @@ class PerformanceTracker():
When the simulation is complete, run the full period risk report
and send it out on the result_stream.
"""
# the stream will end on the last trading day, but will not trigger
# an end of day, so we trigger the final market close here.
self.handle_market_close()
log_msg = "Simulated {n} trading days out of {m}."
qutil.LOGGER.info(log_msg.format(n=self.day_count, m=self.total_days))
qutil.LOGGER.info("first open: {d}".format(d=self.trading_environment.first_open))
self.risk_report = risk.RiskReport(
self.returns,
self.trading_environment
+9 -5
View File
@@ -64,7 +64,9 @@ def advance_by_months(dt, jump_in_months):
class DailyReturn():
def __init__(self, date, returns):
self.date = date
assert isinstance(date, datetime.datetime)
self.date = date.replace(hour=0, minute=0, second=0)
self.returns = returns
def to_dict(self):
@@ -304,9 +306,11 @@ class RiskMetrics():
if rate != None:
return rate * (td.days + 1) / 365
message = "no rate for end date = {dt} and term = {term}. Using zero."
message = message.format(dt=self.end_date,term=self.treasury_duration)
raise Exception(message)
message = "no rate for end date = {dt} and term = {term}. Check \
that date doesn't exceed treasury history range."
message = message.format(dt=self.end_date,term=self.treasury_duration)
raise Exception(message)
class RiskReport():
@@ -326,7 +330,7 @@ class RiskReport():
else:
start_date = self.algorithm_returns[0].date
end_date = self.algorithm_returns[-1].date
self.month_periods = self.periodsInRange(1, start_date, end_date)
self.three_month_periods = self.periodsInRange(3, start_date, end_date)
self.six_month_periods = self.periodsInRange(6, start_date, end_date)
+51 -5
View File
@@ -356,10 +356,10 @@ class TradingEnvironment(object):
self,
benchmark_returns,
treasury_curves,
period_start=None,
period_end=None,
capital_base=None,
max_drawdown=None
period_start = None,
period_end = None,
capital_base = None,
max_drawdown = None
):
self.trading_days = []
@@ -372,10 +372,55 @@ class TradingEnvironment(object):
self.capital_base = capital_base
self.period_trading_days = None
self.max_drawdown = max_drawdown
for bm in benchmark_returns:
self.trading_days.append(bm.date)
self.trading_day_map[bm.date] = bm
self.first_open = self.calculate_first_open()
self.last_close = self.calculate_last_close()
def calculate_first_open(self):
"""
Finds the first trading day on or after self.period_start.
"""
first_open = self.period_start
one_day = datetime.timedelta(days=1)
while not self.is_trading_day(first_open):
first_open = first_open + one_day
first_open = self.set_NYSE_time(first_open, 9, 30)
return first_open
def calculate_last_close(self):
"""
Finds the last trading day on or before self.period_end
"""
last_close = self.period_end
one_day = datetime.timedelta(days=1)
while not self.is_trading_day(last_close):
last_close = last_close - one_day
last_close = self.set_NYSE_time(last_close, 16, 00)
return last_close
#TODO: add other exchanges and timezones...
def set_NYSE_time(self, dt, hour, minute):
naive = datetime.datetime(
year=dt.year,
month=dt.month,
day=dt.day
)
local = pytz.timezone ('US/Eastern')
local_dt = naive.replace (tzinfo = local)
# set the clock to the opening bell in NYC time.
local_dt = local_dt.replace(hour=hour, minute=minute)
# convert to UTC
utc_dt = local_dt.astimezone (pytz.utc)
return utc_dt
def normalize_date(self, test_date):
return datetime.datetime(
@@ -399,6 +444,7 @@ class TradingEnvironment(object):
if date >= self.period_start:
self.period_trading_days.append(date)
return len(self.period_trading_days)
+37 -10
View File
@@ -634,6 +634,7 @@ def PERF_FRAME(perf):
daily_perf = {
'date' : EPOCH(date),
'date_string' : str(date),
'returns' : tp['returns'],
'pnl' : tp['pnl'],
'portfolio_value' : tp['ending_value']
@@ -675,8 +676,28 @@ def PERF_UNFRAME(msg):
# Date Helpers
# -----------------------
def EPOCH(some_date):
seconds = time.mktime(some_date.timetuple())
UNIX_EPOCH = datetime.datetime(1970, 1, 1, 0, 0, tzinfo = pytz.utc)
def EPOCH(utc_datetime):
"""
The key is to ensure all the dates you are using are in the utc timezone
before you start converting. See http://pytz.sourceforge.net/ to learn how
to do that properly. By normalizing to utc, you eliminate the ambiguity of
daylight savings transitions. Then you can safely use timedelta to calculate
distance from the unix epoch, and then convert to seconds or milliseconds.
Note that the resulting unix timestamp is itself in the UTC timezone. If you
wish to see the timestamp in a localized timezone, you will need to make
another conversion.
Also note that this will only work for dates after 1970.
"""
assert isinstance(utc_datetime, datetime.datetime)
# utc only please
assert utc_datetime.tzinfo == pytz.utc
# how long since the epoch?
delta = utc_datetime - UNIX_EPOCH
seconds = delta.total_seconds()
ms = seconds * 1000
return ms
@@ -694,10 +715,14 @@ def PACK_DATE(event):
:rtype: None
"""
assert isinstance(event.dt, datetime.datetime)
assert event.dt.tzinfo == pytz.utc #utc only please
year, month, day, hour, minute, second = event.dt.timetuple()[0:6]
micros = event.dt.microsecond
event['dt'] = tuple([year, month, day, hour, minute, second, micros])
# utc only please
assert event.dt.tzinfo == pytz.utc
event['dt'] = date_to_tuple(event['dt'])
def date_to_tuple(dt):
year, month, day, hour, minute, second = dt.timetuple()[0:6]
micros = dt.microsecond
return tuple([year, month, day, hour, minute, second, micros])
def UNPACK_DATE(event):
"""
@@ -720,12 +745,14 @@ def UNPACK_DATE(event):
assert len(event.dt) == 7
for item in event.dt:
assert isinstance(item, numbers.Integral)
year, month, day, hour, minute, second, micros = event.dt
event.dt = tuple_to_date(event.dt)
def tuple_to_date(date_tuple):
year, month, day, hour, minute, second, micros = date_tuple
dt = datetime.datetime(year, month, day, hour, minute, second)
dt = dt.replace(microsecond = micros, tzinfo = pytz.utc)
event.dt = dt
return dt
DATASOURCE_TYPE = Enum(
'ORDER',
'TRADE',
+30 -30
View File
@@ -14,40 +14,41 @@ from zipline.finance.trading import TradingEnvironment
def load_market_data():
fp_bm = open("./zipline/test/benchmark.msgpack", "rb")
bm_map = msgpack.loads(fp_bm.read())
bm_list = msgpack.loads(fp_bm.read())
bm_returns = []
for epoch, returns in bm_map.iteritems():
event_dt = datetime.fromtimestamp(epoch)
event_dt = event_dt.replace(
hour=0,
minute=0,
second=0,
tzinfo=pytz.utc
)
for packed_date, returns in bm_list:
event_dt = zp.tuple_to_date(packed_date)
#event_dt = event_dt.replace(
# hour=0,
# minute=0,
# second=0,
# tzinfo=pytz.utc
#)
daily_return = risk.DailyReturn(date=event_dt, returns=returns)
bm_returns.append(daily_return)
bm_returns = sorted(bm_returns, key=lambda(x): x.date)
fp_tr = open("./zipline/test/treasury_curves.msgpack", "rb")
tr_map = msgpack.loads(fp_tr.read())
tr_list = msgpack.loads(fp_tr.read())
tr_curves = {}
for epoch, curve in tr_map.iteritems():
tr_dt = datetime.fromtimestamp(epoch)
tr_dt = tr_dt.replace(hour=0, minute=0, second=0, tzinfo=pytz.utc)
for packed_date, curve in tr_list:
tr_dt = zp.tuple_to_date(packed_date)
#tr_dt = tr_dt.replace(hour=0, minute=0, second=0, tzinfo=pytz.utc)
tr_curves[tr_dt] = curve
return bm_returns, tr_curves
def create_trading_environment():
"""Construct a complete environment with reasonable defaults"""
benchmark_returns, treasury_curves = load_market_data()
start = datetime.strptime("01/01/2006","%m/%d/%Y")
start = start.replace(tzinfo=pytz.utc)
start = datetime(2006, 1, 1, tzinfo=pytz.utc)
end = datetime(2006, 12, 31, tzinfo=pytz.utc)
trading_environment = TradingEnvironment(
benchmark_returns,
treasury_curves,
period_start = start,
period_end = end,
capital_base = 100000.0
)
@@ -72,9 +73,9 @@ def get_next_trading_dt(current, interval, trading_calendar):
return next
def create_trade_history(sid, prices, amounts, start_time, interval, trading_calendar):
def create_trade_history(sid, prices, amounts, interval, trading_calendar):
trades = []
current = start_time.replace(tzinfo = pytz.utc)
current = trading_calendar.first_open
for price, amount in zip(prices, amounts):
@@ -94,9 +95,9 @@ def create_txn(sid, price, amount, datetime, btrid=None):
})
return txn
def create_txn_history(sid, priceList, amtList, startTime, interval, trading_calendar):
def create_txn_history(sid, priceList, amtList, interval, trading_calendar):
txns = []
current = startTime
current = trading_calendar.first_open
for price, amount in zip(priceList, amtList):
current = get_next_trading_dt(current, interval, trading_calendar)
@@ -106,13 +107,13 @@ def create_txn_history(sid, priceList, amtList, startTime, interval, trading_cal
return txns
def create_returns(daycount, start, trading_calendar):
def create_returns(daycount, trading_calendar):
"""
For the given number of calendar (not trading) days return all the trading
days between start and start + daycount.
"""
test_range = []
current = start.replace(tzinfo=pytz.utc)
current = trading_calendar.first_open
one_day = timedelta(days = 1)
for day in range(daycount):
@@ -124,9 +125,9 @@ def create_returns(daycount, start, trading_calendar):
return test_range
def create_returns_from_range(start, end, trading_calendar):
current = start.replace(tzinfo=pytz.utc)
end = end.replace(tzinfo=pytz.utc)
def create_returns_from_range(trading_calendar):
current = trading_calendar.first_open
end = trading_calendar.last_close
one_day = timedelta(days = 1)
test_range = []
while current <= end:
@@ -136,8 +137,8 @@ def create_returns_from_range(start, end, trading_calendar):
return test_range
def create_returns_from_list(returns, start, trading_calendar):
current = start.replace(tzinfo=pytz.utc)
def create_returns_from_list(returns, trading_calendar):
current = trading_calendar.first_open
one_day = timedelta(days = 1)
test_range = []
@@ -157,7 +158,7 @@ def create_random_trade_source(sid, trade_count, trading_environment):
source = RandomEquityTrades(sid, "rand-"+str(sid), trade_count)
# make the period_end of trading_environment match
cur = trading_environment.period_start
cur = trading_environment.first_open
one_day = timedelta(days = 1)
for i in range(trade_count + 2):
cur = get_next_trading_dt(cur, one_day, trading_environment)
@@ -179,14 +180,13 @@ def create_daily_trade_source(sids, trade_count, trading_environment):
for sid in sids:
price = [10.1] * trade_count
volume = [100] * trade_count
start_date = trading_environment.period_start
start_date = trading_environment.first_open
trade_time_increment = timedelta(days=1)
generated_trades = create_trade_history(
sid,
price,
volume,
start_date,
trade_time_increment,
trading_environment
)
+52
View File
@@ -50,6 +50,58 @@ class FinanceTestCase(TestCase):
if prev:
self.assertTrue(trade.dt > prev.dt)
prev = trade
@timed(DEFAULT_TIMEOUT)
def test_trading_environment(self):
benchmark_returns, treasury_curves = \
factory.load_market_data()
env = TradingEnvironment(
benchmark_returns,
treasury_curves,
period_start = datetime(2008, 1, 1, tzinfo = pytz.utc),
period_end = datetime(2008, 12, 31, tzinfo = pytz.utc),
capital_base = 100000,
max_drawdown = 0.50
)
#holidays taken from: http://www.nyse.com/press/1191407641943.html
new_years = datetime(2008, 1, 1, tzinfo = pytz.utc)
mlk_day = datetime(2008, 1, 21, tzinfo = pytz.utc)
presidents = datetime(2008, 2, 18, tzinfo = pytz.utc)
good_friday = datetime(2008, 3, 21, tzinfo = pytz.utc)
memorial_day= datetime(2008, 5, 26, tzinfo = pytz.utc)
july_4th = datetime(2008, 7, 4, tzinfo = pytz.utc)
labor_day = datetime(2008, 9, 1, tzinfo = pytz.utc)
tgiving = datetime(2008, 11, 27, tzinfo = pytz.utc)
christmas = datetime(2008, 5, 25, tzinfo = pytz.utc)
a_saturday = datetime(2008, 8, 2, tzinfo = pytz.utc)
a_sunday = datetime(2008, 10, 12, tzinfo = pytz.utc)
holidays = [
new_years,
mlk_day,
presidents,
good_friday,
memorial_day,
july_4th,
labor_day,
tgiving,
christmas,
a_saturday,
a_sunday
]
for holiday in holidays:
self.assertTrue(not env.is_trading_day(holiday))
first_trading_day = datetime(2008, 1, 2, tzinfo = pytz.utc)
last_trading_day = datetime(2008, 12, 31, tzinfo = pytz.utc)
workdays = [first_trading_day, last_trading_day]
for workday in workdays:
self.assertTrue(env.is_trading_day(workday))
self.assertTrue(env.last_close.month == 12)
self.assertTrue(env.last_close.day == 31)
@timed(DEFAULT_TIMEOUT)
def test_orders(self):
+21 -28
View File
@@ -18,18 +18,23 @@ class PerformanceTestCase(unittest.TestCase):
self.benchmark_returns, self.treasury_curves = \
factory.load_market_data()
random_index = random.randint(
0,
len(self.treasury_curves)
)
self.dt = self.treasury_curves.keys()[random_index]
self.end_dt = self.dt + datetime.timedelta(days=365+2)
self.trading_environment = TradingEnvironment(
self.benchmark_returns,
self.treasury_curves
self.treasury_curves,
period_start = self.dt,
period_end = self.end_dt
)
self.onesec = datetime.timedelta(seconds=1)
self.oneday = datetime.timedelta(days=1)
self.tradingday = datetime.timedelta(hours=6, minutes=30)
random_index = random.randint(
0,
len(self.trading_environment.trading_days)
)
self.dt = self.trading_environment.trading_days[random_index]
@@ -46,7 +51,6 @@ class PerformanceTestCase(unittest.TestCase):
1,
[10,10,10,11],
[100,100,100,100],
self.dt,
self.onesec,
self.trading_environment
)
@@ -110,15 +114,16 @@ class PerformanceTestCase(unittest.TestCase):
def test_short_position(self):
"""verify that the performance period calculates properly for a \
single short-sale transaction"""
trades_1 = factory.create_trade_history(
trades = factory.create_trade_history(
1,
[10,10,10,11],
[100,100,100,100],
self.dt,
[10,10,10,11,10,9],
[100,100,100,100,100,100],
self.onesec,
self.trading_environment
)
trades_1 = trades[:-2]
txn = factory.create_txn(1, 10.0, -100, self.dt + self.onesec)
pp = perf.PerformancePeriod({}, 0.0, 1000.0)
@@ -173,16 +178,9 @@ single short-sale transaction"""
self.assertEqual(pp.pnl,-100,"gain of 1 on 100 shares should be 100")
#simulate additional trades, and ensure that the position value
#reflects the new price
trades_2 = factory.create_trade_history(
1,
[10,9],
[100,100],
trades_1[-1]['dt'] + self.onesec,
self.onesec,
self.trading_environment
)
# simulate additional trades, and ensure that the position value
# reflects the new price
trades_2 = trades[-2:]
#simulate a rollover to a new period
pp2 = perf.PerformancePeriod(
@@ -314,7 +312,6 @@ trade after cover"""
1,
[10,10,10,11,9,8,7,8,9,10],
[100,100,100,100,100,100,100,100,100,100],
self.dt,
self.onesec,
self.trading_environment
)
@@ -393,8 +390,7 @@ shares in position"
trades = factory.create_trade_history(
1,
[10,11,11,12],
[100,100,100,100],
self.dt,
[100,100,100,100],
self.onesec,
self.trading_environment
)
@@ -403,7 +399,6 @@ shares in position"
1,
[10,11,11,12],
[100,100,100,100],
self.dt,
self.onesec,
self.trading_environment
)
@@ -510,14 +505,13 @@ shares in position"
price = 10.1
price_list = [price] * trade_count
volume = [100] * trade_count
start_date = datetime.datetime.strptime("01/01/2011","%m/%d/%Y")
start_date = start_date.replace(tzinfo=pytz.utc)
#start_date = datetime.datetime.strptime("01/01/2011","%m/%d/%Y")
#start_date = start_date.replace(tzinfo=pytz.utc)
trade_time_increment = datetime.timedelta(days=1)
trade_history = factory.create_trade_history(
sid,
price_list,
volume,
start_date,
trade_time_increment,
self.trading_environment
)
@@ -529,7 +523,6 @@ shares in position"
sid2,
price2_list,
volume,
start_date,
trade_time_increment,
self.trading_environment
)
-1
View File
@@ -39,7 +39,6 @@ class ProtocolTestCase(TestCase):
sid,
price,
volume,
start_date,
one_day_td,
self.trading_environment
)
+65 -36
View File
@@ -27,7 +27,9 @@ class Risk(unittest.TestCase):
self.trading_env = TradingEnvironment(
self.benchmark_returns,
self.treasury_curves
self.treasury_curves,
period_start = start_date,
period_end = end_date
)
self.onesec = datetime.timedelta(seconds=1)
@@ -37,7 +39,6 @@ class Risk(unittest.TestCase):
self.algo_returns_06 = factory.create_returns_from_list(
RETURNS,
start_date,
self.trading_env
)
@@ -46,26 +47,43 @@ class Risk(unittest.TestCase):
self.trading_env
)
start_08 = datetime.datetime(
year=2008,
month=1,
day=1,
hour=0,
minute=0,
tzinfo=pytz.utc)
end_08 = datetime.datetime(
year=2008,
month=12,
day=31,
tzinfo=pytz.utc
)
self.trading_env08 = TradingEnvironment(
self.benchmark_returns,
self.treasury_curves,
period_start = start_08,
period_end = end_08
)
def tearDown(self):
return
def test_factory(self):
returns = [0.1] * 100
start_date = datetime.datetime(year=2006, month=1, day=1, tzinfo=pytz.utc)
r_objects = factory.create_returns_from_list(returns, start_date, self.trading_env)
r_objects = factory.create_returns_from_list(returns, self.trading_env)
self.assertTrue(r_objects[-1].date <= datetime.datetime(year=2006, month=12, day=31, tzinfo=pytz.utc))
def test_drawdown(self):
start_date = datetime.datetime(year=2006, month=1, day=1)
returns = factory.create_returns_from_list([1.0,-0.5,0.8,.17,1.0,-0.1,-0.45], start_date, self.trading_env)
returns = factory.create_returns_from_list([1.0,-0.5,0.8,.17,1.0,-0.1,-0.45], self.trading_env)
#200, 100, 180, 210.6, 421.2, 379.8, 208.494
metrics = risk.RiskMetrics(returns[0].date, returns[-1].date, returns, self.trading_env)
self.assertEqual(metrics.max_drawdown, 0.505)
def test_benchmark_returns_06(self):
start_date = datetime.datetime(year=2006, month=1, day=1)
end_date = datetime.datetime(year=2006, month=12, day=31)
returns = factory.create_returns_from_range(start_date, end_date, self.trading_env)
returns = factory.create_returns_from_range(self.trading_env)
metrics = risk.RiskReport(returns, self.trading_env)
self.assertEqual([round(x.benchmark_period_returns, 4) for x in metrics.month_periods],
[0.0255,0.0005,0.0111,0.0122,-0.0309,0.0001,0.0051,0.0213,0.0246,0.0315,0.0165,0.0126])
@@ -76,17 +94,13 @@ class Risk(unittest.TestCase):
self.assertEqual([round(x.benchmark_period_returns,4) for x in metrics.year_periods],[0.1362])
def test_trading_days_06(self):
start_date = datetime.datetime(year=2006, month=1, day=1)
end_date = datetime.datetime(year=2006, month=12, day=31)
returns = factory.create_returns_from_range(start_date, end_date, self.trading_env)
returns = factory.create_returns_from_range(self.trading_env)
metrics = risk.RiskReport(returns, self.trading_env)
self.assertEqual([x.trading_days for x in metrics.year_periods],[251])
self.assertEqual([x.trading_days for x in metrics.month_periods],[20,19,23,19,22,22,20,23,20,22,21,20])
def test_benchmark_volatility_06(self):
start_date = datetime.datetime(year=2006, month=1, day=1)
end_date = datetime.datetime(year=2006, month=12, day=31)
returns = factory.create_returns_from_range(start_date, end_date, self.trading_env)
returns = factory.create_returns_from_range(self.trading_env)
metrics = risk.RiskReport(returns, self.trading_env)
self.assertEqual([round(x.benchmark_volatility, 3) for x in metrics.month_periods],
[0.031,0.026,0.024,0.025,0.037,0.047,0.039,0.022,0.023,0.021,0.025,0.019])
@@ -146,11 +160,13 @@ class Risk(unittest.TestCase):
def test_benchmark_returns_08(self):
start_date = datetime.datetime(year=2008, month=1, day=1)
end_date = datetime.datetime(year=2008, month=12, day=31)
returns = factory.create_returns_from_range(start_date, end_date, self.trading_env)
metrics = risk.RiskReport(returns, self.trading_env)
self.assertEqual([round(x.benchmark_period_returns, 3) for x in metrics.month_periods],
returns = factory.create_returns_from_range(self.trading_env08)
metrics = risk.RiskReport(returns, self.trading_env08)
monthly = [round(x.benchmark_period_returns, 3) for x in metrics.month_periods]
self.assertEqual( monthly,
[-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])
@@ -159,18 +175,14 @@ class Risk(unittest.TestCase):
self.assertEqual([round(x.benchmark_period_returns,3) for x in metrics.year_periods],[-0.385])
def test_trading_days_08(self):
start_date = datetime.datetime(year=2008, month=1, day=1)
end_date = datetime.datetime(year=2008, month=12, day=31)
returns = factory.create_returns_from_range(start_date, end_date, self.trading_env)
metrics = risk.RiskReport(returns, self.trading_env)
returns = factory.create_returns_from_range(self.trading_env08)
metrics = risk.RiskReport(returns, self.trading_env08)
self.assertEqual([x.trading_days for x in metrics.year_periods],[253])
self.assertEqual([x.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):
start_date = datetime.datetime(year=2008, month=1, day=1)
end_date = datetime.datetime(year=2008, month=12, day=31)
returns = factory.create_returns_from_range(start_date, end_date, self.trading_env)
metrics = risk.RiskReport(returns, self.trading_env)
returns = factory.create_returns_from_range(self.trading_env08)
metrics = risk.RiskReport(returns, self.trading_env08)
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],
@@ -181,9 +193,7 @@ class Risk(unittest.TestCase):
self.assertEqual([round(x.benchmark_volatility, 3) for x in metrics.year_periods],[0.41099999999999998])
def test_treasury_returns_06(self):
start_date = datetime.datetime(year=2006, month=1, day=1)
end_date = datetime.datetime(year=2006, month=12, day=31)
returns = factory.create_returns_from_range(start_date, end_date, self.trading_env)
returns = factory.create_returns_from_range(self.trading_env)
metrics = risk.RiskReport(returns, self.trading_env)
self.assertEqual([round(x.treasury_period_return, 4) for x in metrics.month_periods],
[0.0037,0.0034,0.0039,0.0038,0.0040,0.0037,0.0043,0.0043,0.0038,0.0044,0.0043,0.0041])
@@ -198,12 +208,31 @@ class Risk(unittest.TestCase):
self.check_year_range(datetime.datetime(year=2008,month=1,day=1), 2)
def test_partial_month(self):
start_date = datetime.datetime(year=1991, month=1, day=1)
returns = factory.create_returns(365 * 5 + 2, start_date, self.trading_env) #1992 and 1996 were leap years
start = datetime.datetime(
year=1991,
month=1,
day=1,
hour=0,
minute=0,
tzinfo=pytz.utc)
#1992 and 1996 were leap years
total_days = 365 * 5 + 2
end = start + datetime.timedelta(days = total_days)
trading_env90s = TradingEnvironment(
self.benchmark_returns,
self.treasury_curves,
period_start = start,
period_end = end
)
returns = factory.create_returns(total_days, trading_env90s)
returns = returns[:-10] #truncate the returns series to end mid-month
metrics = risk.RiskReport(returns, self.trading_env)
metrics = risk.RiskReport(returns, trading_env90s)
total_months = 60
self.check_metrics(metrics, total_months, start_date)
self.check_metrics(metrics, total_months, start)
def check_year_range(self, start_date, years):
if(start_date.month <= 2):
@@ -211,7 +240,7 @@ class Risk(unittest.TestCase):
else:
#because we may catch the leap of the last year, and i think this func is [start,end)
ld = calendar.leapdays(start_date.year, start_date.year + years + 1)
returns = factory.create_returns(365 * years + ld, start_date, self.trading_env)
returns = factory.create_returns(365 * years + ld, self.trading_env08)
metrics = risk.RiskReport(returns, self.trading_env)
total_months = years * 12
self.check_metrics(metrics, total_months, start_date)