| Total Complexity | 47 | 
| Total Lines | 458 | 
| Duplicated Lines | 0 % | 
Complex classes like zipline.finance.performance.PerformanceTracker often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | #  | 
            ||
| 79 | class PerformanceTracker(object):  | 
            ||
| 80 | """  | 
            ||
| 81 | Tracks the performance of the algorithm.  | 
            ||
| 82 | """  | 
            ||
| 83 | def __init__(self, sim_params, env, data_portal):  | 
            ||
| 84 | self.sim_params = sim_params  | 
            ||
| 85 | self.env = env  | 
            ||
| 86 | |||
| 87 | self.period_start = self.sim_params.period_start  | 
            ||
| 88 | self.period_end = self.sim_params.period_end  | 
            ||
| 89 | self.last_close = self.sim_params.last_close  | 
            ||
| 90 | first_open = self.sim_params.first_open.tz_convert(  | 
            ||
| 91 | self.env.exchange_tz  | 
            ||
| 92 | )  | 
            ||
| 93 | self.day = pd.Timestamp(datetime(first_open.year, first_open.month,  | 
            ||
| 94 | first_open.day), tz='UTC')  | 
            ||
| 95 | self.market_open, self.market_close = env.get_open_and_close(self.day)  | 
            ||
| 96 | self.total_days = self.sim_params.days_in_period  | 
            ||
| 97 | self.capital_base = self.sim_params.capital_base  | 
            ||
| 98 | self.emission_rate = sim_params.emission_rate  | 
            ||
| 99 | |||
| 100 | all_trading_days = env.trading_days  | 
            ||
| 101 | mask = ((all_trading_days >= normalize_date(self.period_start)) &  | 
            ||
| 102 | (all_trading_days <= normalize_date(self.period_end)))  | 
            ||
| 103 | |||
| 104 | self.trading_days = all_trading_days[mask]  | 
            ||
| 105 | |||
| 106 | self._data_portal = data_portal  | 
            ||
| 107 | if data_portal is not None:  | 
            ||
| 108 | self._adjustment_reader = data_portal._adjustment_reader  | 
            ||
| 109 | else:  | 
            ||
| 110 | self._adjustment_reader = None  | 
            ||
| 111 | |||
| 112 | self.position_tracker = PositionTracker(asset_finder=env.asset_finder,  | 
            ||
| 113 | data_portal=data_portal)  | 
            ||
| 114 | |||
| 115 | if self.emission_rate == 'daily':  | 
            ||
| 116 | self.all_benchmark_returns = pd.Series(  | 
            ||
| 117 | index=self.trading_days)  | 
            ||
| 118 | self.cumulative_risk_metrics = \  | 
            ||
| 119 | risk.RiskMetricsCumulative(self.sim_params, self.env)  | 
            ||
| 120 | elif self.emission_rate == 'minute':  | 
            ||
| 121 | self.all_benchmark_returns = pd.Series(index=pd.date_range(  | 
            ||
| 122 | self.sim_params.first_open, self.sim_params.last_close,  | 
            ||
| 123 | freq='Min'))  | 
            ||
| 124 | |||
| 125 | self.cumulative_risk_metrics = \  | 
            ||
| 126 | risk.RiskMetricsCumulative(self.sim_params, self.env,  | 
            ||
| 127 | create_first_day_stats=True)  | 
            ||
| 128 | |||
| 129 | # this performance period will span the entire simulation from  | 
            ||
| 130 | # inception.  | 
            ||
| 131 | self.cumulative_performance = PerformancePeriod(  | 
            ||
| 132 | # initial cash is your capital base.  | 
            ||
| 133 | starting_cash=self.capital_base,  | 
            ||
| 134 | # the cumulative period will be calculated over the entire test.  | 
            ||
| 135 | period_open=self.period_start,  | 
            ||
| 136 | period_close=self.period_end,  | 
            ||
| 137 | # don't save the transactions for the cumulative  | 
            ||
| 138 | # period  | 
            ||
| 139 | keep_transactions=False,  | 
            ||
| 140 | keep_orders=False,  | 
            ||
| 141 | # don't serialize positions for cumulative period  | 
            ||
| 142 | serialize_positions=False,  | 
            ||
| 143 | asset_finder=self.env.asset_finder,  | 
            ||
| 144 | name="Cumulative"  | 
            ||
| 145 | )  | 
            ||
| 146 | |||
| 147 | # this performance period will span just the current market day  | 
            ||
