Portfolio Analysis

by Samuel Ching, Maxwell Margenot, Gus Gordon, and Delaney Mackenzie

Part of the Quantopian Lecture Series:

Notebook released under the Creative Commons Attribution 4.0 License. Please do not remove this attribution.


In professional quant workflows, it is critical to demonstrate the efficacy of any portfolio through rigorous testing. This is fundamental to understanding the risk profile as well as the performance of the portfolio. As such, quants and developers often have to build in-house tools to measure these metrics. To this end, we have created a package called pyfolio. pyfolio is a Python library for performance and risk analysis of financial portfolios, available on github here. It allows us to easily generate tear sheets to analyze the risk and performance of trading algorithms as well as return streams in general.

Issues with Backtesting

It is often tempting to run many backtests while building an algorithm. A common pitfall is to use the success of backtests as a feedback metric to fine-tune an algorithm's parameters or features while still in the construction phase. This leads to the overfitting of the strategy to whichever time periods the user ran the backtests on. Ultimately, this results in poor performance when deployed out of sample in live trading.

As such, running backtests and generating tearsheets should only occur at the tail end of the algorithm creation lifecycle. We then get a picture of the algorithm's performance, aiding the user in deciding whether to move forward with the deployment of the algorithm or to switch to another strategy.

There are two main parts to a full pyfolio tearsheet. First, there are the performance statistics in table format. Useful metrics such as the annual return, market beta, and Sharpe ratio are all listed in this table. These metrics not only represent how well the strategy has performed during the time period of the backtest (annual rate of return), they also show the risk-adjusted return as measured by the different ratios. We will go into more detail about the meaning of these metrics.

Next, there are plots which help to visualize a variety of the performance metrics. For instance, the user can use the drawdown plots to quickly pinpoint the time periods in which the strategy performed the worst. In addition, it will help the user to see if the strategy is performing as it should - if a strategy is market neutral, but suffers significant drawdowns during crisis periods, then there are clearly issues with the strategy's design or implementation.

Setup - Getting a Backtest into the Research Environment

First, we import a backtest into the research envrionment. In this lecture, we will use the backtest from this forum post.


In [1]:
import pyfolio as pf
import matplotlib.pyplot as plt
import empyrical

In [2]:
# Get benchmark returns
benchmark_rets = pf.utils.get_symbol_rets('SPY')

In [3]:
# Get the backtest
bt = get_backtest('58812b2977ca4c474bbf393f')


100% Time: 0:00:07|###########################################################|

Now, we want to understand the returns, positions and transactions of the trading algorithm over our backtest's time period. We can get these data points from backtest object attributes.


In [4]:
bt_returns = bt.daily_performance['returns']
bt_positions = bt.pyfolio_positions
bt_transactions = bt.pyfolio_transactions

Now, we are ready to use pyfolio to dive into the different performance metrics and plots of our algorithm. Throughout the course of this lecture we will detail how to interpret the various individual plots generated by an pyfolio tear sheet and include the proper call to generate the whole tear sheet at once at the end. This function is built into our backtest object, removing the need to write out all the code in the long form presented here.

Performance Statistics

With pyfolio, there is a wealth of performance statistics which most professional fund managers would use to analyze the performance of the algorithm. These metrics range from the algorithm's annual and monthly returns, return quantiles, rolling beta and sharpe ratios to the turnover of the portfolio. The most critical metrics are discussed as follows.

Risk-Adjusted Return

The risk-adjusted return is an essential metric of any strategy. Risk-adjusted returns allow us to judge returns streams that have different individual volatilities by providing an avenue for meaningful comparison. There are different measures of risk-adjusted returns but one of the most popular is the Sharpe ratio. In this particular backtest, the annual return of $2\%$ for $1\%$ volatility is an example of a relatively low absolute return, but a relatively high risk-adjusted return. Then, with a low risk strategy, leverage can then be applied to increase the absolute return.


In [5]:
print "The Sharpe Ratio of the backtest is: ", empyrical.sharpe_ratio(bt_returns)


The Sharpe Ratio of the backtest is:  1.29850718492

Market Beta

The market beta of an algorithm is the exposure of that stategy to the broader market. For instance, a market beta of $1$ would mean that you're buying the the market, while a beta of $-1$ means that you are shorting the market. Any beta within this range signifies reduced market influence, while any beta outside this range signifies increased market influence.


