mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-27 11:20:45 +08:00
Merge pull request #1337 from quantopian/margin_changes
Capital Changes Refactoring
This commit is contained in:
+69
-1
@@ -409,9 +409,13 @@ class TradingAlgorithm(object):
|
||||
|
||||
self.benchmark_sid = kwargs.pop('benchmark_sid', None)
|
||||
|
||||
# A dictionary of capital change values keyed by timestamp
|
||||
# A dictionary of capital changes, keyed by timestamp, indicating the
|
||||
# target/delta of the capital changes, along with values
|
||||
self.capital_changes = kwargs.pop('capital_changes', {})
|
||||
|
||||
# A dictionary of the actual capital change deltas, keyed by timestamp
|
||||
self.capital_change_deltas = {}
|
||||
|
||||
def init_engine(self, get_loader):
|
||||
"""
|
||||
Construct and store a PipelineEngine from loader.
|
||||
@@ -786,6 +790,70 @@ class TradingAlgorithm(object):
|
||||
|
||||
return daily_stats
|
||||
|
||||
def calculate_capital_changes(self, dt, emission_rate, is_interday):
|
||||
"""
|
||||
If there is a capital change for a given dt, this means the the change
|
||||
occurs before `handle_data` on the given dt. In the case of the
|
||||
change being a target value, the change will be computed on the
|
||||
portfolio value according to prices at the given dt
|
||||
"""
|
||||
try:
|
||||
capital_change = self.capital_changes[dt]
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
if emission_rate == 'daily':
|
||||
# If we are running daily emission, prices won't
|
||||
# necessarily be synced at the end of every minute, and we
|
||||
# need the up-to-date prices for capital change
|
||||
# calculations. We want to sync the prices as of the
|
||||
# last market minute, and this is okay from a data portal
|
||||
# perspective as we have technically not "advanced" to the
|
||||
# current dt yet.
|
||||
self.perf_tracker.position_tracker.sync_last_sale_prices(
|
||||
self.trading_calendar.previous_minute(
|
||||
dt
|
||||
),
|
||||
False,
|
||||
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()
|
||||
|
||||
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
|
||||
|
||||
log.info('Processing capital change to target %s at %s. Capital '
|
||||
'change delta is %s' % (capital_change['value'], dt,
|
||||
capital_change_amount))
|
||||
elif capital_change['type'] == 'delta':
|
||||
capital_change_amount = capital_change['value']
|
||||
log.info('Processing capital change of delta %s at %s'
|
||||
% (capital_change_amount, dt))
|
||||
else:
|
||||
log.error("Capital change %s does not indicate a valid type "
|
||||
"('target' or 'delta')" % capital_change)
|
||||
return
|
||||
|
||||
self.capital_change_deltas.update({dt: capital_change_amount})
|
||||
self.perf_tracker.process_capital_change(capital_change_amount,
|
||||
is_interday)
|
||||
|
||||
@api_method
|
||||
def get_environment(self, field='platform'):
|
||||
"""Query the execution environment.
|
||||
|
||||
Reference in New Issue
Block a user