Notebook

Run the cell below to create your tear sheet, or return to your algorithm.

In [4]:
bt = get_backtest('5a699a71223ce142e8128aeb')
bt.create_full_tear_sheet()
import empyrical as ep
import pyfolio as pf
import numpy as np
from matplotlib import pyplot as plt
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
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
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
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)
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.'
        
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))

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

Performance Relative to Common Risk Factors

Summary Statistics
Annualized Specific Return 14.65%
Annualized Common Return 0.41%
Annualized Total Return 15.07%
Specific Sharpe Ratio 2.31
Exposures Summary Average Risk Factor Exposure Annualized Return Cumulative Return
basic_materials -0.01 -0.37% -0.77%
consumer_cyclical -0.00 -0.60% -1.23%
financial_services 0.00 -0.22% -0.45%
real_estate -0.00 -0.11% -0.23%
consumer_defensive 0.00 0.09% 0.19%
health_care 0.04 -1.06% -2.16%
utilities -0.00 0.04% 0.09%
communication_services 0.00 -0.09% -0.18%
energy 0.02 1.81% 3.75%
industrials -0.02 -0.93% -1.89%
technology -0.01 -0.36% -0.74%
momentum -0.02 -0.62% -1.27%
size -0.03 0.27% 0.55%
value 0.07 -0.75% -1.53%
short_term_reversal 0.84 3.54% 7.40%
volatility 0.03 -0.14% -0.28%
Checking positions concentration limit...
PASS: Max position concentration of 3.08% <= 5.0%.

Checking leverage limits...
PASS: Leverage range of 0.93x-1.02x is between 0.8x-1.1x.

Checking turnover limits...
PASS: Mean turnover range of 24.19%-38.61% is between 5.0%-65.0%.

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

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

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

Checking style exposure limits...
FAIL: Mean short_term_reversal exposure of 0.912 on 2017-03-06 is not 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.33 is positive.

Results:
8/9 tests passed.

Score computed between 2018-01-03 and 2018-01-22.
Cumulative Score: 0.096751