Yes, this line of code converts the prices into z-scores:
changes_all = stats.zscore(prices, axis=0, ddof=1)
The second detail is that the changes in the sector funds are relative to the SPY benchmark (if I've coded it properly):
changes = changes_all[:,0:-1] - np.tile(changes_all[:,-1],(len(context.stocks)-1,1)).T
So, the variable 'changes' is the z-score difference for each sector fund and the underlying benchmark, i.e. changes = z_sector - z_SPY. So, if changes > 0, it indicates that the sector fund was statistically higher than the benchmark on a given day. Thus z-scoring allows for the direct normalization of the sector funds to their collective benchmark.
My sense is that this normalization approach works because the sector funds are basically SPY chopped up into various categories (and each is still highly correlated to the benchmark). So, the normalization resolves which sectors are favorable over the benchmark. But the Random Forest voodoo is a mystery to me, so this interpretation could be off-base.
From a practical standpoint, I'm not sure that I've captured all of the costs with:
Does this accurately account for all of the Interactive Brokers (IB) costs? And last I heard, Quantopian might charge ~$100 per month per algorithm, so that would need to be rolled in. And short-term capital gains taxes (assuming a non-IRA account)?
Note, also, that orders are submitted at the daily close. My understanding is that in live trading, the orders would be cancelled, correct? This is probably not fundamental, but I thought I'd point it out in case someone tries the algo live with IB.