| 148 | self.todays_performance = PerformancePeriod(  | 
            ||
| 149 | # initial cash is your capital base.  | 
            ||
| 150 | starting_cash=self.capital_base,  | 
            ||
| 151 | # the daily period will be calculated for the market day  | 
            ||
| 152 | period_open=self.market_open,  | 
            ||
| 153 | period_close=self.market_close,  | 
            ||
| 154 | keep_transactions=True,  | 
            ||
| 155 | keep_orders=True,  | 
            ||
| 156 | serialize_positions=True,  | 
            ||
| 157 | asset_finder=self.env.asset_finder,  | 
            ||
| 158 | name="Daily"  | 
            ||
| 159 | )  | 
            ||
| 160 | |||
| 161 | self.saved_dt = self.period_start  | 
            ||
| 162 | # one indexed so that we reach 100%  | 
            ||
| 163 | self.day_count = 0.0  | 
            ||
| 164 | self.txn_count = 0  | 
            ||
| 165 | |||
| 166 | self.account_needs_update = True  | 
            ||
| 167 | self._account = None  | 
            ||
| 168 | |||
| 169 | self._perf_periods = [self.cumulative_performance,  | 
            ||
| 170 | self.todays_performance]  | 
            ||
| 171 | |||
| 172 | @property  | 
            ||
| 173 | def perf_periods(self):  | 
            ||
| 174 | return self._perf_periods  | 
            ||
| 175 | |||
| 176 | def __repr__(self):  | 
            ||
| 177 | return "%s(%r)" % (  | 
            ||
| 178 | self.__class__.__name__,  | 
            ||
| 179 |             {'simulation parameters': self.sim_params}) | 
            ||
| 180 | |||
| 181 | @property  | 
            ||
| 182 | def progress(self):  | 
            ||
| 183 | if self.emission_rate == 'minute':  | 
            ||
| 184 | # Fake a value  | 
            ||
| 185 | return 1.0  | 
            ||
| 186 | elif self.emission_rate == 'daily':  | 
            ||
| 187 | return self.day_count / self.total_days  | 
            ||
| 188 | |||
| 189 | def set_date(self, date):  | 
            ||
| 190 | if self.emission_rate == 'minute':  | 
            ||
| 191 | self.saved_dt = date  | 
            ||
| 192 | self.todays_performance.period_close = self.saved_dt  | 
            ||
| 193 | |||
| 194 | def get_portfolio(self, dt):  | 
            ||
| 195 | position_tracker = self.position_tracker  | 
            ||
| 196 | position_tracker.sync_last_sale_prices(dt)  | 
            ||
| 197 | pos_stats = position_tracker.stats()  | 
            ||
| 198 | period_stats = self.cumulative_performance.stats(  | 
            ||
| 199 | position_tracker.positions, pos_stats, self._data_portal)  | 
            ||
| 200 | return self.cumulative_performance.as_portfolio(  | 
            ||
| 201 | pos_stats,  | 
            ||
| 202 | period_stats,  | 
            ||
| 203 | position_tracker,  | 
            ||
| 204 | dt)  | 
            ||
| 205 | |||
| 206 | def get_account(self, dt):  | 
            ||
| 207 | self.position_tracker.sync_last_sale_prices(dt)  | 
            ||
| 208 | pos_stats = self.position_tracker.stats()  | 
            ||
| 209 | period_stats = self.cumulative_performance.stats(  | 
            ||
| 210 | self.position_tracker.positions, pos_stats, self._data_portal)  | 
            ||
| 211 | self._account = self.cumulative_performance.as_account(  | 
            ||
| 212 | pos_stats, period_stats)  | 
            ||
| 213 | return self._account  | 
            ||
| 214 | |||
| 215 | def to_dict(self, emission_type=None):  | 
            ||
| 216 | """  | 
            ||
| 217 | Wrapper for serialization compatibility.  | 
            ||
| 218 | """  | 
            ||
| 219 | pos_stats = self.position_tracker.stats()  | 
            ||
| 220 | cumulative_stats = self.cumulative_performance.stats(  | 
            ||
| 221 | self.position_tracker.positions, pos_stats, self._data_portal)  | 
            ||
| 222 | todays_stats = self.todays_performance.stats(  | 
            ||
| 223 | self.position_tracker.positions, pos_stats, self._data_portal)  | 
            ||
| 224 | |||
| 225 | return self._to_dict(pos_stats,  | 
            ||
| 226 | cumulative_stats,  | 
            ||
| 227 | todays_stats,  | 
            ||
| 228 | emission_type)  | 
            ||