In [6]:
print "The market beta of the backtest is: ", empyrical.beta(bt_returns,benchmark_rets)


The market beta of the backtest is:  -0.00165873783566

In the case of this strategy, the beta is 0. This means that this strategy has no exposure to the broader market, it is market neutral. To institutional investors, market neutral strategies are very attractive. After all, if the investors want a strategy which is highly exposed to the market, they could simply buy an ETF or an index fund.

Drawdowns

A drawdown is the 'peak to trough decline' of an investment strategy. Intuitively speaking, it refers to the losses the strategy has experienced from the base amount of capital which it had at the peak. For instance, in the 2008 Financial Crisis, the market drawdown was over 50% from the peak in 2007 to the trough in 2009.


In [7]:
print "The maxmimum drawdown of the backtest is: ", empyrical.max_drawdown(bt_returns)


The maxmimum drawdown of the backtest is:  -0.0113644622693

This is another measure of the financial risk of an algorithm. If the net drawdown of a strategy is very significant, this generally means that the volatility of the algorithm is more significant. Good strategies try to limit drawdowns. A good benchmark is to have a maximum drawdown of less than 20%.

Plotting

In pyfolio, there is a plotting module which allows users to quickly plot these metrics. These plots can be individually plotted using the following functions:

  • plot_annual_returns
  • plot_daily_returns_similarity
  • plot_daily_volume
  • plot_drawdown_periods
  • plot_drawdown_underwater
  • plot_exposures
  • plot_gross_leverage
  • plot_holdings
  • plot_long_short_holdings
  • plot_monthly_returns_dist
  • plot_monthly_returns_heatmap
  • plot_multistrike_cones
  • plot_prob_profit_trade
  • plot_return_quantiles
  • plot_rolling_beta
  • plot_rolling_returns
  • plot_rolling_sharpe
  • plot_turnover
  • plot_txn_time_hist
  • show_and_plot_top_positions

Returns Plots

Plots of cumulative returns and daily, non-cumulative returns allow you to gain a quick overview of the algorithm's performance and pick out any anomalies across the time period of the backtest. The cumulative return plot also allows you to make a comparison against benchmark returns - this could be against another investment strategy or an index like the S&P 500.


In [8]:
# Cumulative Returns
plt.subplot(2,1,1)
pf.plotting.plot_rolling_returns(bt_returns, benchmark_rets)

# Daily, Non-Cumulative Returns
plt.subplot(2,1,2)
pf.plotting.plot_returns(bt_returns)
plt.tight_layout()


With the annual and monthly return plots, you can see which years and months the algorithm performed the best in. For instance, in the monthly heatmap plot, this algorithm performed the best in June 2014 (shaded in dark green). In a backtest with a longer period of time, these plots will reveal more information. Furthermore, the distribution of the monthly returns is also instructive in gauging how the algorithm performs in different periods throughout the year and if it is affected by seasonal patterns.


In [9]:
fig = plt.figure(1)
plt.subplot(1,3,1)
pf.plot_annual_returns(bt_returns)
plt.subplot(1,3,2)
pf.plot_monthly_returns_dist(bt_returns)
plt.subplot(1,3,3)
pf.plot_monthly_returns_heatmap(bt_returns)
plt.tight_layout()
fig.set_size_inches(15,5)


Return Quantiles

These box and whisker plots provide an overview of the return quantiles broken down by the return timeframe (daily / weekly / monthly) across the entire backtest time period.


In [10]:
pf.plot_return_quantiles(bt_returns);


The center line in the middle of each box shows the median return, and the box shows the first quartile (25th percentile) as well as the 3rd quartile (75th percentile). While a high median return is always helpful, it is also important to understand the returns distribution. A tight box means that the bulk of the returns (25th - 75th percentile) fall within a tight bound - i.e. the returns are consistent and not volatile. A larger box means that the returns are more spread out. It is important, however, to take note of the scale to the left to put the quartiles in perspective. In addition, returns over longer periods of time will have a wider distribution as increasing the length of time increases the variability in returns.

The 'whiskers' at the end indicate the returns which fall outside the 25th and 75th percentile. A tight box with long whiskers indicate that there may be outliers in the returns - which may not be ideal if the outliers are negative. This may indicate that your strategy may be susceptible to certain market conditions / time periods.

Rolling Plots

