Notebook

Enter your backtest ID.

Note: the backtest needs to be longer than 2 years in order to receive a score.

In [1]:
bt = get_backtest('5a670456c92404443820567f')
100% Time: 0:00:44|###########################################################|
In [2]:
import empyrical as ep
import pyfolio as pf
import numpy as np
from matplotlib import pyplot as plt
In [3]:
from quantopian.pipeline import Pipeline
from quantopian.research import run_pipeline
from quantopian.pipeline.experimental import QTradableStocksUS

def get_tradable_universe(start, end):
    """
    Gets the tradable universe in a format that can be compared to the positions
    of a backtest.
    """
    pipe = Pipeline(
        columns={'qtu':QTradableStocksUS()}
    )
    df = run_pipeline(pipe, start, end)
    df = df.unstack()
    df.columns = df.columns.droplevel()
    df = df.astype(float).replace(0, np.nan)
    return df
In [4]:
def volatility_adjusted_daily_return(trailing_returns):
    """
    Normalize the last daily return in `trailing_returns` by the annualized
    volatility of `trailing_returns`.
    """
    
    todays_return = trailing_returns[-1]
    # Volatility is floored at 2%.
    volatility = max(ep.annual_volatility(trailing_returns), 0.02)
    score = (todays_return / volatility)
    
    return score
In [5]:
def compute_score(returns):
    """
    Compute the score of a backtest from its returns.
    """
    
    result = []
    
    cumulative_score = 0
    count = 0
    
    daily_scores = returns.rolling(63).apply(volatility_adjusted_daily_return)
    
    cumulative_score = np.cumsum(daily_scores[504:])
    latest_score = cumulative_score[-1]
    
    print ''
    print 'Score computed between %s and %s.' % (cumulative_score.index[0].date(), daily_scores.index[-1].date())
    
    plt.plot(cumulative_score)
    plt.title('Out-of-Sample Score Over Time')
    print 'Cumulative Score: %f' % latest_score
In [6]:
SECTORS = [
    'basic_materials', 'consumer_cyclical', 'financial_services',
    'real_estate', 'consumer_defensive', 'health_care', 'utilities',
    'communication_services', 'energy', 'industrials', 'technology'
]

STYLES = [
    'momentum', 'size', 'value', 'short_term_reversal', 'volatility'
]

POSITION_CONCENTRATION_MAX = 0.05
LEVERAGE_MIN = 0.8
LEVERAGE_MAX = 1.1
DAILY_TURNOVER_MIN = 0.05
DAILY_TURNOVER_MAX = 0.65
NET_EXPOSURE_LIMIT_MAX = 0.1
BETA_TO_SPY_99TH_MAX = 0.3
BETA_TO_SPY_100TH_MAX = 0.4
SECTOR_EXPOSURE_MAX = 0.2
STYLE_EXPOSURE_MAX = 0.4
TRADABLE_UNIVERSE_MIN = 0.9