| 229 | |||
| 230 | def _to_dict(self, pos_stats, cumulative_stats, todays_stats,  | 
            ||
| 231 | emission_type=None):  | 
            ||
| 232 | """  | 
            ||
| 233 | Creates a dictionary representing the state of this tracker.  | 
            ||
| 234 | Returns a dict object of the form described in header comments.  | 
            ||
| 235 | |||
| 236 | Use this method internally, when stats are available.  | 
            ||
| 237 | """  | 
            ||
| 238 | # Default to the emission rate of this tracker if no type is provided  | 
            ||
| 239 | if emission_type is None:  | 
            ||
| 240 | emission_type = self.emission_rate  | 
            ||
| 241 | |||
| 242 | position_tracker = self.position_tracker  | 
            ||
| 243 | |||
| 244 |         _dict = { | 
            ||
| 245 | 'period_start': self.period_start,  | 
            ||
| 246 | 'period_end': self.period_end,  | 
            ||
| 247 | 'capital_base': self.capital_base,  | 
            ||
| 248 | 'cumulative_perf': self.cumulative_performance.to_dict(  | 
            ||
| 249 | pos_stats, cumulative_stats, position_tracker,  | 
            ||
| 250 | ),  | 
            ||
| 251 | 'progress': self.progress,  | 
            ||
| 252 | 'cumulative_risk_metrics': self.cumulative_risk_metrics.to_dict()  | 
            ||
| 253 | }  | 
            ||
| 254 | if emission_type == 'daily':  | 
            ||
| 255 | _dict['daily_perf'] = self.todays_performance.to_dict(  | 
            ||
| 256 | pos_stats,  | 
            ||
| 257 | todays_stats,  | 
            ||
| 258 | position_tracker)  | 
            ||
| 259 | elif emission_type == 'minute':  | 
            ||
| 260 | _dict['minute_perf'] = self.todays_performance.to_dict(  | 
            ||
| 261 | pos_stats,  | 
            ||
| 262 | todays_stats,  | 
            ||
| 263 | position_tracker,  | 
            ||
| 264 | self.saved_dt)  | 
            ||
| 265 | else:  | 
            ||
| 266 |             raise ValueError("Invalid emission type: %s" % emission_type) | 
            ||
| 267 | |||
| 268 | return _dict  | 
            ||
| 269 | |||
| 270 | def copy_state_from(self, other_perf_tracker):  | 
            ||
| 271 | self.all_benchmark_returns = other_perf_tracker.all_benchmark_returns  | 
            ||
| 272 | |||
| 273 | if other_perf_tracker.position_tracker:  | 
            ||
| 274 | self.position_tracker._unpaid_dividends = \  | 
            ||
| 275 | other_perf_tracker.position_tracker._unpaid_dividends  | 
            ||
| 276 | |||
| 277 | self.position_tracker._unpaid_stock_dividends = \  | 
            ||
| 278 | other_perf_tracker.position_tracker._unpaid_stock_dividends  | 
            ||
| 279 | |||
| 280 | def process_transaction(self, transaction):  | 
            ||
| 281 | self.txn_count += 1  | 
            ||
| 282 | self.position_tracker.execute_transaction(transaction)  | 
            ||
| 283 | self.cumulative_performance.handle_execution(transaction)  | 
            ||
| 284 | self.todays_performance.handle_execution(transaction)  | 
            ||
| 285 | |||
| 286 | def handle_splits(self, splits):  | 
            ||
| 287 | leftover_cash = self.position_tracker.handle_splits(splits)  | 
            ||
| 288 | if leftover_cash > 0:  | 
            ||
| 289 | self.cumulative_performance.handle_cash_payment(leftover_cash)  | 
            ||
| 290 | self.todays_performance.handle_cash_payment(leftover_cash)  | 
            ||
| 291 | |||
| 292 | def process_order(self, event):  | 
            ||
| 293 | self.cumulative_performance.record_order(event)  | 
            ||
| 294 | self.todays_performance.record_order(event)  | 
            ||
| 295 | |||
| 296 | def process_commission(self, commission):  | 
            ||
| 297 | sid = commission["sid"]  | 
            ||
| 298 | cost = commission["cost"]  | 
            ||
| 299 | |||
| 300 | self.position_tracker.handle_commission(sid, cost)  | 
            ||
| 301 | self.cumulative_performance.handle_commission(cost)  | 
            ||
| 302 | self.todays_performance.handle_commission(cost)  | 
            ||
