From a4ea3e3343245ff187c1904c6b0063f29d38abda Mon Sep 17 00:00:00 2001 From: fawce Date: Wed, 30 May 2012 23:55:25 -0400 Subject: [PATCH 1/5] marked a todo for a calculation bug --- zipline/finance/risk.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zipline/finance/risk.py b/zipline/finance/risk.py index f4bd736f..b4888f9e 100644 --- a/zipline/finance/risk.py +++ b/zipline/finance/risk.py @@ -187,6 +187,8 @@ class RiskMetrics(): return period_returns, returns def calculate_volatility(self, daily_returns): + # TODO: we should be using an annualized number for the + # square root, not the days in the period. return np.std(daily_returns, ddof=1) * math.sqrt(self.trading_days) def calculate_sharpe(self): From 036f9e93a7c87d18620cfaea27f492a64ca86b5f Mon Sep 17 00:00:00 2001 From: fawce Date: Thu, 31 May 2012 23:15:53 -0400 Subject: [PATCH 2/5] fixed a type-o in the documentation. --- zipline/finance/risk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zipline/finance/risk.py b/zipline/finance/risk.py index b4888f9e..a63cf872 100644 --- a/zipline/finance/risk.py +++ b/zipline/finance/risk.py @@ -27,7 +27,7 @@ Risk Report | alpha | The _algorithm_ alpha to the benchmark. | +-----------------+----------------------------------------------------+ | excess_return | The excess return of the algorithm over the | - | | benchmark. | + | | treasuries. | +-----------------+----------------------------------------------------+ | max_drawdown | The largest relative peak to relative trough move | | | for the portfolio returns between self.start_date | From 6d8a786214cb77a8858457ddeac3eeae88f310e9 Mon Sep 17 00:00:00 2001 From: fawce Date: Thu, 7 Jun 2012 13:53:45 -0400 Subject: [PATCH 3/5] updated performance to be trade by trade. --- zipline/finance/performance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index 5a2aeaef..f8380ae9 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -247,12 +247,12 @@ class PerformanceTracker(object): self.cumulative_performance.update_last_sale(event) self.todays_performance.update_last_sale(event) - - def handle_market_close(self): #calculate performance as of last trade self.cumulative_performance.calculate_performance() self.todays_performance.calculate_performance() + def handle_market_close(self): + # add the return results from today to the list of DailyReturn objects. todays_date = self.market_close.replace(hour=0, minute=0, second=0) todays_return_obj = risk.DailyReturn( @@ -503,7 +503,7 @@ class PerformancePeriod(object): 'capital_used' : self.period_capital_used, 'starting_value' : self.starting_value, 'starting_cash' : self.starting_cash, - 'ending_cash' : self.ending_cash, + 'cash' : self.ending_cash, 'portfolio_value' : self.ending_cash + self.ending_value, 'cumulative_capital_used' : self.cumulative_capital_used, 'max_capital_used' : self.max_capital_used, From 6a8654342add82ea6e6b69fe3c1d8ba8fae1d02f Mon Sep 17 00:00:00 2001 From: fawce Date: Thu, 7 Jun 2012 17:40:26 -0400 Subject: [PATCH 4/5] added an as_portfolio method to the PerformancePeriod. --- zipline/finance/performance.py | 90 +++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index f8380ae9..9f32ae09 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -59,11 +59,17 @@ Position Tracking +-----------------+----------------------------------------------------+ | last_sale_price | price at last sale of the security on the exchange | +-----------------+----------------------------------------------------+ + | cost_basis | the volume weighted average price paid per share | + +-----------------+----------------------------------------------------+ + Performance Period ================== +Performance Periods are updated with every trade. When calling +code needs + +---------------+------------------------------------------------------+ | key | value | +===============+======================================================+ @@ -190,7 +196,7 @@ class PerformanceTracker(object): ) def get_portfolio(self): - return self.cumulative_performance.to_ndict() + return self.cumulative_performance.as_portfolio() def open(self, context): if self.results_addr: @@ -490,64 +496,80 @@ class PerformancePeriod(object): self.positions[event.sid].last_sale_price = event.price self.positions[event.sid].last_sale_date = event.dt - def to_dict(self): - """ - Creates a dictionary representing the state of this performance - period. See header comments for a detailed description. - """ - positions = self.get_positions_list() - transactions = [x.as_dict() for x in self.processed_transactions] - + def __core_dict(self): rval = { 'ending_value' : self.ending_value, 'capital_used' : self.period_capital_used, 'starting_value' : self.starting_value, 'starting_cash' : self.starting_cash, - 'cash' : self.ending_cash, + 'ending_cash' : self.ending_cash, 'portfolio_value' : self.ending_cash + self.ending_value, 'cumulative_capital_used' : self.cumulative_capital_used, 'max_capital_used' : self.max_capital_used, 'max_leverage' : self.max_leverage, - 'positions' : positions, 'pnl' : self.pnl, 'returns' : self.returns, - 'transactions' : transactions, 'period_open' : self.period_open, 'period_close' : self.period_close } + return rval + + + def to_dict(self): + """ + Creates a dictionary representing the state of this performance + period. See header comments for a detailed description. + """ + rval = self.__core_dict() + positions = self.get_positions_list() + rval['positions'] = positions + # we want the key to be absent, not just empty - if not self.keep_transactions: - del rval['transactions'] + if self.keep_transactions: + transactions = [x.as_dict() for x in self.processed_transactions] + rval['transactions'] = transactions return rval - def to_ndict(self): + def as_portfolio(self): """ - Creates a ndict representing the state of this perfomance period. - Properties are the same as the results of to_dict. See header comments - for a detailed description. - + The purpose of this method is to provide a portfolio + object to algorithms running inside the same trading + client. The data needed is captured raw in a + PerformancePeriod, and in this method we rename some + fields for usability and remove extraneous fields. """ - positions = self.get_positions(ndicted=True) + portfolio = self.__core_dict() + # rename: + # ending_cash -> cash + # period_open -> backtest_start + # + # remove: + # period_close, starting_value, + # cumulative_capital_used, max_leverage, max_capital_used + portfolio['cash'] = portfolio['ending_cash'] + portfolio['start_date'] = portfolio['period_open'] + portfolio['position_value'] = portfolio['ending_value'] - positions = zp.ndict(positions) + del(portfolio['ending_cash']) + del(portfolio['period_open']) + del(portfolio['period_close']) + del(portfolio['starting_value']) + del(portfolio['ending_value']) + del(portfolio['cumulative_capital_used']) + del(portfolio['max_leverage']) + del(portfolio['max_capital_used']) - return zp.ndict({ - 'ending_value' : self.ending_value, - 'capital_used' : self.period_capital_used, - 'starting_value' : self.starting_value, - 'starting_cash' : self.starting_cash, - 'ending_cash' : self.ending_cash, - 'cumulative_capital_used' : self.cumulative_capital_used, - 'max_capital_used' : self.max_capital_used, - 'max_leverage' : self.max_leverage, - 'positions' : positions, - 'transactions' : self.processed_transactions - }) + portfolio['positions'] = self.get_positions(ndicted=True) + return zp.ndict(portfolio) def get_positions(self, ndicted=False): - positions = {} + if ndicted: + positions = zp.ndict({}) + else: + positions = {} + for sid, pos in self.positions.iteritems(): cur = pos.to_dict() if ndicted: From 0dea9c5ecb2154326ed7e7839d20b34c7b3aa6d6 Mon Sep 17 00:00:00 2001 From: fawce Date: Thu, 7 Jun 2012 17:58:30 -0400 Subject: [PATCH 5/5] finished comment --- zipline/finance/performance.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index 9f32ae09..e237ec7b 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -68,7 +68,10 @@ Performance Period ================== Performance Periods are updated with every trade. When calling -code needs +code needs a portfolio object that fulfills the algorithm +protocol, use the PerformancePeriod.as_portfolio method. See that +method for comments on the specific fields provided (and +omitted). +---------------+------------------------------------------------------+ | key | value |