def check_constraints(positions, transactions, returns, risk_exposures):
    
    sector_constraints = True
    style_constraints = True
    constraints_met = 0
    num_constraints = 9
    
    # Position Concentration Constraint
    print 'Checking positions concentration limit...'
    try:
        percent_allocations = pf.pos.get_percent_alloc(positions[23:])
        max_pos_concentration = pf.pos.get_top_long_short_abs(percent_allocations)[2][0]
    except IndexError:
        max_pos_concentration = -1
    if (max_pos_concentration > 0) and (max_pos_concentration <= POSITION_CONCENTRATION_MAX):
        print 'PASS: Max position concentration of %.2f%% <= %.1f%%.' % (
            max_pos_concentration*100,
            POSITION_CONCENTRATION_MAX*100
        )
        constraints_met += 1
    else:
        print 'FAIL: Max position concentration of %.2f%% > %.1f%%.' % (
            max_pos_concentration*100,
            POSITION_CONCENTRATION_MAX*100
        )
        
    # Leverage Constraint
    print ''
    print 'Checking leverage limits...'
    leverage = pf.timeseries.gross_lev(positions[23:])
    if (leverage.min() >= LEVERAGE_MIN) and (leverage.max() <= LEVERAGE_MAX):
        print 'PASS: Leverage range of %.2fx-%.2fx is between %.1fx-%.1fx.' % (
            leverage.min(),
            leverage.max(),
            LEVERAGE_MIN,
            LEVERAGE_MAX
        )
        constraints_met += 1
    else:
        print 'FAIL: Leverage range of %.2fx-%.2fx is not between %.1fx-%.1fx.' % (
            leverage.min(), 
            leverage.max(),
            LEVERAGE_MIN,
            LEVERAGE_MAX
        )
      
    # Turnover Constraint
    print ''
    print 'Checking turnover limits...'
    turnover = pf.txn.get_turnover(positions, transactions)
    # Compute mean rolling 63 trading day turnover.
    rolling_mean_turnover = turnover.rolling(63).mean()[62:]
    if (rolling_mean_turnover.min() >= DAILY_TURNOVER_MIN) \
    and (rolling_mean_turnover.max() <= DAILY_TURNOVER_MAX):
        print 'PASS: Mean turnover range of %.2f%%-%.2f%% is between %.1f%%-%.1f%%.' % (
            rolling_mean_turnover.min()*100, 
            rolling_mean_turnover.max()*100,
            DAILY_TURNOVER_MIN*100,
            DAILY_TURNOVER_MAX*100
        )
        constraints_met += 1
    else:
        print 'FAIL: Mean turnover range of %.2f%%-%.2f%% is not between %.1f%%-%.1f%%.' % (
            rolling_mean_turnover.min()*100, 
            rolling_mean_turnover.max()*100,
            DAILY_TURNOVER_MIN*100,
            DAILY_TURNOVER_MAX*100
        )
        
    # Net Exposure Constraint
    print ''
    print 'Checking net exposure limit...'
    net_exposure = pf.pos.get_long_short_pos(positions[23:])['net exposure'].abs()
    if (net_exposure.max() <= NET_EXPOSURE_LIMIT_MAX):
        print 'PASS: Net exposure (absolute value) of %.2f%% <= %.1f%%.' % (
            net_exposure.max()*100,
            NET_EXPOSURE_LIMIT_MAX*100
        )
        constraints_met += 1
    else:
        print 'FAIL: Net exposure (absolute value) of %.2f%% on %s > %.1f%%.' % (
            net_exposure.max()*100,
            net_exposure.argmax().date(),
            NET_EXPOSURE_LIMIT_MAX*100
        )
        
    # Beta Constraint
    print ''
    print 'Checking beta-to-SPY limit...'
    beta = pf.timeseries.rolling_beta(returns, pf.utils.get_symbol_rets('SPY')).abs().dropna()
    beta_99 = beta.quantile(0.99)
    beta_100 = beta.max()
    if (beta_99 > BETA_TO_SPY_99TH_MAX):
        print 'FAIL: 99th percentile absolute beta of %.2f > %.1f.' % (
        beta_99,
        BETA_TO_SPY_99TH_MAX
    )
    elif (beta_100 > BETA_TO_SPY_100TH_MAX):
        print 'FAIL: 100th percentile absolute beta of %.2f > %.1f.' % (
        beta_100,
        BETA_TO_SPY_100TH_MAX
    )
    else:
        print 'PASS: Absolute beta with max of %.2f satisfies all constraints.' % (
            beta_100,
        )
        constraints_met += 1
        
    # Risk Exposures
    rolling_mean_risk_exposures = risk_exposures.rolling(63, axis=0).mean()[62:]
    
    # Sector Exposures
    print ''
    print 'Checking sector exposure limits...'
    for sector in SECTORS:
        absolute_mean_sector_exposure = rolling_mean_risk_exposures[sector].abs()
        if (absolute_mean_sector_exposure.max() > SECTOR_EXPOSURE_MAX):
            max_sector_exposure_day = absolute_mean_sector_exposure.idxmax()
            largest_sector_exposure = rolling_mean_risk_exposures[sector].loc[max_sector_exposure_day]
            print 'FAIL: Mean %s exposure of %.3f on %s is not between +/-%.2f.' % (
                sector, 
                largest_sector_exposure, 
                max_sector_exposure_day.date(),
                SECTOR_EXPOSURE_MAX
            )
            sector_constraints = False
    if sector_constraints:
        print 'PASS: All sector exposures were between +/-%.2f.' % SECTOR_EXPOSURE_MAX
        constraints_met += 1
        
    # Style Exposures
    print ''
    print 'Checking style exposure limits...'
    for style in STYLES:
        absolute_mean_style_exposure = rolling_mean_risk_exposures[style].abs()
        if (absolute_mean_style_exposure.max() > STYLE_EXPOSURE_MAX):
            max_style_exposure_day = absolute_mean_style_exposure.idxmax()
            largest_style_exposure = rolling_mean_risk_exposures[style].loc[max_style_exposure_day]
            print 'FAIL: Mean %s exposure of %.3f on %s is not between +/-%.2f.' % (
                style, 
                largest_style_exposure, 
                max_style_exposure_day.date(),
                STYLE_EXPOSURE_MAX
            )
            style_constraints = False
    if style_constraints:
        print 'PASS: All style exposures were between +/-%.2f.' % STYLE_EXPOSURE_MAX
        constraints_met += 1
    
    # Tradable Universe
    print ''
    print 'Checking investment in tradable universe...'
    positions_wo_cash = positions.drop('cash', axis=1)
    positions_wo_cash = positions_wo_cash.abs()
    total_investment = positions_wo_cash.fillna(0).sum(axis=1)
    daily_qtu_investment = universe.multiply(positions_wo_cash).fillna(0).sum(axis=1)
    percent_in_qtu = daily_qtu_investment / total_investment
    
    min_percent_in_qtu = percent_in_qtu.min()
    
    if min_percent_in_qtu >= TRADABLE_UNIVERSE_MIN:
        print 'PASS: Investment in QTradableStocksUS is >= %.1f%% at all times.' % (
            TRADABLE_UNIVERSE_MIN*100
        )
        constraints_met += 1
    else:
        min_percent_in_qtu_date = percent_in_qtu.argmin()
        print 'FAIL: Investment in QTradableStocksUS of %.2f%% on %s is < %.1f%%.' % (
            min_percent_in_qtu*100, 
            min_percent_in_qtu_date.date(),
            TRADABLE_UNIVERSE_MIN*100
        )
        
    # Total Returns Constraint
    print ''
    print 'Checking that algorithm has positive returns...'
    cumulative_returns = ep.cum_returns_final(returns)
    if (cumulative_returns > 0):
        print 'PASS: Cumulative returns of %.2f is positive.' % (
            cumulative_returns
        )
        constraints_met += 1
    else:
        print 'FAIL: Cumulative returns of %.2f is negative.' % (
            cumulative_returns
        )
    
    print ''
    print 'Results:'
    if constraints_met == num_constraints:
        print 'All constraints met!'
    else:
        print '%d/%d tests passed.' % (constraints_met, num_constraints)
