Sure, let me try to explain what I was trying to do.
for i in range(len(norm_pct)):
stock = context.stocks[i]
sell_amount = round(-1 * context.portfolio.positions[stock].amount * norm_pct[i] * norm_pct[i])
buy_amount = buy_multiplier * round((context.portfolio.cash / data[stock].price) * norm_pct[i] * norm_pct[i])
I step through each stock that I'm watching, and compute how many of that stock I'd buy or sell given my current position, cash, and its performance. The amount to buy is the maximum number of the stocks I could buy (cash / stock price) weighted by its performance relative to the other stocks in my portfolio. The amount we want to sell is the amount of that stock we own weighted in the same way.
I'm not 100% convinced of the validity of this logic (I feel like I should be weighting the stocks that had gains and losses independently of each other, but I haven't implemented it yet). My reasoning was that if we assume the stock is mean reverting, it makes sense to buy more of the ones that had performed poorly, and quickly sell off more of what had been performing well. The weightings were my way of expressing this idea.
if norm_pct[i] > 0 and abs(sell_amount) > 0 and notional > -context.max_notional:
if norm_pct[i]**2 > 0.05:
order(stock, sell_amount)
if norm_pct[i] < 0 and buy_amount > 0 and notional < context.max_notional:
if abs(norm_pct[i]) > 0.05:
order(stock, buy_amount)
The next part implements the buying and selling. We compute how much we would buy or would sell for every stock, but only buy or sell if it's normalized percent change is negative or positive.
We also don't want to submit a buy or sell order unless we have hit some kind of threshold for how much it changed. In cases where the total change was very small we just hold onto the stock. It may be worth considering the stock performance from the point where we bought for the case where we're selling, but I haven't gotten around to testing that.
I hope that's helpful, let me know if you have any other questions.