Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Trading strategy

Торговая стратегия команды пробная, не конечная. В портфель включены 50 акций, отобранные последовательно в описанном кодом порядке. Ребалансировка происходит раз в год в январе, а не раз в месяц, как сказано в коде.

9 responses

Тот же алгоритм, протестированный до конца 2017 года.

This trading strategy has an interesting property. It attempts to compensate for return degradation, even if it does not appear to be intentional.

My modifications make it more volatile, yes. Giving it larger drawdowns, yes. The chart says that there is a 12% alpha, but in reality it is more like a 43% CAGR over the 7-year testing period.

It comes at a cost. The strategy has a gross leverage of about 2.57. So, we would need to deduct from 5 to 8% from the total CAGR. Make it 10%, it would still be a 33% CAGR.

Made only two changes to this trading strategy. One was to increase its tradable candidates, and the other permit it to rebalance twice a year. That's it. Note that I also increased the initial stake to $10 million.

It was enough to raise performance by about 2.5x. Adding more than $97 million to this scenario. Evidently, since you are using a bit more leverage, there will be a higher propensity for larger drawdowns as well as some higher volatility and higher beta. But, you are in it for the CAGR, so... Also, as said, there will be a cost for the leveraging, but it will not be $97 million.

The strategy could be mixed with a low volatility zero beta strategy as the one presented in the Risk Model thread which would dampen volatility and drawdowns, and still keep an appreciable performance level.

The most interesting part is its gradual inventory increase which is one way to partially compensate for return degradation.

@Ksenia, great work. Thanks for posting.

For a little extra “pain”, something like adding a one time -3.4% more in drawdown, one could add some $61.8 million more in profits to the preceding scenario. Pushing the strategy to $229.1 million in profit over its 7-year simulation.

To achieve this, it was sufficient to simply rebalance 3 times a year instead of 2. A question might be: is 3.4% more in drawdown over a single month in 7 years worth $61.8 million?

Having produced more by adding more tradable candidates and rebalancing more often, it was easy to say: do more of that.

So, here is the backtest with rebalancing 4 times a year with 20 more tradable candidates.
It added, over the previous simulation, some $161.8 million. Bringing the grand total profit to: $390.9 million over its 7-year trading interval.

In building a trading strategy, we should test for its limits. They might not have been reached yet.

Can the strategy afford to pay for the extra leverage? It has more than enough to pay the bill. What is used here is trade aggressiveness and you need the nerves to go with it.

One way to temper this is by combining it with low volatility and low drawdown strategies.

A 10% CAGR strategy with low drawdowns with this 68.8% CAGR would generate:

F(1)(T) + F(2)(T) = $10M∙(1+0.10)^7 + $10M∙(1+0.688)^7 = $409.97 million.

It would cut the drawdown nearly in half, reduce the volatility and produce a total 53.9% CAGR. You would still have to pay for the leveraging on the section that is using it.

You could push the above scenario for more. It would only require doing more of the same.

The following test starts with $50 million as initial stake. Five times the previous $10 million scenario, or 5,000 times the original $10k. It makes it a scalability test. Having a lot more money to play with also enabled doing more.

So, the number of trade candidates was increased.

The strategy generated $1,430,862,069 in profits.

The outcome is still a 62.26% CAGR, more than enough to cover leveraging expenses.

Now that we know we can go there, time to set some limits, giving the strategy some constraints to reduce its drawdowns and volatility according to our own level of trade aggressiveness. Overall, we will find that there is always a price to pay for everything we do. But, there are also rewards.

Few of the program's numbers were changed (2). And yet, they had a tremendous impact on the strategy's outcome.

A trading strategy has a signature and pressure points, and a way it is intended to behave. At times, simple variables can dictate how a strategy should behave. And just like using levers, we can add pressure where it matters most.

There is still room to do more if we wanted to.

@KSENIA: your algo will not sell assets that are not in the target list anymore. As US1500 is an unstable universe you need something like this in the rebalance function:

        for security in context.portfolio.positions:  
            if security not in context.security_list:  
                order_target_percent(security, 0.0)  

Here's how the strategy performed in the 2008 mortgage crisis and subsequent recession:

Trade Info for the 50M backtest.

@Gary, thanks. Great analysis. I got to about the same conclusions. There is a large number of partial fills.

Here is my take on this trading strategy.

The script at the top of this thread was not designed with the intention of going very far. It had for objective to trade 50 stocks using $10k. That is $200 per trade. So it did 1 to 10 shares of some high price-to-book stocks and held on with no explicit exit strategy, no downside protection. Protections can always be added on later. Still, the strategy got a 26.5% CAGR.

Usually, I consider such strategies as playing with peanuts and expect them to only make peanuts. But here, the over-average performance had to come from somewhere.

By design, the strategy is for an upmarket which over the past 7 years is mainly what it got. If you buy and hold a bunch of stocks in an up market, you are bound to make some profit.

