Merge pull request #1359 from quantopian/refactor_subperiod

MAINT: Refactor application of capital changes
This commit is contained in:
Andrew Liang
2016-08-01 14:00:48 -04:00
committed by GitHub
5 changed files with 42 additions and 35 deletions
+3 -4
View File
@@ -2264,12 +2264,11 @@ shares in position"
pt.execute_transaction(txn)
pp.handle_execution(txn)
# sync prices and calculate performance before we introduce a capital
# change
# sync prices before we introduce a capital change
pt.sync_last_sale_prices(trades[2].dt, False, data_portal)
pp.calculate_performance()
pp.subdivide_period(1000.0)
pp.initialize_subperiod_divider()
pp.set_current_subperiod_starting_values(1000.0)
pt.sync_last_sale_prices(trades[-1].dt, False, data_portal)
pp.calculate_performance()
+4 -17
View File
@@ -844,25 +844,12 @@ class TradingAlgorithm(object):
self.data_portal
)
# Calculate performance before we sync prices price for the current dt
self.perf_tracker.cumulative_performance.calculate_performance()
self.perf_tracker.todays_performance.calculate_performance()
self.perf_tracker.prepare_capital_change(is_interday)
if capital_change['type'] == 'target':
# Get an updated portfolio value as of this dt, but do it in a way
# so that the performance is not recalculated. This is done so
# that `process_capital_change` can find the performance values
# for the end of the subperiod, which is the previous dt
self.perf_tracker.position_tracker.sync_last_sale_prices(
dt,
self._in_before_trading_start,
self.data_portal
)
portfolio_value = \
self.perf_tracker.position_tracker.stats().net_value + \
self.perf_tracker.cumulative_performance.ending_cash
capital_change_amount = capital_change['value'] - portfolio_value
capital_change_amount = capital_change['value'] - \
self.updated_portfolio().portfolio_value
self.portfolio_needs_update = True
log.info('Processing capital change to target %s at %s. Capital '
'change delta is %s' % (capital_change['value'], dt,
+19 -7
View File
@@ -241,14 +241,12 @@ class PerformancePeriod(object):
else:
del self._payout_last_sale_prices[asset]
def subdivide_period(self, capital_change):
# Apply the capital change to the ending cash
self.ending_cash += capital_change
def initialize_subperiod_divider(self):
self.calculate_performance()
# Increment the total capital change occurred within the period
self._total_intraperiod_capital_change += capital_change
# Divide the period into subperiods
# Initialize a subperiod divider to stash the current performance
# values. Current period starting values are set to equal ending values
# of the previous subperiod
self.subperiod_divider = SubPeriodDivider(
prev_returns=self.returns,
prev_pnl=self.pnl,
@@ -257,6 +255,20 @@ class PerformancePeriod(object):
curr_starting_cash=self.ending_cash
)
def set_current_subperiod_starting_values(self, capital_change):
# Apply the capital change to the ending cash
self.ending_cash += capital_change
# Increment the total capital change occurred within the period
self._total_intraperiod_capital_change += capital_change
# Update the current subperiod starting cash to reflect the capital
# change
starting_value = self.subperiod_divider.curr_subperiod.starting_value
self.subperiod_divider.curr_subperiod = CurrSubPeriodStats(
starting_value=starting_value,
starting_cash=self.ending_cash)
def handle_dividends_paid(self, net_cash_payment):
if net_cash_payment:
self.handle_cash_payment(net_cash_payment)
+11 -2
View File
@@ -238,8 +238,16 @@ class PerformanceTracker(object):
return _dict
def prepare_capital_change(self, is_interday):
self.cumulative_performance.initialize_subperiod_divider()
if not is_interday:
# Change comes in the middle of day
self.todays_performance.initialize_subperiod_divider()
def process_capital_change(self, capital_change_amount, is_interday):
self.cumulative_performance.subdivide_period(capital_change_amount)
self.cumulative_performance.set_current_subperiod_starting_values(
capital_change_amount)
if is_interday:
# Change comes between days
@@ -247,7 +255,8 @@ class PerformanceTracker(object):
capital_change_amount)
else:
# Change comes in the middle of day
self.todays_performance.subdivide_period(capital_change_amount)
self.todays_performance.set_current_subperiod_starting_values(
capital_change_amount)
def process_transaction(self, transaction):
self.txn_count += 1
+5 -5
View File
@@ -100,11 +100,11 @@ class AlgorithmSimulator(object):
def every_bar(dt_to_use, current_data=self.current_data,
handle_data=algo.event_manager.handle_data):
# called every tick (minute or day).
algo.on_dt_changed(dt_to_use)
calculate_minute_capital_changes(dt_to_use)
self.simulation_dt = dt_to_use
algo.on_dt_changed(dt_to_use)
blotter = algo.blotter
perf_tracker = algo.perf_tracker
@@ -149,10 +149,6 @@ class AlgorithmSimulator(object):
perf_tracker = algo.perf_tracker
# process any capital changes that came overnight
algo.calculate_capital_changes(
midnight_dt, emission_rate=emission_rate, is_interday=True)
# Get the positions before updating the date so that prices are
# fetched for trading close instead of midnight
positions = algo.perf_tracker.position_tracker.positions
@@ -162,6 +158,10 @@ class AlgorithmSimulator(object):
self.simulation_dt = midnight_dt
algo.on_dt_changed(midnight_dt)
# process any capital changes that came overnight
algo.calculate_capital_changes(
midnight_dt, emission_rate=emission_rate, is_interday=True)
# we want to wait until the clock rolls over to the next day
# before cleaning up expired assets.
self._cleanup_expired_assets(midnight_dt, position_assets)