In [7]:
def evaluate_backtest(positions, transactions, returns, risk_exposures):
    if len(positions.index) > 504:
        check_constraints(positions, transactions, returns, risk_exposures)
        score = compute_score(returns[start:end])
        return score
    else:
        print 'ERROR: Backtest must be longer than 2 years to be evaluated.'

Transform some of the data.

In [8]:
positions = bt.pyfolio_positions
transactions = bt.pyfolio_transactions
returns = bt.daily_performance.returns
factor_exposures = bt.factor_exposures

start = positions.index[0]
end = positions.index[-1]
universe = get_tradable_universe(start, end)
universe.columns = universe.columns.map(lambda x: '%s-%s' % (x.symbol, x.sid))

Run this to evaluate your algorithm. Note that the new contest will require all filters to pass before a submission is eligible to participate.

In [ ]:
evaluate_backtest(positions, transactions, returns, factor_exposures)
Checking positions concentration limit...
FAIL: Max position concentration of 6.11% > 5.0%.

Checking leverage limits...
PASS: Leverage range of 0.95x-1.04x is between 0.8x-1.1x.

Checking turnover limits...
PASS: Mean turnover range of 26.11%-35.49% is between 5.0%-65.0%.

Checking net exposure limit...
PASS: Net exposure (absolute value) of 7.09% <= 10.0%.

Checking beta-to-SPY limit...
PASS: Absolute beta with max of 0.18 satisfies all constraints.

Checking sector exposure limits...
PASS: All sector exposures were between +/-0.20.

Checking style exposure limits...
PASS: All style exposures were between +/-0.40.

Checking investment in tradable universe...
PASS: Investment in QTradableStocksUS is >= 90.0% at all times.

Checking that algorithm has positive returns...
PASS: Cumulative returns of 0.18 is positive.

Results:
8/9 tests passed.