| 303 | |||
| 304 | def process_close_position(self, event):  | 
            ||
| 305 | txn = self.position_tracker.\  | 
            ||
| 306 | maybe_create_close_position_transaction(event)  | 
            ||
| 307 | if txn:  | 
            ||
| 308 | self.process_transaction(txn)  | 
            ||
| 309 | |||
| 310 | def check_upcoming_dividends(self, next_trading_day):  | 
            ||
| 311 | """  | 
            ||
| 312 | Check if we currently own any stocks with dividends whose ex_date is  | 
            ||
| 313 | the next trading day. Track how much we should be payed on those  | 
            ||
| 314 | dividends' pay dates.  | 
            ||
| 315 | |||
| 316 | Then check if we are owed cash/stock for any dividends whose pay date  | 
            ||
| 317 | is the next trading day. Apply all such benefits, then recalculate  | 
            ||
| 318 | performance.  | 
            ||
| 319 | """  | 
            ||
| 320 | if self._adjustment_reader is None:  | 
            ||
| 321 | return  | 
            ||
| 322 | position_tracker = self.position_tracker  | 
            ||
| 323 | held_sids = set(position_tracker.positions)  | 
            ||
| 324 | # Dividends whose ex_date is the next trading day. We need to check if  | 
            ||
| 325 | # we own any of these stocks so we know to pay them out when the pay  | 
            ||
| 326 | # date comes.  | 
            ||
| 327 | if held_sids:  | 
            ||
| 328 | dividends_earnable = self._adjustment_reader.\  | 
            ||
| 329 | get_dividends_with_ex_date(held_sids, next_trading_day)  | 
            ||
| 330 | stock_dividends = self._adjustment_reader.\  | 
            ||
| 331 | get_stock_dividends_with_ex_date(held_sids, next_trading_day)  | 
            ||
| 332 | position_tracker.earn_dividends(dividends_earnable,  | 
            ||
| 333 | stock_dividends)  | 
            ||
| 334 | |||
| 335 | net_cash_payment = position_tracker.pay_dividends(next_trading_day)  | 
            ||
| 336 | if not net_cash_payment:  | 
            ||
| 337 | return  | 
            ||
| 338 | |||
| 339 | self.cumulative_performance.handle_dividends_paid(net_cash_payment)  | 
            ||
| 340 | self.todays_performance.handle_dividends_paid(net_cash_payment)  | 
            ||
| 341 | |||
| 342 | def check_asset_auto_closes(self, next_trading_day):  | 
            ||
| 343 | """  | 
            ||
| 344 | Check if the position tracker currently owns any Assets with an  | 
            ||
| 345 | auto-close date that is the next trading day. Close those positions.  | 
            ||
| 346 | |||
| 347 | Parameters  | 
            ||
| 348 | ----------  | 
            ||
| 349 | next_trading_day : pandas.Timestamp  | 
            ||
| 350 | The next trading day of the simulation  | 
            ||
| 351 | """  | 
            ||
| 352 | auto_close_events = self.position_tracker.auto_close_position_events(  | 
            ||
| 353 | next_trading_day=next_trading_day  | 
            ||
| 354 | )  | 
            ||
| 355 | for event in auto_close_events:  | 
            ||
| 356 | self.process_close_position(event)  | 
            ||
| 357 | |||
| 358 | def handle_minute_close(self, dt):  | 
            ||
| 359 | """  | 
            ||
| 360 | Handles the close of the given minute. This includes handling  | 
            ||
| 361 | market-close functions if the given minute is the end of the market  | 
            ||
| 362 | day.  | 
            ||
| 363 | |||
| 364 | Parameters  | 
            ||
| 365 | __________  | 
            ||
| 366 | dt : Timestamp  | 
            ||
| 367 | The minute that is ending  | 
            ||
| 368 | |||
| 369 | Returns  | 
            ||
| 370 | _______  | 
            ||
| 371 | (dict, dict/None)  | 
            ||
| 372 | A tuple of the minute perf packet and daily perf packet.  | 
            ||
| 373 | If the market day has not ended, the daily perf packet is None.  | 
            ||
| 374 | """  | 
            ||
| 375 | todays_date = normalize_date(dt)  | 
            ||
| 376 | account = self.get_account(dt)  | 
            ||
| 377 | |||
| 378 | bench_returns = self.all_benchmark_returns.loc[todays_date:dt]  | 
            ||
| 379 | # cumulative returns  | 
            ||
| 380 | bench_since_open = (1. + bench_returns).prod() - 1  | 
            ||