Below, we have several rolling plots which show how an estimate changes throughout backtest period. In the case of the rolling beta and the rolling Sharpe ratio, the rolling estimate gives us more information than single point estimate for the entire period. A rolling estimate allows the user to see if the risk-adjusted return of the algorithm (Sharpe ratio) is consistent over time or if it fluctuates significantly. A volatile Sharpe ratio may indicate that the strategy may be riskier at certain time points or that it does not perform as well at these time points. Likewise, a volatile rolling beta indicates that it is exposed to the market during certain time points - if the strategy is meant to be market neutral, this could be a red flag.

Rolling Beta Plot

The plot below shows the rolling beta of the strategy against benchmark returns over the entire period of the backtest. In this instance, the benchmark return of the SPY was used. Thus, the lower the rolling portfolio beta to the SPY, the more market neutral an algorithm is.


In [11]:
pf.plot_rolling_beta(bt_returns, benchmark_rets);


Rolling Sharpe Ratio Plot

The plot below shows the rolling Sharpe ratio over the period of the backtest. This allows you to understand the performance of the algorithm at different time points.


In [12]:
pf.plot_rolling_sharpe(bt_returns);


In the case of this strategy, the Sharpe ratio is above 2 for the first 4 months before dropping toward the end of the year. It would be helpful here to check if this algorithm is exposed to other risk factors. This may help to explain the end of year slump. In addition, it would be helpful to understand the market situation at that point in time to see if the strategy was in some way affected by market events.

Rolling Fama-French Single Factor Betas Plot

In this plot, we see how exposed the strategy is to the 3 classical Fama-French factors. A factor model can be used to analyze the sources of risks and returns in a strategy or of any return stream. By looking at a strategy's historical returns, we can determine how much of these returns can be attributed to speculation on different factors and how much is a result of asset-specific fluctuations. This allows you to find out the sources of risk the portfolio is exposed to. For more information about Factor Models, check out the Factor Risk Exposure lecture.


In [13]:
pf.plot_rolling_fama_french(bt_returns);


These classical risk factors measure for small market cap, high-growth, and momentum stocks. The SMB curve represents small-cap stocks minus big-cap stocks, HML curve represents high-growth minus low-growth stocks, and the UMD curve checks exposure to any momentum strategy (i.e. stocks which are trending up perform better than stocks which are trending down). The idea behind these risk factors is that even though they may provide higher returns, they are able to do so because they are riskier. Therefore, low measures of these in your strategy may indicate that your strategy is less risky.

Similar to the beta exposure to the market, a high exposure to a fama french factor ( $\geq 1$) means that you are simply buying these known risk factors. If an algorithm's return is made up of known risk factors, such as the Fama-French ones, then the strategy is not as valuable in generating alpha.

Drawdown Plots

In this plot, we visualize the drawdown chart described above. This chart provides an overview of the worst drawdown periods in the backtest. These periods show the time windows in the backtest in which the top 5 drawdowns occurred.


In [14]:
pf.plot_drawdown_periods(bt_returns);


This, coupled with the underwater plot, allows for a quick check into the time periods during which the algorithm struggles. Generally speaking, the less volatile an algorithm is, the more minimal the drawdowns.


In [15]:
pf.plot_drawdown_underwater(bt_returns);


Gross Leverage

Gross leverage is the sum of long and short leverage exposure per share divided by net asset value. This plot allows you to see the amount of leverage being applied to the portfolio over the backtest period.


In [16]:
pf.plot_gross_leverage(bt_returns, bt_positions);


Monitoring the leverage of a strategy is important as it affects how you trade on margin. Unlike discretionary strategies where you could actively increase or decrease the leverage used in going long or short, algorithmic strategies automatically apply leverage during trading. Therefore, it is useful to monitor the gross leverage plot to ensure that the amount of leverage that your strategy uses is within the limits that you are comfortable with.

Good strategies generally start with an initial leverage of 1. Upon finding out the viability of the strategy by examining the Sharpe ratio and other metrics, leverage can be increased or decreased accordingly. A lower Sharpe ratio indicates that the strategy has a higher volatility per unit return, making it more risky to lever up. On the other hand, a higher Sharpe ratio indicates lower volatility per unit return, allowing you to increase the leverage and correspondingly, returns.

For more details, take a look at the lecture on leverage.

Positions Plots

