Back to Community
Serious bug in backtester?

Here is a sample algorithm. It posts a loss of around 100K between 18th July and 21st July 2015. When I look at the transactions there are no transactions for 21st July on some stocks. When I look at daily positions for 21st July 2015, some positions from 18th July have disappeared. Please look into it.

Clone Algorithm
646
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
import math
import numpy as np
import pandas as pd
import scipy as sp
from sklearn.covariance import OAS
import statsmodels.api as smapi
from sklearn.decomposition import PCA
from sklearn.cluster import affinity_propagation as AF
from statsmodels.stats.moment_helpers import cov2corr
import statsmodels.tsa.stattools as st
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.filters.morningstar import Q1500US
from quantopian.pipeline.classifiers.morningstar import Sector
from quantopian.pipeline.factors.morningstar import MarketCap
from quantopian.pipeline.data import morningstar as mstar
import quantopian.experimental.optimize as opt

def make_pipeline():
    minprice = USEquityPricing.close.latest > 15
    pipe = Pipeline(screen=Q1500US() & minprice)
    
    sectors = Sector()
    pipe.add(sectors, 'sector')
    return pipe
    
def initialize(context):
    set_commission(commission.PerShare(cost=0.001, min_trade_cost=0))
    context.err = sid(39171)
    context.stocks = None
    context.alphas = None
    context.betas = None
    context.clusters = None
    
    context.leverage = 1.
    context.days = 120
    schedule_function(trade_sectors, 
                      date_rules.every_day(), 
                      time_rules.market_open(minutes=1))
    
    schedule_function(update_chart, 
                      date_rules.every_day(), 
                      time_rules.market_close(minutes=1))
    
    attach_pipeline(make_pipeline(), "Q1500")
    
def handle_data(context, data):
    pass

def close_all(context, data):
    os = get_open_orders()
    
    for ol in os.values():
        for o in ol:
            cancel_order(o)
    
    for sid in context.portfolio.positions:
        order_target(sid, 0)

def before_trading_start(context, data):
    if context.days < 120:
        context.days += 1
        return
    context.days = 0
    context.output = pipeline_output("Q1500")
    context.clusters = get_cluster(context, data, context.output.index)
    
    
def get_cluster(context, data, stocks):
    prices = data.history(stocks, "price", 250, "1d")
    prices = prices.dropna(axis=1)
    returns = prices.pct_change().dropna().values
    cov = OAS().fit(returns).covariance_
    corr = cov2corr(cov)
    _, labels = AF(corr)
    
    clusters = {}
    for i, stock in enumerate(prices.columns):
        label = labels[i]
        if label not in clusters:
            clusters[label] = []
        clusters[label].append(stock)    
    
    return clusters
    
def trade_sectors(context, data):
    context.stocks = None
    context.alphas = None
    context.betas = None
        
    for cluster in context.clusters.values():
        if len(cluster) < 35:
            continue
        stocks, alphas, betas = find_weights(context, data, cluster)
    
        if stocks is None:
            continue
            
        if context.stocks is None:
            context.stocks = stocks
            context.alphas = alphas
            context.betas = betas
        else:
            context.stocks = np.hstack((context.stocks, stocks))
            context.alphas = np.hstack((context.alphas, alphas))
            zero1 = np.zeros((context.betas.shape[0], betas.shape[1]))
            zero2 = np.zeros((betas.shape[0], context.betas.shape[1]))
            context.betas = np.hstack((context.betas, zero1))
            betas = np.hstack((zero2, betas))
            context.betas = np.vstack((context.betas, betas))
            
        
    if context.stocks is None:
        return
    
    todays_universe = context.stocks
    N = context.betas.shape[1]
    M = context.betas.shape[0]
    names = [str(i) for i in range(0, N)]
    risk_factor_exposures = pd.DataFrame(context.betas, index=todays_universe, columns=names)
    objective = opt.MaximizeAlpha(pd.Series(context.alphas, index=todays_universe))
    
    constraints = []

    constraints.append(opt.MaxGrossLeverage(1.0))
    constraints.append(opt.DollarNeutral(0.01))
    neutralize_risk_factors = opt.WeightedExposure(
        loadings=risk_factor_exposures,
        min_exposures=pd.Series([-0.01] * N, index=names),
        max_exposures=pd.Series([0.01] * N, index=names))
    constraints.append(neutralize_risk_factors)
    constraints.append(opt.PositionConcentration.with_equal_bounds(min=-2. / M, max=2. / M))
    order_optimal_portfolio(objective=objective, constraints=constraints)
                
def find_weights(context, data, stocks):
    prices = data.history(stocks, "price", 200, "1d").dropna(axis=1)
    returns = np.log1p(prices.pct_change().dropna().values)
    factors = PCA(0.75).fit_transform(returns)
    model = smapi.OLS(returns, smapi.add_constant(factors)).fit()
    remainder = model.resid
    corr = np.zeros(remainder.shape[1])
    
    for i in range(0, len(corr)):
        corr[i] = np.corrcoef(remainder[1:, i], remainder[:-1, i])[0, 1]
    zscores = sp.stats.zscore(remainder[-1, :])
    return prices.columns.values, zscores * np.sign(corr), model.params.T[:, 1:]

def update_chart(context,data):
    record(leverage = context.account.leverage)

    longs = shorts = 0
    
    for position in context.portfolio.positions.itervalues():        
        if position.amount > 0:
            longs += 1
        if position.amount < 0:
            shorts += 1
            
    record(long_lever=longs, short_lever=shorts)
There was a runtime error.