Merge pull request #464 from quantopian/expand_perf_packet

adding net leverage, long/short exposure, long/short position count
This commit is contained in:
fawce
2015-01-08 17:33:22 -05:00
3 changed files with 118 additions and 5 deletions
+13
View File
@@ -49,3 +49,16 @@
> # The standard deviation of the price in the last 3 days.
> data[security].stdev(3)
> ```
* New fields in Performance Period
[PR464](https://github.com/quantopian/zipline/pull/464)
> Performance Period has new fields accessible in return value of to_dict:
> - gross leverage
> - net leverage
> - short exposure
> - long exposure
> - shorts count
> - longs count
+85
View File
@@ -53,6 +53,29 @@ oneday = timedelta(days=1)
tradingday = timedelta(hours=6, minutes=30)
def check_perf_period(pp,
gross_leverage,
net_leverage,
long_exposure,
longs_count,
short_exposure,
shorts_count):
perf_data = pp.to_dict()
np.testing.assert_allclose(
gross_leverage, perf_data['gross_leverage'], rtol=1e-3)
np.testing.assert_allclose(
net_leverage, perf_data['net_leverage'], rtol=1e-3)
np.testing.assert_allclose(
long_exposure, perf_data['long_exposure'], rtol=1e-3)
np.testing.assert_allclose(
longs_count, perf_data['longs_count'], rtol=1e-3)
np.testing.assert_allclose(
short_exposure, perf_data['short_exposure'], rtol=1e-3)
np.testing.assert_allclose(
shorts_count, perf_data['shorts_count'], rtol=1e-3)
def check_account(account,
settled_cash,
equity_with_loan,
@@ -865,6 +888,14 @@ class TestPositionPerformance(unittest.TestCase):
pp.calculate_performance()
check_perf_period(
pp,
gross_leverage=2.0,
net_leverage=0.0,
long_exposure=1000.0,
longs_count=1,
short_exposure=-1000.0,
shorts_count=1)
# Validate that the account attributes were updated.
account = pp.as_account()
check_account(account,
@@ -889,6 +920,15 @@ class TestPositionPerformance(unittest.TestCase):
# Validate that the account attributes were updated.
account = pp.as_account()
check_perf_period(
pp,
gross_leverage=2.5,
net_leverage=-0.25,
long_exposure=900.0,
longs_count=1,
short_exposure=-1100.0,
shorts_count=1)
check_account(account,
settled_cash=1000.0,
equity_with_loan=800.0,
@@ -925,6 +965,15 @@ class TestPositionPerformance(unittest.TestCase):
pp.calculate_performance()
check_perf_period(
pp,
gross_leverage=10.0,
net_leverage=10.0,
long_exposure=10000.0,
longs_count=1,
short_exposure=0.0,
shorts_count=0)
# Validate that the account attributes were updated.
account = pp.as_account()
check_account(account,
@@ -944,6 +993,15 @@ class TestPositionPerformance(unittest.TestCase):
pp.calculate_performance()
check_perf_period(
pp,
gross_leverage=5.5,
net_leverage=5.5,
long_exposure=11000.0,
longs_count=1,
short_exposure=0.0,
shorts_count=0)
# Validate that the account attributes were updated.
account = pp.as_account()
@@ -1039,6 +1097,15 @@ class TestPositionPerformance(unittest.TestCase):
self.assertEqual(pp.pnl, 100, "gain of 1 on 100 shares should be 100")
check_perf_period(
pp,
gross_leverage=1.0,
net_leverage=1.0,
long_exposure=1100.0,
longs_count=1,
short_exposure=0.0,
shorts_count=0)
# Validate that the account attributes were updated.
account = pp.as_account()
check_account(account,
@@ -1242,6 +1309,15 @@ cost of sole txn in test"
"drop of 1 on -100 shares should be 100"
)
check_perf_period(
pp,
gross_leverage=0.8181,
net_leverage=-0.8181,
long_exposure=0.0,
longs_count=0,
short_exposure=-900.0,
shorts_count=1)
# Validate that the account attributes.
account = ppTotal.as_account()
check_account(account,
@@ -1337,6 +1413,15 @@ shares in position"
"gain of 1 on 100 shares should be 300"
)
check_perf_period(
pp,
gross_leverage=0.0,
net_leverage=0.0,
long_exposure=0.0,
longs_count=0,
short_exposure=0.0,
shorts_count=0)
account = pp.as_account()
check_account(account,
settled_cash=1300.0,
+20 -5
View File
@@ -320,25 +320,35 @@ class PerformancePeriod(object):
def calculate_positions_value(self):
return np.dot(self._position_amounts, self._position_last_sale_prices)
def _long_value(self):
def _longs_count(self):
longs = self._position_amounts[self._position_amounts > 0]
return longs.count()
def _long_exposure(self):
pos_values = self._position_amounts * self._position_last_sale_prices
longs = pos_values[pos_values > 0]
return longs.sum()
def _short_value(self):
def _shorts_count(self):
shorts = self._position_amounts[self._position_amounts < 0]
return shorts.count()
def _short_exposure(self):
pos_values = self._position_amounts * self._position_last_sale_prices
shorts = pos_values[pos_values < 0]
return shorts.sum()
def _gross_exposure(self):
return self._long_value() + abs(self._short_value())
return self._long_exposure() + abs(self._short_exposure())
def _net_exposure(self):
return self.calculate_positions_value()
@property
def _net_liquidation_value(self):
return self.ending_cash + self._long_value() + self._short_value()
return self.ending_cash + \
self._long_exposure() + \
self._short_exposure()
def _gross_leverage(self):
net_liq = self._net_liquidation_value
@@ -380,7 +390,12 @@ class PerformancePeriod(object):
'returns': self.returns,
'period_open': self.period_open,
'period_close': self.period_close,
'gross_leverage': self._gross_leverage()
'gross_leverage': self._gross_leverage(),
'net_leverage': self._net_leverage(),
'short_exposure': self._short_exposure(),
'long_exposure': self._long_exposure(),
'longs_count': self._longs_count(),
'shorts_count': self._shorts_count()
}
return rval