Top Long and Short Positions

The tables below list the top 10 long and short positions of all time. The goal of each algorithm is to minimize the proportion of the portfolio invested in each security at any time point. This prevents the movement of any individual security from having a significant impact on the portfolio as a whole. The bigger the exposure a strategy has to any security, the greater the risk.

Generally, the biggest failure point for many strategies is high portfolio concentration in a few securities. While this may produce significant positive returns over a given time period, the converse can easily occur. Huge swings in a small number of equities would result in significant drawdowns. Good strategies tend to be those in which no security comprises more than 10% of the portfolio.


In [17]:
pos_percent = pf.pos.get_percent_alloc(bt_positions)
pf.plotting.show_and_plot_top_positions(bt_returns, pos_percent);


Top 10 long positions of all time max
DNR-15789 0.60%
PPG-6116 0.60%
WPX-42251 0.60%
ATI-24840 0.59%
HP-3647 0.59%
CNX-24758 0.59%
INTC-3951 0.59%
TRIP-42230 0.59%
AET-168 0.59%
CIM-35081 0.59%
Top 10 short positions of all time max
THC-5343 -0.45%
SHLD-26169 -0.45%
BBY-754 -0.45%
SPLS-7061 -0.44%
WTW-23269 -0.44%
GME-23438 -0.44%
CPB-1795 -0.44%
PFE-5923 -0.44%
T-6653 -0.44%
MAT-4668 -0.44%
Top 10 positions of all time max
DNR-15789 0.60%
PPG-6116 0.60%
WPX-42251 0.60%
ATI-24840 0.59%
HP-3647 0.59%
CNX-24758 0.59%
INTC-3951 0.59%
TRIP-42230 0.59%
AET-168 0.59%
CIM-35081 0.59%
All positions ever held max
DNR-15789 0.60%
PPG-6116 0.60%
WPX-42251 0.60%
ATI-24840 0.59%
HP-3647 0.59%
CNX-24758 0.59%
INTC-3951 0.59%
TRIP-42230 0.59%
AET-168 0.59%
CIM-35081 0.59%
IPG-3990 0.59%
BIG-22657 0.59%
HRL-3668 0.58%
MMC-4914 0.58%
MWV-23380 0.58%
GMCR-9736 0.58%
LRCX-4537 0.58%
AVB-18834 0.58%
ADT-43399 0.58%
DUK-2351 0.58%
MSFT-5061 0.58%
CTSH-18870 0.58%
HRB-3660 0.58%
NTAP-13905 0.58%
NRG-26143 0.58%
APOL-24829 0.58%
BCR-779 0.58%
LH-12909 0.58%
WIN-27019 0.58%
FLIR-9156 0.58%
... ...
MPC-41636 0.39%
PCAR-5787 0.39%
COG-1746 0.39%
DHI-2298 0.38%
WY-8326 0.38%
VRSN-18221 0.38%
SNA-6976 0.38%
VLO-7990 0.38%
CAMP-1244 0.38%
RSH-21550 0.38%
SIRI-11901 0.37%
DO-13635 0.37%
D-2071 0.37%
ESRX-2618 0.36%
LM-4488 0.36%
HSY-3695 0.36%
MUR-5126 0.36%
NOC-5387 0.36%
QCOR-20914 0.36%
NLY-17702 0.35%
PCLN-19917 0.35%
ACI-88 0.35%
UTX-7883 0.35%
BHI-858 0.35%
ECYT-40814 0.34%
FRX-3014 0.34%
TJX-7457 0.34%
JOSB-11321 0.34%
SWY-7254 0.32%
LSI-4553 0.32%

517 rows × 1 columns

Holdings Per Day

The holdings per day allows us to gain an insight into whether the total portfolio holdings fluctuate from day to day. This plot provides a good sanity check as to whether the algorithm is performing as it should, or if there were any bugs which should be fixed. For instance, we can use to holdings plot to check if the trading behavior is expected, i.e. if there are extended periods in which the number of holdings is exceptionally low or if that the algorithm is not trading.


In [18]:
pf.plot_holdings(bt_returns, bt_positions);


Transaction Plots

Daily Turnover

This plot reflects how many shares are traded as a fraction of total shares. The higher the daily turnover, the higher the transaction costs associated with the algorithm. However, this also means that the returns and risk metrics are better able to capture the underlying performance of the algorithm as the higher quantity of trades provides more samples (of returns, risk, etc.) to draw from. This would in turn give a better estimation on Out of Sample periods as well.