| 381 | |||
| 382 | self.position_tracker.sync_last_sale_prices(dt)  | 
            ||
| 383 | pos_stats = self.position_tracker.stats()  | 
            ||
| 384 | cumulative_stats = self.cumulative_performance.stats(  | 
            ||
| 385 | self.position_tracker.positions, pos_stats, self._data_portal  | 
            ||
| 386 | )  | 
            ||
| 387 | todays_stats = self.todays_performance.stats(  | 
            ||
| 388 | self.position_tracker.positions, pos_stats, self._data_portal  | 
            ||
| 389 | )  | 
            ||
| 390 | self.cumulative_risk_metrics.update(todays_date,  | 
            ||
| 391 | todays_stats.returns,  | 
            ||
| 392 | bench_since_open,  | 
            ||
| 393 | account)  | 
            ||
| 394 | |||
| 395 | minute_packet = self._to_dict(pos_stats,  | 
            ||
| 396 | cumulative_stats,  | 
            ||
| 397 | todays_stats,  | 
            ||
| 398 | emission_type='minute')  | 
            ||
| 399 | |||
| 400 | if dt == self.market_close:  | 
            ||
| 401 | # if this is the last minute of the day, we also want to  | 
            ||
| 402 | # emit a daily packet.  | 
            ||
| 403 | return minute_packet, self._handle_market_close(todays_date,  | 
            ||
| 404 | pos_stats,  | 
            ||
| 405 | todays_stats)  | 
            ||
| 406 | else:  | 
            ||
| 407 | return minute_packet, None  | 
            ||
| 408 | |||
| 409 | def handle_market_close_daily(self, dt):  | 
            ||
| 410 | """  | 
            ||
| 411 | Function called after handle_data when running with daily emission  | 
            ||
| 412 | rate.  | 
            ||
| 413 | """  | 
            ||
| 414 | completed_date = normalize_date(dt)  | 
            ||
| 415 | |||
| 416 | self.position_tracker.sync_last_sale_prices(dt)  | 
            ||
| 417 | |||
| 418 | pos_stats = self.position_tracker.stats()  | 
            ||
| 419 | todays_stats = self.todays_performance.stats(  | 
            ||
| 420 | self.position_tracker.positions, pos_stats, self._data_portal  | 
            ||
| 421 | )  | 
            ||
| 422 | account = self.get_account(completed_date)  | 
            ||
| 423 | |||
| 424 | # update risk metrics for cumulative performance  | 
            ||
| 425 | benchmark_value = self.all_benchmark_returns[completed_date]  | 
            ||
| 426 | |||
| 427 | self.cumulative_risk_metrics.update(  | 
            ||
| 428 | completed_date,  | 
            ||
| 429 | todays_stats.returns,  | 
            ||
| 430 | benchmark_value,  | 
            ||
| 431 | account)  | 
            ||
| 432 | |||
| 433 | daily_packet = self._handle_market_close(completed_date,  | 
            ||
| 434 | pos_stats,  | 
            ||
| 435 | todays_stats)  | 
            ||
| 436 | |||
| 437 | return daily_packet  | 
            ||
| 438 | |||
| 439 | def _handle_market_close(self, completed_date, pos_stats, todays_stats):  | 
            ||
| 440 | |||
| 441 | # increment the day counter before we move markers forward.  | 
            ||
| 442 | self.day_count += 1.0  | 
            ||
| 443 | |||
| 444 | # Get the next trading day and, if it is past the bounds of this  | 
            ||
| 445 | # simulation, return the daily perf packet  | 
            ||
| 446 | next_trading_day = self.env.next_trading_day(completed_date)  | 
            ||
| 447 | |||
| 448 | # Check if any assets need to be auto-closed before generating today's  | 
            ||
| 449 | # perf period  | 
            ||
| 450 | if next_trading_day:  | 
            ||
| 451 | self.check_asset_auto_closes(next_trading_day=next_trading_day)  | 
            ||
| 452 | |||
| 453 | # Take a snapshot of our current performance to return to the  | 
            ||
| 454 | # browser.  | 
            ||
| 455 | cumulative_stats = self.cumulative_performance.stats(  | 
            ||
| 456 | self.position_tracker.positions,  | 
            ||
| 457 | pos_stats, self._data_portal)  | 
            ||
| 458 | daily_update = self._to_dict(pos_stats,  | 
            ||
| 459 | cumulative_stats,  | 
            ||
| 460 | todays_stats,  | 
            ||
| 461 | emission_type='daily')  | 
            ||
