Trading Strategy Analysis.
What interested me in this trading strategy was not the stock selection process. It was the trading strategy's structure. I saw something I could reshape and mold to meet my objectives.
Gradually, as seen by the successive simulations, I gave the strategy a new direction by adding the things I wanted to see and partly control. Each step doing more and more. Each step gaining more and more.
What I consider the cornerstone of this program is a lowly variable. It controlled everything of significance this trading strategy had to offer.
The constant: max_long_sec, represents the maximum number of stocks one can take long at any one time. It is determined by choice. It is not calculated by the program's logic, nor regulated by any other variable. It is simply preset in code.
I viewed it more as the programmer's afterthought or prerequisite. As if “maybe I should limit this and have half for longs from the top of the list of the projected rising stocks”. All the program's effort seemed to have been concentrated elsewhere with no trace or mention of the importance or significance of this constant. And this, even if it has its say in about everything.
I disabled most of the original functions in this trading strategy, some without replacements, others altering the very nature of the program. I modified its trading mechanics, and it resulted in quite a different program from the original version.
For example, stop loss and profit target procedures were eliminated since it was redundant code. Beta scaling and targeting functions were rendered inoperative. In fact, little of the original strategy was kept. Even the benchmark's one share directional referencer was not purchased (SPY).
The max_long_sec constant permeates the whole infrastructure of this trading strategy forcing it to do things maybe not intended by the original programmer, or just maybe he did not see what I saw in it.
As a side note: my books, Stock Trading Strategy Mechanics, if you want more, you have to do more, and Building Your Stock Portfolio. Both covered the subject of trade mechanics, and that the trading strategy itself was at the center of the payoff matrix: Σ(H.*ΔP). It is what you do (H) with ΔP that will have an impact. Your trading logic over what is available will determine what will be the outcome. This has been extensively covered on my website.
A payoff matrix is trade agnostic. It does not care where the profit or loss comes from. Neither does it care about sentimentalities, trade psychology, theories or moon phase. It only keeps track of the final score.
All the successive tests I presented showed incremental alpha by modifying the trade mechanics of the program, by modifying g(t) in: F(t) = F(0) + (1 + g(t))∙Σ(H.*ΔP).
Test 60 showed remarkable performance. Relatively low drawdowns and volatility with a 37.82% CAGR net of all trading expenses: commissions, slippage, and leveraging fees.
Test 70 did even better with a 45.33% CAGR net of all expenses.
Test 72 raised the bar with a 49.64% CAGR.
And, test 73 raised the bar even higher with a 53.22% CAGR, net of all expenses.
In all four cases, I increased performance by increasing the number of trades (n). And this, increased the alpha generation which is what, in the end, really matters. We can also see that the incremental CAGR is decreasing. It is getting harder to produce more.
Test 70's payoff matrix Σ(H.*ΔP) has a minimum size of 5,580 rows by 240 columns, a total of 1,399,200 data elements. However, due to Quantopian's 2.5% of volume rule the size of this payoff matrix is more like a minimum 10,400 by 240, or at least 2,496,000 data entries. The matrices at play: the price matrix, holding matrix, price difference matrix, as well as the decision matrix are of the same size, each with as many data elements.
All the payoff matrix data elements can be resumed in two numbers: Σ(H.*ΔP) = n∙APPT where APPT is the net average profit per trade. It does not matter what the trading strategy is or its composition, the output will be: n∙APPT, with unit a dollar sign.
If I can write: F(t) = F(0) + g(t)∙Σ(H.*ΔP), then I can also write: F(t) = F(0) + g(t)∙n∙APPT. Meaning that by controlling the number of trades, and the average net profit per trade (APPT), I can have some function to scale up, or down, the output of the trading strategy.
All I need is find g(t) and give it a positive stance. Just g(t) > 1 would appear sufficient. Or, expressed differently, but saying the same thing: F(t) = F(0) + (1+g(t))∙n∙APPT with g(t) > 0. We can make g(t) market correlated.
My calculations for test 60 estimated the APPT to be about $ 13.95 on an average $ 8,889 bet (0.1569% profit or 0.001569). To put this in perspective, it is less than an average 8-cent move on a $50 stock (0.07848). While the market as a whole had to offer on average: $ 13.68 (approx: 0.1538%) just for participating in the game, also less than 8 cents (0.07695) for a comparable move.
This would imply that the advantage of using the PreCog dataset might be 0.0031% or $0.27 per average transaction. You get $0.27 more profit than market average on an $ 8,889 bet.
This is not a great incentive for or against the use of this dataset since I could not differentiate it from the market's average offer by any statistically significant measure.
This confirms why the initial version of this program could not obtain high alpha readings from the PreCog dataset since it tended to be close to the market's average performance level.
Tests showed you had this swarm of price variance hovering above and below the zero-change line. This swarm was ordered by momentum (252 days), then divided into three parts. The top 180, the bottom 60, and all the rest standing in between. As if the middle was a buffer, a no-trade zone. A 5-day PreCog prediction could throw a selected stock in either of the three zones every day with for side effect a lot of churning.
I consider the dataset used as not that different from what the market had to offer. At least, I can not exclude the null hypothesis that they are about the same. You were simply trading on market noise.
Test 73 does show impressive results. A net CAGR of 53.22%, all expenses paid, including leveraging fees. But as expressed before, one could still nudge its alpha higher simply by increasing g(t): F(t) = F(0) + (1 + g(t)↑)∙Σ(H.*ΔP) as was done in prior tests (see test 75).
This was also demonstrated in test 78.
Here are the important numbers in graphic form:
CAGR vs Leveraging Costs:
Now that I know where the strategy limits are and how far it could go, I can choose the level at which I feel most comfortable knowing that I could do more if I wanted to.
Also, knowing what controls the trading strategy, I could give this control to outside program intervention as if having the trading program on a joystick, or some slider control of some kind. That would be fun.
Note: with all the observations provided, anyone could rebuild this trading strategy. Rebuilding it yourself makes you understand what makes it tick.
Some can ignore the math of the game, but it won't make it go away.