Score computed between 2018-01-18 and 2018-01-19.
Cumulative Score: 0.105952
In [ ]:
bt.create_full_tear_sheet()
Start date2016-01-21
End date2018-01-19
Total months24
Backtest
Annual return 8.4%
Cumulative returns 17.5%
Annual volatility 8.0%
Sharpe ratio 1.05
Calmar ratio 1.65
Stability 0.76
Max drawdown -5.1%
Omega ratio 1.21
Sortino ratio 1.81
Skew 2.15
Kurtosis 16.92
Tail ratio 1.11
Daily value at risk -1.0%
Gross leverage 1.00
Daily turnover 29.3%
Alpha 0.08
Beta -0.00
Worst drawdown periods Net drawdown in % Peak date Valley date Recovery date Duration
0 5.08 2017-01-10 2017-04-19 2017-06-28 122
1 4.11 2017-06-28 2017-09-28 2017-12-01 113
2 3.53 2016-01-27 2016-02-08 2016-02-29 24
3 2.69 2016-11-02 2016-12-08 2016-12-29 42
4 2.02 2018-01-05 2018-01-17 NaT NaN
Stress Events mean min max
New Normal 0.03% -1.18% 4.76%
Top 10 long positions of all time max
CBI-1287 6.11%
DEPO-18010 5.61%
LC-48220 5.39%
OKE-5634 5.38%
RICE-46240 5.37%
ENDP-21750 5.37%
TDOC-49222 5.34%
ABX-64 5.26%
PRTA-43730 5.24%
LXRX-21413 5.24%
Top 10 short positions of all time max
SGMS-22637 -5.37%
BPMC-49000 -5.32%
AXON-49107 -5.28%
ASPS-38633 -5.26%
WTW-23269 -5.26%
W-47833 -5.24%
INO-3150 -5.22%
FGEN-48088 -5.21%
QEP-39778 -5.20%
NKTR-24572 -5.19%
Top 10 positions of all time max
CBI-1287 6.11%
DEPO-18010 5.61%
LC-48220 5.39%
OKE-5634 5.38%
SGMS-22637 5.37%
RICE-46240 5.37%
ENDP-21750 5.37%
TDOC-49222 5.34%
BPMC-49000 5.32%
AXON-49107 5.28%
All positions ever held max
CBI-1287 6.11%
DEPO-18010 5.61%
LC-48220 5.39%
OKE-5634 5.38%
SGMS-22637 5.37%
RICE-46240 5.37%
ENDP-21750 5.37%
TDOC-49222 5.34%
BPMC-49000 5.32%
AXON-49107 5.28%
ASPS-38633 5.26%
ABX-64 5.26%
WTW-23269 5.26%
PRTA-43730 5.24%
LXRX-21413 5.24%
W-47833 5.24%
TWOU-46648 5.23%
INO-3150 5.22%
FGEN-48088 5.21%
MDCO-21906 5.21%
SHLD-26169 5.21%
QEP-39778 5.20%
CC-49210 5.20%
NKTR-24572 5.19%
SA-26203 5.19%
SSW-27550 5.18%
GOGO-44965 5.18%
PAH-45531 5.18%
SMCI-33609 5.17%
KNX-40606 5.17%
JOY-22996 5.17%
RGLD-6455 5.17%
BOX-48486 5.17%
INCY-10187 5.17%
SSRM-15591 5.16%
SNCR-32234 5.15%
MMYT-40028 5.15%
FPRX-45430 5.15%
STKL-7158 5.15%
JCP-4118 5.14%
ACRS-49465 5.14%
SEDG-48823 5.14%
MDCA-12800 5.14%
BKD-27830 5.13%
GSM-38638 5.13%
DO-13635 5.13%
FNSR-20866 5.13%
ACOR-28077 5.13%
SIG-9774 5.13%
ACLS-21717 5.13%
NVDQ-42595 5.13%
LITE-49288 5.13%
SWIR-21561 5.12%
FCAU-47888 5.12%
LGIH-45818 5.12%
RH-43599 5.12%
TWTR-45815 5.12%
RATE-41601 5.11%
AIMT-49323 5.11%
CCJ-14479 5.11%
MRD-47126 5.11%
PAYC-46744 5.11%
PMC-34241 5.11%
TAHO-39938 5.10%
LL-35036 5.10%
ASNA-2105 5.10%
AMPH-47193 5.10%
MU-5121 5.10%
SHEN-22166 5.09%
BDC-26479 5.09%
DERM-47845 5.09%
TRTN-50119 5.09%
TLN-49003 5.09%
FORM-25182 5.09%
TBPH-46932 5.09%
ANF-15622 5.08%
GIMO-44892 5.08%
DXCM-27173 5.08%
PGNX-17908 5.08%
GCO-3131 5.08%
SYNA-23398 5.07%
YELP-42596 5.07%
SCHN-10268 5.07%
WLH-43733 5.07%
HEES-28023 5.07%
MDXG-34049 5.06%
GPOR-28116 5.06%
SFS-47776 5.06%
OLED-14774 5.06%
CUDA-45797 5.05%
MGI-26435 5.05%
AFSI-32871 5.05%
ARIA-11880 5.04%
XPO-26287 5.04%
DLTH-49615 5.04%
ALR-15575 5.03%
CZZ-34560 5.03%
HUBS-47872 5.03%
MBLY-47430 5.02%
HUN-27030 5.01%
FSLR-32902 5.01%
INVN-42165 5.01%
TIME-46965 5.01%
HABT-48126 5.00%
HBM-40301 5.00%
WDC-8132 5.00%
MFRM-42184 5.00%
MTOR-21723 5.00%
GKOS-49178 5.00%
VSTO-48531 4.99%
UCTT-26146 4.98%
FL-8383 4.98%
UIS-7761 4.98%
GG-22226 4.97%
VRA-40287 4.97%
PBF-43713 4.97%
TERP-47334 4.97%
CPG-46206 4.92%
INOV-48629 4.89%
DPLO-47883 4.78%
DK-32042 4.78%
IAG-24491 4.77%
NSM-42611 4.75%
PANW-43202 4.70%
AXDX-15934 4.70%
NOMD-47572 4.68%
CVE-38896 4.65%
SLCA-42436 4.64%
EIGI-45735 4.63%
SUPN-42877 4.63%
PSTG-49464 4.63%
NG-25781 4.60%
QRVO-48384 4.59%
BETR-49318 4.58%
FOSL-8816 4.52%
AR-45618 4.51%
HSC-3686 4.51%
PCRX-40815 4.50%
NBR-5214 4.48%
KATE-4479 4.48%
ABCO-23176 4.44%
MEOH-4795 4.37%
HLX-17180 4.36%
MBI-4684 4.32%
GLOG-42746 4.30%
AMC-46027 4.29%
MDVN-28160 4.29%
FRGI-42856 4.20%
ECHO-38798 4.18%
AMAG-659 4.14%
QLYS-43454 4.13%
MKTO-44738 4.13%
CACC-1216 4.11%
AOBC-24519 4.11%
XPER-25705 4.10%
ADRO-48925 4.09%
LCI-23602 4.07%
FINL-2845 4.07%
GIII-3210 4.07%
MRO-5035 4.06%
KSS-4313 4.06%
APTI-50318 3.99%
AGI-44156 3.96%
FSM-41915 3.95%
GEO-11710 3.95%
TXMD-28966 3.94%
LPLA-40445 3.88%
ELLI-41243 3.88%
GRUB-46693 3.87%
WETF-31288 3.87%
AEM-154 3.82%
CZR-42461 3.78%
SRPT-16999 3.77%
GNC-41182 3.73%
YNDX-41484 3.72%
REV-14420 3.70%
CRAY-21374 3.67%
BGC-3129 3.63%
AA-50428 3.56%
RAD-6330 3.56%
EVHC-45269 3.55%
SYNH-48027 3.55%
WAIR-41757 3.53%
EVH-49100 3.50%
CPE-12011 3.48%
PRTK-32095 3.47%
SCOR-34111 3.46%
MNTA-26381 3.44%
RCII-24827 3.43%
TPC-5824 3.43%
ELGX-23769 3.43%
HALO-26766 3.42%
BW-49208 3.42%
TSRO-43124 3.42%
CO-33188 3.41%
FIVN-46695 3.40%
KITE-47169 3.38%
VG-32143 3.38%
KRO-25764 3.37%
CVT-45249 3.36%
SNBR-19559 3.33%
NFX-10231 3.28%
TECK-31886 3.28%
LTRP_A-47578 3.28%
FMI-45499 3.26%
JUNO-48317 3.25%
WPM-27437 3.23%
CARB-41820 3.22%
INGN-46370 3.22%
SUM-48746 3.18%
RGEN-6449 3.16%
AMBA-43495 3.15%
CAM-13176 3.14%
CYH-21608 3.13%
QUOT-46497 3.11%
NAT-17553 3.10%
PETS-25867 3.09%
HDP-48257 3.08%
GPRO-47208 3.08%
ARCB-41 3.07%
SAGE-47332 3.07%
TTS-40545 3.06%
OPK-23120 3.02%
PVG-42366 3.01%
OPHT-45498 3.01%
ICPT-43505 3.00%
VRTX-8045 2.99%
NRG-26143 2.98%
AKRX-270 2.98%
KRA-39079 2.98%
GTN-23945 2.98%
DDD-12959 2.96%
ELF-50320 2.96%
XXIA-22185 2.95%
XLRN-45431 2.94%
TEX-7408 2.94%
STMP-26286 2.93%
DY-2385 2.93%
SGEN-22563 2.93%
WIX-45800 2.93%
ITGR-22015 2.92%
KOS-41416 2.90%
HRI-32887 2.90%
SHOP-49060 2.88%
P-41579 2.88%
RNG-45521 2.86%
RRC-19249 2.84%
AXL-19672 2.84%
SHLM-6851 2.84%
OSUR-22151 2.84%
PAAS-13083 2.83%
CVI-22766 2.82%
DVN-2368 2.82%
S-2938 2.81%
ECA-23021 2.80%
TEAM-49655 2.80%
MXL-39393 2.79%
CLR-33856 2.77%
BANC-23943 2.76%
ASIX-50260 2.76%
DKS-24070 2.75%
HMSY-3607 2.74%
RTRX-41663 2.73%
TPX-25802 2.73%
CTCT-34783 2.73%
ATGE-2371 2.72%
SPPI-24517 2.68%
NEM-5261 2.68%
MTCH-49608 2.67%
CSIQ-32856 2.65%
KRNT-48872 2.64%
MIME-49606 2.63%
OPB-46768 2.63%
BZH-10728 2.61%
PBY-5783 2.60%
THC-5343 2.59%
EVHC-50499 2.57%
RRGB-23904 2.56%
MTW-4656 2.56%
RFP-40576 2.54%
RYAM-47128 2.53%
XOG-50368 2.53%
TSEM-12116 2.53%
SPWR-27817 2.52%
ETSY-48934 2.52%
DB-23113 2.50%
KEM-4265 2.49%
PRAA-24440 2.48%
BCOR-24011 2.48%
ADPT-47191 2.46%
SAND-43329 2.46%
LZB-4621 2.46%
MDAS-35268 2.45%
SKX-20284 2.41%
DDS-2126 2.40%
OFG-16394 2.40%
APA-448 2.40%
RUN-49321 2.39%
PTLA-44770 2.38%
AAXN-22846 2.36%
CHUY-43215 2.33%
FDC-49496 2.31%
WNR-27997 2.31%
RRD-2248 2.31%
MGNX-45643 2.29%
ACAD-26322 2.29%
ESND-7866 2.28%
IMPV-42131 2.24%
FCX-13197 2.23%
OSIS-17718 2.22%
INSY-44665 2.21%
NAV-5199 2.20%
M-2754 2.20%
SCMP-34477 2.20%
ALJ-27500 2.18%
IMKT_A-3890 2.15%
CXW-22102 2.14%
RES-6426 2.13%
TLRD-7203 2.12%
CAR-17991 2.10%
CALM-16169 2.09%
SWC-12362 2.07%
ARCO-41242 2.06%
EGRX-46354 2.06%
ATI-24840 2.05%
DDC-39 2.05%
OCLR-21366 2.05%
ANDE-14329 2.05%
RIG-9038 2.05%
TIVO-16661 2.04%
DECK-9909 2.03%
TMH-39076 2.02%
CSTM-44780 2.02%
SYNT-24790 2.01%
CRZO-17358 2.01%
AAN-523 2.00%
CRUS-1882 2.00%
APOL-24829 1.99%
LDRH-45619 1.98%
NSH-32386 1.98%
ESV-2621 1.97%
CSTE-42704 1.97%
TRN-7583 1.97%
ALKS-301 1.96%
CPLA-32860 1.96%
GDOT-39932 1.93%
EXPR-39626 1.93%
MAG-34175 1.93%
ALRM-49192 1.92%
KS-30759 1.92%
MNK-44917 1.89%
AGX-28450 1.89%
IPXL-37849 1.88%
SSYS-12107 1.86%
LSCC-4549 1.85%
SPKE-47372 1.84%
ZUMZ-27229 1.84%
PEN-49413 1.84%
NFLX-23709 1.84%
TCX-3929 1.84%
SFG-20019 1.84%
CSC-1898 1.81%
OMF-45670 1.81%
COUP-50350 1.81%
NLS-23710 1.80%
DNOW-46949 1.80%
FWON_K-47272 1.79%
BB-19831 1.79%
ZOES-46742 1.79%
LILA_K-49206 1.78%
HNI-26259 1.78%
CPA-27908 1.77%
SHAK-48543 1.77%
NUS-16059 1.76%
FIT-49139 1.76%
SXC-41733 1.76%
NRF-26740 1.74%
RDC-6392 1.74%
MTSI-42646 1.74%
EXTR-19973 1.73%
WYNN-24124 1.73%
TXTR-44879 1.71%
KORS-42270 1.70%
ECPG-25320 1.70%
AFFX-15064 1.70%
CYTK-26232 1.69%
NYLD-49043 1.69%
FCPT-49543 1.68%
IRBT-27780 1.68%
EVBG-50264 1.68%
DWA-26750 1.67%
EFII-2460 1.67%
VRTS-37869 1.67%
BCC-44089 1.65%
VA-48091 1.65%
AVXS-49751 1.65%
URBN-10303 1.64%
LNG-22096 1.64%
NVGS-45915 1.63%
TBI-15165 1.62%
OLN-5643 1.61%
SPXC-7086 1.61%
MGPI-24094 1.60%
EBIX-18693 1.60%
CTRL-45212 1.60%
GBX-11645 1.60%
PDCE-5907 1.58%
NXTM-27733 1.57%
TNET-46633 1.56%
RMBS-16945 1.56%
NR-5413 1.55%
SPLK-42815 1.54%
ENLC-25850 1.54%
TWI-9066 1.54%
NBIX-14972 1.54%
LB-4564 1.54%
RAX-36714 1.54%
STX-24518 1.53%
PTEN-10254 1.53%
PODD-33858 1.52%
HSKA-17227 1.51%
BOFI-27108 1.51%
CBPO-35846 1.50%
SOHU-21813 1.49%
ARNC-2 1.48%
FEYE-45451 1.47%
CROX-28078 1.46%
SVU-7233 1.46%
AY-47123 1.46%
ILMN-21774 1.46%
IGT-48892 1.45%
IPHI-40399 1.45%
TRGP-40547 1.45%
AGEN-21104 1.44%
INFN-33979 1.43%
TK-13289 1.43%
FTR-2069 1.42%
KND-23221 1.41%
DRII-45112 1.41%
INSM-21778 1.41%
CORE-27864 1.41%
FET-42784 1.41%
ATHN-34692 1.40%
CHRS-48026 1.40%
RPD-49275 1.40%
LNKD-41451 1.39%
ERF-22215 1.39%
VNDA-28326 1.38%
SQ-49610 1.38%
NTRI-21697 1.36%
SRCI-35051 1.35%
FLOW-49434 1.35%
GRPN-42118 1.35%
TREE-36742 1.34%
AMKR-18655 1.34%
OME-18601 1.34%
DYN-43462 1.33%
CASH-9700 1.33%
CXO-34440 1.32%
MHLD-36164 1.32%
MDR-4752 1.31%
EXEL-21383 1.31%
ACIA-33321 1.31%
RIC-16681 1.31%
NVRO-48025 1.30%
ZBRA-8388 1.30%
TMST-47162 1.30%
ACET-84 1.29%
GLNG-24489 1.29%
CORT-26191 1.28%
BPT-1068 1.27%
AERI-45733 1.27%
KN-46369 1.26%
UVE-31185 1.26%
HSNI-36733 1.26%
SKYW-6925 1.25%
SWN-7244 1.25%
IBP-46365 1.25%
USCR-40241 1.23%
VECO-12267 1.23%
RARE-46285 1.22%
MOH-25349 1.22%
MACK-42735 1.21%
QLGC-10829 1.21%
CMRE-40354 1.21%
HA-3431 1.20%
ATRO-617 1.20%
CF-27558 1.20%
AMN-23178 1.20%
MATX-289 1.20%
PRTY-48933 1.19%
MYGN-13698 1.19%
LPI-42263 1.19%
XON-45239 1.18%
WGO-8168 1.18%
DBD-2100 1.17%
NVAX-14112 1.17%
TWLO-50077 1.17%
EXAM-40320 1.16%
PCTY-46569 1.16%
TGI-15905 1.16%
IONS-4031 1.15%
SSNI-44270 1.15%
DGI-38374 1.15%
IVC-4084 1.14%
AMWD-405 1.14%
PHH-26956 1.14%
BNFT-45428 1.14%
NE-5249 1.13%
FTK-27496 1.13%
HZO-18917 1.13%
FRAC-50612 1.13%
LMAT-32750 1.11%
BKE-915 1.11%
PGTI-32324 1.11%
ONCE-48547 1.10%
BRCD-20061 1.10%
ANIP-25565 1.10%
AHT-25398 1.10%
CHS-8612 1.10%
BEAT-35929 1.09%
ENV-39958 1.08%
SAVE-41498 1.08%
RDUS-46871 1.08%
ESIO-2612 1.06%
UNFI-16129 1.05%
OAS-39797 1.05%
MRC-42786 1.05%
FRO-22983 1.04%
CYBR-47779 1.04%
KTWO-46870 1.04%
TTMI-22072 1.03%
RSPP-46182 1.03%
BLDR-27369 1.02%
GPRE-28159 1.02%
SPN-14141 1.01%
GTLS-32433 1.01%
ITG-25095 1.01%
GES-24811 1.01%
HMHC-45861 1.00%
AROC-34575 0.99%
HL-3585 0.99%
EXTN-49560 0.98%
CHGG-45847 0.97%
WIFI-41374 0.97%
MAT-4668 0.97%
GLOB-47330 0.96%
EVRI-27639 0.96%
EBS-32878 0.96%
NMBL-46002 0.95%
IQNT-34997 0.94%
WIN-27019 0.94%
ICON-6856 0.94%
ALNY-26335 0.94%
ZAGG-32502 0.93%
ATRC-27532 0.93%
MB-49156 0.92%
FN-39824 0.92%
IDTI-3808 0.92%
MEDP-50194 0.91%
FRAN-41737 0.90%
NVDA-19725 0.90%
CDE-1374 0.90%
MYL-5166 0.89%
SINA-21448 0.89%
QUAD-39860 0.89%
FARO-17508 0.89%
UAA-27822 0.89%
KTOS-20947 0.88%
BID-869 0.87%
NPTN-40807 0.86%
CBB-24891 0.86%
FBP-2806 0.86%
PE-46989 0.85%
ALXN-14328 0.85%
CSII-32325 0.84%
STRA-15397 0.84%
CERS-16333 0.83%
SC-46215 0.82%
BRKS-12512 0.82%
USNA-15408 0.82%
VRTU-34483 0.82%
MYCC-45453 0.82%
HRTX-22651 0.81%
LKSD-50312 0.81%
MTDR-42446 0.81%
AFAM-21103 0.81%
VDSI-21457 0.80%
ACHC-42091 0.80%
THS-27406 0.79%
NXPI-39994 0.79%
APC-455 0.78%
FLWS-20490 0.78%
SAAS-31137 0.77%
CRS-1874 0.77%
WFT-19336 0.76%
MUR-5126 0.75%
WWE-20818 0.75%
MCRB-49195 0.74%
CMC-1636 0.73%
LOCK-43467 0.73%
TSE-47098 0.72%
NEWR-48253 0.72%
IOC-26617 0.72%
IIIN-3849 0.71%
EZPW-2671 0.71%
COWN-32377 0.71%
CAMP-1244 0.71%
HTZ-50070 0.70%
TRUE-46929 0.70%
BKS-9693 0.70%
MITL-39526 0.69%
AMBC-44636 0.69%
WRD-50537 0.69%
COHR-1751 0.69%
RUBI-46671 0.68%
BL-50418 0.68%
DSW-27409 0.68%
ZEN-46918 0.68%
BLOX-42821 0.66%
MLNT-42455 0.66%
BBBY-739 0.66%
SEMG-39358 0.66%
Z-49315 0.64%
SCLN-6714 0.64%
AG-40607 0.64%
ICHR-50509 0.63%
ANGI-42175 0.63%
BBY-754 0.63%
MEG-4779 0.63%
MMI-45771 0.62%
LPSN-21415 0.62%
DATA-44747 0.61%
EBAY-24819 0.61%
CNQ-21735 0.61%
IIVI-3854 0.61%
ARII-27998 0.60%
SALE-45114 0.60%
CIR-20696 0.59%
ZG-41730 0.59%
URI-18113 0.58%
ERII-36518 0.58%
ISLE-19391 0.58%
SAIA-24115 0.58%
PBI-5773 0.57%
PTHN-50143 0.57%
NVMI-21427 0.56%
NBL-5213 0.56%
LE-46579 0.56%
NSR-27413 0.56%
BLUE-44935 0.55%
AAWW-28378 0.55%
PDS-5855 0.55%
AKBA-46583 0.54%
OIS-22464 0.54%
AXLL-3189 0.54%
PIR-6000 0.53%
HLF-26892 0.53%
JBSS-4112 0.53%
COHU-1749 0.53%
SGYP-32331 0.53%
ZIOP-31341 0.53%
INST-49594 0.53%
CPHD-21603 0.51%
OUTR-24791 0.51%
XENT-47373 0.51%
CYNO-27887 0.51%
HES-216 0.50%
RGR-6458 0.49%
LULU-34395 0.49%
CBL-9890 0.49%
TAL-27704 0.49%
X-8329 0.49%
ININ-13046 0.49%
KLIC-4248 0.49%
GPS-3321 0.48%
HP-3647 0.47%
SODA-40353 0.47%
ACHN-32790 0.46%
KMI-40852 0.45%
AEGN-3949 0.45%
TPL-7551 0.45%
LGF-19491 0.45%
RVNC-46315 0.45%
EGN-2470 0.45%
PAHC-46748 0.44%
AEL-25710 0.44%
BSFT-39782 0.44%
PAY-27206 0.43%
AVG-42445 0.43%
OTIC-47495 0.43%
AVAV-33194 0.42%
IRDM-35933 0.42%
CBM-1297 0.42%
NGD-27323 0.42%
TVTY-371 0.42%
AVP-660 0.42%
ZLTQ-42037 0.41%
MTRX-5105 0.41%
OMER-38827 0.41%
HAR-3455 0.41%
CUTR-26157 0.40%
TGH-34810 0.40%
QDEL-6297 0.40%
DFIN-50310 0.40%
WMB-8214 0.40%
CNX-24758 0.40%
AGIO-45143 0.39%
TREX-20028 0.39%
QTNA-50417 0.39%
LOXO-47432 0.39%
TRIP-42230 0.39%
HPQ-3735 0.39%
HAWK-44570 0.38%
RKUS-43627 0.38%
EXAS-22364 0.38%
ALDR-46869 0.38%
NNBR-11003 0.37%
IMGN-3885 0.36%
ITCI-46053 0.36%
MTZ-4667 0.36%
GHDX-27666 0.36%
COTV-50002 0.36%
LGND-12200 0.35%
MOD-4958 0.34%
ABAX-31 0.34%
INVA-26676 0.34%
REI-42894 0.33%
WPX-42251 0.33%
YRCW-8370 0.33%
NTGR-25354 0.33%
XNCR-45942 0.33%
NSIT-12471 0.33%
NCMI-33317 0.32%
JWN-5382 0.32%
DWRE-42638 0.32%
SM-4664 0.32%
RSTI-15710 0.32%
PRO-34118 0.31%
TFM-40376 0.31%
ENTA-44332 0.31%
MOS-41462 0.31%
SPNC-7064 0.31%
WOR-8306 0.30%
ROCK-10263 0.30%
GTT-44938 0.30%
MELI-34525 0.30%
TTI-7633 0.29%
ENVA-47979 0.29%
MOV-14762 0.29%
UEPS-27529 0.29%
ESL-2614 0.29%
MEI-4803 0.28%
TCMD-50169 0.28%
CPN-35531 0.28%
EROS-45867 0.27%
CLB-13508 0.27%
CALD-25643 0.27%
HFC-3620 0.27%
BMRN-20330 0.27%
PLUS-25150 0.27%
MENT-4794 0.27%
PRLB-42546 0.27%
BOJA-49024 0.27%
BUFF-49279 0.27%
AMCC-17799 0.27%
WRLD-8268 0.26%
AEO-11086 0.26%
KOP-28039 0.26%
BLDP-13798 0.26%
FLTX-43479 0.25%
ABMD-53 0.25%
IXYS-19331 0.25%
RGNX-49409 0.25%
WEB-27762 0.25%
NTNX-50338 0.25%
KGC-9189 0.24%
FNGN-39363 0.24%
LXFT-44986 0.24%
HOLI-28942 0.24%
AMD-351 0.23%
DAR-11908 0.23%
AMRI-24777 0.23%
SSTK-43494 0.22%
KBR-32880 0.22%
HZNP-41766 0.22%
PWR-6269 0.22%
OII-5629 0.21%
VSAR-46582 0.21%
ATKR-50040 0.21%
SGRY-49456 0.21%
VRTV-47143 0.21%
CATM-35253 0.21%
SHOR-34145 0.21%
BRS-5645 0.20%
AYX-50735 0.20%
EGHT-22889 0.20%
LOGM-38560 0.19%
ANET-47063 0.19%
CAL-1195 0.19%
CHK-8461 0.18%
SAH-24786 0.18%
IRWD-39194 0.18%
KERX-21789 0.18%
BOLD-50135 0.18%
GCI-49203 0.18%
CAI-33864 0.18%
TROX-40530 0.17%
BWLD-25642 0.17%
WDR-18508 0.17%
ANW-33014 0.16%
VET-44278 0.16%
HQY-47397 0.16%
AIRM-508 0.16%
AAP-23175 0.16%
PLCE-24789 0.16%
EPZM-44830 0.16%
WNC-8233 0.16%
NOV-24809 0.15%
ODP-5583 0.15%
QTWO-46578 0.15%
CIEN-16453 0.14%
CJ-50690 0.14%
FOLD-33949 0.14%
AJRD-3424 0.14%
LOCO-47382 0.13%
AXGN-4413 0.13%
DVAX-25972 0.13%
CLF-1595 0.13%
GPT-26520 0.13%
HOME-50187 0.13%
CSOD-41098 0.11%
REN-34800 0.11%
STNG-39422 0.11%
HTWR-38150 0.11%
ATEN-46598 0.10%
CTMX-49470 0.10%
CCRN-24893 0.09%
SGNT-41301 0.09%
AMED-25392 0.09%
TISI-7487 0.08%
COG-1746 0.08%
WCIC-42777 0.08%
EGL-43151 0.07%
MULE-50719 0.07%
PRGO-6161 0.07%
ADT-43399 0.07%
SNDK-13940 0.07%
FI-45248 0.06%
PUMP-50718 0.06%
PEI-5876 0.06%
SD-50348 0.06%
ARAY-33310 0.06%
GOOS-50713 0.06%
LRN-35259 0.03%
ARCH-50357 0.02%
/usr/local/lib/python2.7/dist-packages/pyfolio/perf_attrib.py:611: UserWarning: This algorithm has relatively high turnover of its positions. As a result, performance attribution might not be fully accurate.

Performance attribution is calculated based on end-of-day holdings and does not account for intraday activity. Algorithms that derive a high percentage of returns from buying and selling within the same day may receive inaccurate performance attribution.

  warnings.warn(warning_msg)

Performance Relative to Common Risk Factors