| 462 | |||
| 463 | # On the last day of the test, don't create tomorrow's performance  | 
            ||
| 464 | # period. We may not be able to find the next trading day if we're at  | 
            ||
| 465 | # the end of our historical data  | 
            ||
| 466 | if self.market_close >= self.last_close:  | 
            ||
| 467 | return daily_update  | 
            ||
| 468 | |||
| 469 | # move the market day markers forward  | 
            ||
| 470 | self.market_open, self.market_close = \  | 
            ||
| 471 | self.env.next_open_and_close(self.day)  | 
            ||
| 472 | self.day = self.env.next_trading_day(self.day)  | 
            ||
| 473 | |||
| 474 | # Roll over positions to current day.  | 
            ||
| 475 | self.todays_performance.rollover(pos_stats, todays_stats)  | 
            ||
| 476 | self.todays_performance.period_open = self.market_open  | 
            ||
| 477 | self.todays_performance.period_close = self.market_close  | 
            ||
| 478 | |||
| 479 | # If the next trading day is irrelevant, then return the daily packet  | 
            ||
| 480 | if (next_trading_day is None) or (next_trading_day >= self.last_close):  | 
            ||
| 481 | return daily_update  | 
            ||
| 482 | |||
| 483 | # Check for any dividends and auto-closes, then return the daily perf  | 
            ||
| 484 | # packet  | 
            ||
| 485 | self.check_upcoming_dividends(next_trading_day=next_trading_day)  | 
            ||
| 486 | return daily_update  | 
            ||
| 487 | |||
| 488 | def handle_simulation_end(self):  | 
            ||
| 489 | """  | 
            ||
| 490 | When the simulation is complete, run the full period risk report  | 
            ||
| 491 | and send it out on the results socket.  | 
            ||
| 492 | """  | 
            ||
| 493 | |||
| 494 |         log_msg = "Simulated {n} trading days out of {m}." | 
            ||
| 495 | log.info(log_msg.format(n=int(self.day_count), m=self.total_days))  | 
            ||
| 496 |         log.info("first open: {d}".format( | 
            ||
| 497 | d=self.sim_params.first_open))  | 
            ||
| 498 |         log.info("last close: {d}".format( | 
            ||
| 499 | d=self.sim_params.last_close))  | 
            ||
| 500 | |||
| 501 | bms = pd.Series(  | 
            ||
| 502 | index=self.cumulative_risk_metrics.cont_index,  | 
            ||
| 503 | data=self.cumulative_risk_metrics.benchmark_returns_cont)  | 
            ||
| 504 | ars = pd.Series(  | 
            ||
| 505 | index=self.cumulative_risk_metrics.cont_index,  | 
            ||
| 506 | data=self.cumulative_risk_metrics.algorithm_returns_cont)  | 
            ||
| 507 | acl = self.cumulative_risk_metrics.algorithm_cumulative_leverages  | 
            ||
| 508 | self.risk_report = risk.RiskReport(  | 
            ||
| 509 | ars,  | 
            ||
| 510 | self.sim_params,  | 
            ||
| 511 | benchmark_returns=bms,  | 
            ||
| 512 | algorithm_leverages=acl,  | 
            ||
| 513 | env=self.env)  | 
            ||
| 514 | |||
| 515 | risk_dict = self.risk_report.to_dict()  | 
            ||
| 516 | return risk_dict  | 
            ||
| 517 | |||
| 518 | def __getstate__(self):  | 
            ||
| 519 | state_dict = \  | 
            ||
| 520 |             {k: v for k, v in iteritems(self.__dict__) | 
            ||
| 521 |                 if not k.startswith('_')} | 
            ||
| 522 | |||
| 523 | STATE_VERSION = 4  | 
            ||
| 524 | state_dict[VERSION_LABEL] = STATE_VERSION  | 
            ||
| 525 | |||
| 526 | return state_dict  | 
            ||
| 527 | |||
| 528 | def __setstate__(self, state):  | 
            ||
| 529 | |||
| 530 | OLDEST_SUPPORTED_STATE = 4  | 
            ||
| 531 | version = state.pop(VERSION_LABEL)  | 
            ||
| 532 | |||
| 533 | if version < OLDEST_SUPPORTED_STATE:  | 
            ||
| 534 |             raise BaseException("PerformanceTracker saved state is too old.") | 
            ||
| 535 | |||
| 536 | self.__dict__.update(state)  | 
            ||
| 537 |