Nonetheless, due to its design, it is making more than average by simply not selling that many shares when it rebalances its stock weights on the way up. Selling one or two shares here and there if the price rises enough. Most of what it does is hold on to the few shares it has and slowly adding to its inventory. To do this, it uses leverage.

The strategy exploits a weakness in the Q trading environment. It can get leverage without even asking for it. We could classify it as a flaw, a trick, or a feature. It depends on how you will want to consider it. If it is a flaw or trick, and you can control it, does it not become a welcomed feature, if it works?

One can easily force the strategy to over-leverage. Thereby, increasing its volatility, drawdowns, and performance. Which is what I tried to demonstrate making small changes to the strategy's pressure points by changing a couple of numbers.

The strategy is a fixed-fraction of equity play. It is regulated by its basic trading unit:
u = q∙p = 2%∙F(0). Initially picking 50 stocks, it starts diversified and also fully invested.

The basic trade unit, in reality, is u = q∙p = 2%∙F(t), and this makes a difference. The trade unit will increase with time by no fault of its own. It will rise at the market's pace: u(t) = u∙(1+R(m))^t.

By not selling all stocks not making a new tradable candidate list, the program will take on new positions and make weight adjustments on the rest. I do not think this was intentional.

On rising prices, shares will be gradually sold, piece by piece, requiring more and more of a rise to sell shares while declining prices would be gradually bought to maintain the 2% weighting. A variation to a Markowitz portfolio rebalancing thing and a variation on the Buy & Hold theme with a fixed-fraction gambit. Buying on relative dips, holding, and selling on a relative rise. Nothing wrong there, and nothing new.

By giving the strategy a bigger initial stake, and increasing is tradable candidate list, perception changes. New stocks are added to the inventory with their own 2% of equity objective. This reduces the relative weights of all the stocks that were already in inventory and forces the accumulation of their shares.

On an initial purchase, the trade unit is: u = q∙p = 2%∙F(0). Afterwards, on each rebalancing, it is: u = q∙p = 2%∙F(t). And since, on average, F(t) increases, stocks not in a selected list will see their inventory rise too.

All stocks in inventory will adopt this staircase function. Going from plateau to plateau as the number of shares increase. As you add new stocks, the relative weights go down forcing to rebalance upwards and thereby buying more and more shares for any of the stocks that ever got in a selection list. It also means that stocks going down the drain will be accumulated to a certain extent, but not exceed 2% of equity. It is a waste and should be managed.

The strategy, indirectly, is forced to use leverage. It does it by not selling off its old inventory. So, the number of stocks in the portfolio will rise after each rebalancing by the number of new acceptable candidates. The strategy is pyramiding on its ongoing equity value using leverage and generated profits to do so.

As some noticed, this produces leverage spikes since there is no control. This leveraging could be considered relatively high if the strategy was to go at it solo. However, in a scenario where it is mixed with more stable, low volatility, low beta strategies, it could raise the bar considerably for an entire portfolio. I presented something to that effect last July (see the last chart). https://alphapowertrading.com/index.php/12-research-papers/14-post-strategy-portfolio-analysis
The higher return is there to pay for the higher leveraging fees. If your trading strategy has a 50% CAGR and pays an extra 5% to 10% in CAGR equivalent to get it, you are still ahead of the game. What you do not want to see is going in the red. Therefore, the need for downside protection and more control. You are not playing the game to be right. You are playing the game so that, on average, you make money. You just want to make sure you do.

The blue line on a Quantopian chart is the daily net liquidating value. Meaning that at any time you could have quit the game and pocketed those profits. For higher returns, you always have to take higher risks or play better.

As F(t) grows, the bet size grows. That is not necessarily a bad thing.

Holdings Distribution

Now that I have exaggerated a bit by pushing the strategy beyond my comfort zone (see previous posts). I will be looking at ways to constrain its exuberance and limit its downside risks, but not necessarily its propensity to accumulate new holdings.

Evidently, this will reduce its overall CAGR. It will also reduce its volatility, drawdowns and leveraging expenses to more manageable levels. It is always easier to break down a strategy than building it up, at least, we got to know some of its limits.

Note that in the above chart we nonetheless are seeing traces of return degradation. The law of diminishing returns is starting to kick in.

There are reasons why the strategy performed the way it did. It is built in the strategy's mathematical signature. Nonetheless, it is up to each one of us to understand where the pressure points are and determine how much pressure we would want to apply.

You don't like a strategy's behavior, the solution is simple: you change it. It is really up to you, nobody else.

The trick used here could be applied elsewhere, and be better controlled. It is all a matter of how you see things and what you will find acceptable. But, often, what we program is not doing exactly what we had in mind. But then again, it might turn out be just another feature, and not necessarily a logical flaw or some programming bug.

A program is not just code. It can be dynamic and have its own trade mechanics.