mirror of
https://github.com/wassname/catalyst.git
synced 2026-06-30 18:13:58 +08:00
ENH: Track max leverage as risk
This commit is contained in:
@@ -397,14 +397,16 @@ class PerformanceTracker(object):
|
||||
# returns for the bench and the algo
|
||||
self.intraday_risk_metrics.update(dt,
|
||||
minute_returns,
|
||||
self.all_benchmark_returns[dt])
|
||||
self.all_benchmark_returns[dt],
|
||||
self.get_account(True))
|
||||
|
||||
bench_since_open = \
|
||||
self.intraday_risk_metrics.benchmark_cumulative_returns[dt]
|
||||
|
||||
self.cumulative_risk_metrics.update(todays_date,
|
||||
self.todays_performance.returns,
|
||||
bench_since_open)
|
||||
bench_since_open,
|
||||
self.get_account(True))
|
||||
|
||||
# if this is the close, save the returns objects for cumulative risk
|
||||
# calculations and update dividends for the next day.
|
||||
@@ -416,7 +418,6 @@ class PerformanceTracker(object):
|
||||
Function called at market close only when emitting at minutely
|
||||
frequency.
|
||||
"""
|
||||
|
||||
# update_performance should have been called in handle_minute_close
|
||||
# so it is not repeated here.
|
||||
self.intraday_risk_metrics = \
|
||||
@@ -438,7 +439,8 @@ class PerformanceTracker(object):
|
||||
self.cumulative_risk_metrics.update(
|
||||
completed_date,
|
||||
self.todays_performance.returns,
|
||||
self.all_benchmark_returns[completed_date])
|
||||
self.all_benchmark_returns[completed_date],
|
||||
self.get_account(True))
|
||||
|
||||
# increment the day counter before we move markers forward.
|
||||
self.day_count += 1.0
|
||||
@@ -481,10 +483,12 @@ class PerformanceTracker(object):
|
||||
|
||||
bms = self.cumulative_risk_metrics.benchmark_returns
|
||||
ars = self.cumulative_risk_metrics.algorithm_returns
|
||||
acl = self.cumulative_risk_metrics.algorithm_cumulative_leverages
|
||||
self.risk_report = risk.RiskReport(
|
||||
ars,
|
||||
self.sim_params,
|
||||
benchmark_returns=bms)
|
||||
benchmark_returns=bms,
|
||||
algorithm_leverages=acl)
|
||||
|
||||
risk_dict = self.risk_report.to_dict()
|
||||
return risk_dict
|
||||
|
||||
@@ -93,7 +93,8 @@ class RiskMetricsCumulative(object):
|
||||
|
||||
def __init__(self, sim_params,
|
||||
returns_frequency=None,
|
||||
create_first_day_stats=False):
|
||||
create_first_day_stats=False,
|
||||
account=None):
|
||||
"""
|
||||
- @returns_frequency allows for configuration of the whether
|
||||
the benchmark and algorithm returns are in units of minutes or days,
|
||||
@@ -143,6 +144,7 @@ class RiskMetricsCumulative(object):
|
||||
|
||||
self.algorithm_returns_cont = pd.Series(index=cont_index)
|
||||
self.benchmark_returns_cont = pd.Series(index=cont_index)
|
||||
self.algorithm_cumulative_leverages_cont = pd.Series(index=cont_index)
|
||||
self.mean_returns_cont = pd.Series(index=cont_index)
|
||||
self.annualized_mean_returns_cont = pd.Series(index=cont_index)
|
||||
self.mean_benchmark_returns_cont = pd.Series(index=cont_index)
|
||||
@@ -160,6 +162,7 @@ class RiskMetricsCumulative(object):
|
||||
|
||||
self.algorithm_cumulative_returns = pd.Series(index=cont_index)
|
||||
self.benchmark_cumulative_returns = pd.Series(index=cont_index)
|
||||
self.algorithm_cumulative_leverages = pd.Series(index=cont_index)
|
||||
self.excess_returns = pd.Series(index=cont_index)
|
||||
|
||||
self.latest_dt = cont_index[0]
|
||||
@@ -171,6 +174,8 @@ class RiskMetricsCumulative(object):
|
||||
self.drawdowns = pd.Series(index=cont_index)
|
||||
self.max_drawdowns = pd.Series(index=cont_index)
|
||||
self.max_drawdown = 0
|
||||
self.max_leverages = pd.Series(index=cont_index)
|
||||
self.max_leverage = 0
|
||||
self.current_max = -np.inf
|
||||
self.daily_treasury = pd.Series(index=self.trading_days)
|
||||
self.treasury_period_return = np.nan
|
||||
@@ -195,7 +200,7 @@ class RiskMetricsCumulative(object):
|
||||
def get_daily_index(self):
|
||||
return self.trading_days
|
||||
|
||||
def update(self, dt, algorithm_returns, benchmark_returns):
|
||||
def update(self, dt, algorithm_returns, benchmark_returns, account):
|
||||
# Keep track of latest dt for use in to_dict and other methods
|
||||
# that report current state.
|
||||
self.latest_dt = dt
|
||||
@@ -261,6 +266,15 @@ class RiskMetricsCumulative(object):
|
||||
self.annualized_mean_benchmark_returns = \
|
||||
self.annualized_mean_benchmark_returns_cont[:dt]
|
||||
|
||||
self.algorithm_cumulative_leverages_cont[dt] = account['leverage']
|
||||
self.algorithm_cumulative_leverages = self.algorithm_cumulative_leverages_cont[:dt]
|
||||
|
||||
if self.create_first_day_stats:
|
||||
if len(self.algorithm_cumulative_leverages) == 1:
|
||||
self.algorithm_cumulative_leverages = pd.Series(
|
||||
{self.day_before_start: 0.0}).append(
|
||||
self.algorithm_cumulative_leverages)
|
||||
|
||||
if not self.algorithm_returns.index.equals(
|
||||
self.benchmark_returns.index
|
||||
):
|
||||
@@ -305,6 +319,8 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}"
|
||||
self.metrics.information[dt] = self.calculate_information()
|
||||
self.max_drawdown = self.calculate_max_drawdown()
|
||||
self.max_drawdowns[dt] = self.max_drawdown
|
||||
self.max_leverage = self.calculate_max_leverage()
|
||||
self.max_leverages[dt] = self.max_leverage
|
||||
|
||||
def to_dict(self):
|
||||
"""
|
||||
@@ -331,6 +347,7 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}"
|
||||
'information': self.metrics.information[dt],
|
||||
'excess_return': self.excess_returns[dt],
|
||||
'max_drawdown': self.max_drawdown,
|
||||
'max_leverage': self.max_leverage,
|
||||
'period_label': period_label
|
||||
}
|
||||
|
||||
@@ -383,6 +400,17 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}"
|
||||
else:
|
||||
return self.max_drawdown
|
||||
|
||||
def calculate_max_leverage(self):
|
||||
# The leverage is defined as: the gross_exposure/net_liquidation
|
||||
# gross_exposure = long_exposure + abs(short_exposure)
|
||||
# net_liquidation = ending_cash + long_exposure + short_exposure
|
||||
cur_leverage = self.algorithm_cumulative_leverages[self.latest_dt]
|
||||
|
||||
if cur_leverage is None or self.max_leverage > cur_leverage:
|
||||
return self.max_leverage
|
||||
else:
|
||||
return cur_leverage
|
||||
|
||||
def calculate_sharpe(self):
|
||||
"""
|
||||
http://en.wikipedia.org/wiki/Sharpe_ratio
|
||||
|
||||
@@ -48,7 +48,7 @@ choose_treasury = functools.partial(risk.choose_treasury,
|
||||
|
||||
class RiskMetricsPeriod(object):
|
||||
def __init__(self, start_date, end_date, returns,
|
||||
benchmark_returns=None):
|
||||
benchmark_returns=None, algorithm_leverages=None):
|
||||
|
||||
treasury_curves = trading.environment.treasury_curves
|
||||
if treasury_curves.index[-1] >= start_date:
|
||||
@@ -71,6 +71,8 @@ class RiskMetricsPeriod(object):
|
||||
|
||||
self.algorithm_returns = self.mask_returns_to_period(returns)
|
||||
self.benchmark_returns = self.mask_returns_to_period(benchmark_returns)
|
||||
self.algorithm_leverages = algorithm_leverages
|
||||
|
||||
self.calculate_metrics()
|
||||
|
||||
def calculate_metrics(self):
|
||||
@@ -131,6 +133,7 @@ class RiskMetricsPeriod(object):
|
||||
self.excess_return = self.algorithm_period_returns - \
|
||||
self.treasury_period_return
|
||||
self.max_drawdown = self.calculate_max_drawdown()
|
||||
self.max_leverage = self.calculate_max_leverage()
|
||||
|
||||
def to_dict(self):
|
||||
"""
|
||||
@@ -152,6 +155,7 @@ class RiskMetricsPeriod(object):
|
||||
'alpha': self.alpha,
|
||||
'excess_return': self.excess_return,
|
||||
'max_drawdown': self.max_drawdown,
|
||||
'max_leverage': self.max_leverage,
|
||||
'period_label': period_label
|
||||
}
|
||||
|
||||
@@ -175,6 +179,7 @@ class RiskMetricsPeriod(object):
|
||||
"beta",
|
||||
"alpha",
|
||||
"max_drawdown",
|
||||
"max_leverage",
|
||||
"algorithm_returns",
|
||||
"benchmark_returns",
|
||||
"condition_number",
|
||||
@@ -284,12 +289,13 @@ class RiskMetricsPeriod(object):
|
||||
for r in self.algorithm_returns:
|
||||
try:
|
||||
cur_return += math.log(1.0 + r)
|
||||
# this is a guard for a single day returning -100%
|
||||
# this is a guard for a single day returning -100%, if returns are
|
||||
# greater than -1.0 it will throw an error because you cannot take
|
||||
# the log of a negative number
|
||||
except ValueError:
|
||||
log.debug("{cur} return, zeroing the returns".format(
|
||||
cur=cur_return))
|
||||
cur_return = 0.0
|
||||
# BUG? Shouldn't this be set to log(1.0 + 0) ?
|
||||
compounded_returns.append(cur_return)
|
||||
|
||||
cur_max = None
|
||||
@@ -307,6 +313,9 @@ class RiskMetricsPeriod(object):
|
||||
|
||||
return 1.0 - math.exp(max_drawdown)
|
||||
|
||||
def calculate_max_leverage(self):
|
||||
return max(self.algorithm_leverages.values)
|
||||
|
||||
def __getstate__(self):
|
||||
state_dict = \
|
||||
{k: v for k, v in iteritems(self.__dict__) if
|
||||
|
||||
@@ -51,7 +51,9 @@ Risk Report
|
||||
| | for the portfolio returns between self.start_date |
|
||||
| | and self.end_date. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
|
||||
| max_leverage | The largest gross leverage between self.start_date |
|
||||
| | and self.end_date |
|
||||
+-----------------+----------------------------------------------------+
|
||||
|
||||
"""
|
||||
|
||||
@@ -70,15 +72,19 @@ log = logbook.Logger('Risk Report')
|
||||
|
||||
|
||||
class RiskReport(object):
|
||||
def __init__(self, algorithm_returns, sim_params, benchmark_returns=None):
|
||||
def __init__(self, algorithm_returns, sim_params, benchmark_returns=None, algorithm_leverages=None):
|
||||
"""
|
||||
algorithm_returns needs to be a list of daily_return objects
|
||||
sorted in date ascending order
|
||||
|
||||
account needs to be a list of account objects sorted in date
|
||||
ascending order
|
||||
"""
|
||||
|
||||
self.algorithm_returns = algorithm_returns
|
||||
self.sim_params = sim_params
|
||||
self.benchmark_returns = benchmark_returns
|
||||
self.algorithm_leverages = algorithm_leverages
|
||||
|
||||
if len(self.algorithm_returns) == 0:
|
||||
start_date = self.sim_params.period_start
|
||||
@@ -136,7 +142,8 @@ class RiskReport(object):
|
||||
start_date=cur_start,
|
||||
end_date=cur_end,
|
||||
returns=self.algorithm_returns,
|
||||
benchmark_returns=self.benchmark_returns
|
||||
benchmark_returns=self.benchmark_returns,
|
||||
algorithm_leverages = self.algorithm_leverages,
|
||||
)
|
||||
|
||||
ends.append(cur_period_metrics)
|
||||
|
||||
@@ -51,6 +51,9 @@ Risk Report
|
||||
| | for the portfolio returns between self.start_date |
|
||||
| | and self.end_date. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| max_leverage | The largest gross leverage between self.start_date |
|
||||
| | and self.end_date |
|
||||
+-----------------+----------------------------------------------------+
|
||||
|
||||
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user