In [19]:
pf.plot_turnover(bt_returns, bt_transactions, bt_positions);


Likewise, the Daily Turnover Histogram gives you an overview of the distribution of the turnover of your portfolio. This shows you both the average daily turnover of your portfolio and any outlier trading days.


In [20]:
pf.plotting.plot_daily_turnover_hist(bt_transactions, bt_positions);


Similarly, another plot which allows you to gauge the number of transactions per day is the Daily Trading Volume plot. This shows the number of shares traded per day and displays the all-time daily trading average as well.


In [21]:
pf.plotting.plot_daily_volume(bt_returns, bt_transactions);


The transaction time histogram shows you when the algorithm makes its trades during each day. You can specify the size of the bin (each column's width) as well as the timezone in the function's parameters.


In [22]:
pf.plotting.plot_txn_time_hist(bt_transactions);


Round Trip Plots

When evaluating the performance of an investment strategy, it is helpful to quantify the frequency, duration, and profitability of its independent bets, or "round trip" trades. A round trip trade is when a new long or short position is opened and later completely or partially closed out.

The intent of the round trip tearsheet is to differentiate strategies that profited off of a few lucky trades from strategies that profited repeatedly off of genuine alpha. Breaking down round trip profitability by traded name and sector can also inform universe selection and identify exposure risks. For example, even if your equity curve looks robust, if only two securities in your universe of fifteen names contributed to overall profitability, you may have reason to question the logic of your strategy.

To identify round trips, pyfolio reconstructs the complete portfolio based on the transactions that you pass in. When you make a trade, pyfolio checks if shares are already present in your portfolio purchased at a certain price. If there are, we compute the Profit and Loss (P&L), returns and duration of that round trip. In calculating round trips, pyfolio also appends position-closing transactions at the last timestamp in the positions data. This closing transaction will cause the P&L from any open positions to realized as completed round trips.

Before the round trip plots, there is a table of summary statistics which provide useful information about the strategy. For instance, the Percent profitable statistic shows the percentage of all trades which are profitable. This allows us to calculate the probability of the strategy making a profitable decision. This probability is also reflected in the round trip plots. A quick check of this plot tells us if our strategy is performing better than chance. In addition, the PnL stats also break down our average net profit for each trade and allow us to see how much of a role our short side trades play versus our long side trades in contributing to our total profit. These statistics give you a quick overview of the profitability of the strategy.

Note: These plots are not included by default in the create_full_tear_sheet() function. In order to plot the round trip plots, you have pass in round_trips=True as a parameter to the function.

The easiest way to run the analysis is to call pf.create_round_trip_tear_sheet(). Passing in a sector map is optional.


In [23]:
pf.create_round_trip_tear_sheet(bt_returns, bt_positions, bt_transactions);


/usr/local/lib/python2.7/dist-packages/pyfolio/round_trips.py:211: UserWarning: Negative price detected, ignoring forround-trip.
  warnings.warn('Negative price detected, ignoring for'
Summary stats All trades Short trades Long trades
Total number of round_trips 30776.00 15939.00 14837.00
Percent profitable 0.50 0.39 0.63
Winning round_trips 15440.00 6140.00 9300.00
Losing round_trips 15336.00 9799.00 5537.00
Even round_trips 0.00 0.00 0.00
PnL stats All trades Short trades Long trades
Total profit $21301.65 $-40678.32 $61979.97
Gross profit $360298.83 $141049.77 $219249.06
Gross loss $-338997.17 $-181728.08 $-157269.09
Profit factor $1.06 $0.78 $1.39
Avg. trade net profit $0.69 $-2.55 $4.18
Avg. winning trade $23.34 $22.97 $23.58
Avg. losing trade $-22.10 $-18.55 $-28.40
Ratio Avg. Win:Avg. Loss $1.06 $1.24 $0.83
Largest winning trade $1864.24 $1864.24 $1227.73
Largest losing trade $-1959.84 $-1952.77 $-1959.84
Duration stats All trades Short trades Long trades
Avg duration 19 days 01:26:31.028073 22 days 03:14:09.988518 15 days 18:10:00.573768
Median duration 13 days 00:00:00 15 days 00:00:00 11 days 23:00:00
Return stats All trades Short trades Long trades
Avg returns all round_trips 0.00% -0.00% 0.00%
Avg returns winning 0.00% 0.00% 0.00%
Avg returns losing -0.00% -0.00% -0.00%
Median returns all round_trips 0.00% -0.00% 0.00%
Median returns winning 0.00% 0.00% 0.00%
Median returns losing -0.00% -0.00% -0.00%
Largest winning trade 0.18% 0.18% 0.12%
Largest losing trade -0.19% -0.19% -0.19%
Symbol stats A-24757 AAPL-24 ABBV-43694 ABC-22954 ABT-62 ACI-88 ACN-25555 ADBE-114 ADI-122 ADM-128 ... XLNX-8344 XOM-8347 XRAY-8352 XRX-8354 XYL-42023 YHOO-14848 YUM-17787 ZION-8399 ZLC-10069 ZNGA-42277
Avg returns all round_trips 0.00% 0.00% -0.00% 0.00% 0.00% 0.00% -0.00% 0.00% 0.00% 0.00% ... 0.00% -0.00% -0.00% -0.00% 0.00% -0.00% -0.00% 0.00% 0.00% -0.00%
Avg returns winning 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% ... 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.01% 0.00%
Avg returns losing -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% ... -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.01%
Median returns all round_trips -0.00% 0.00% 0.00% 0.00% 0.00% 0.00% -0.00% 0.00% 0.00% -0.00% ... 0.00% -0.00% -0.00% -0.00% 0.00% -0.00% -0.00% 0.00% -0.00% -0.00%
Median returns winning 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% ... 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.00% 0.01% 0.00%
Median returns losing -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% ... -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00% -0.00%
Largest winning trade 0.05% 0.01% 0.01% 0.01% 0.02% 0.04% 0.02% 0.03% 0.04% 0.02% ... 0.01% 0.02% 0.00% 0.01% 0.02% 0.03% 0.01% 0.01% 0.02% 0.05%
Largest losing trade -0.02% -0.02% -0.04% -0.01% -0.01% -0.05% -0.01% -0.01% -0.01% -0.01% ... -0.01% -0.02% -0.02% -0.02% -0.02% -0.02% -0.03% -0.02% -0.00% -0.05%

8 rows × 517 columns

Profitability (PnL / PnL total) per name pnl
CLF-1595 0.12%
UNXL-31156 0.10%
TXT-7674 0.09%
VFC-7949 0.09%
NFX-10231 0.09%
APOL-24829 0.08%
ARNC-2 0.08%
JCP-4118 0.08%
WYNN-24124 0.08%
DO-13635 0.08%
BRCM-18529 0.07%
HAL-3443 0.07%
HP-3647 0.07%
MNKD-26524 0.07%
LNKD-41451 0.06%
NUS-16059 0.06%
MU-5121 0.06%
NE-5249 0.06%
UNP-7800 0.06%
LSI-4553 0.05%
DPS-36118 0.05%
AET-168 0.05%
FTR-2069 0.05%
TDC-34661 0.05%
RRC-19249 0.05%
IGT-3840 0.05%
EXC-22114 0.05%
PSX-42788 0.05%
ETFC-15474 0.05%
TWX-357 0.05%
... ...
FRX-3014 -0.03%
VLO-7990 -0.03%
MO-4954 -0.04%
MAR-25920 -0.04%
CELG-1406 -0.04%
AN-410 -0.04%
MAT-4668 -0.04%
OKE-5634 -0.04%
BIIB-3806 -0.04%
PCLN-19917 -0.04%
CA-1209 -0.05%
FFIV-20208 -0.05%
MAS-4665 -0.05%
EA-2602 -0.05%
NFLX-23709 -0.05%
SCTY-43721 -0.05%
WEB-27762 -0.05%
SE-33030 -0.05%
ANF-15622 -0.05%
DNR-15789 -0.05%
AKAM-20680 -0.06%
ALXN-14328 -0.06%
DISC_A-36930 -0.06%
APA-448 -0.06%
APC-455 -0.09%
P-41579 -0.09%
QEP-39778 -0.10%
ZNGA-42277 -0.10%
SHLD-26169 -0.10%
MCP-39960 -0.13%

517 rows × 1 columns

<matplotlib.figure.Figure at 0x7ff9febbe350>