Risk control is absolutely crucial for traders. The first rule of trading is to stay in the game. The humble stop loss is the bread and butter for traders trying to control their risk.

But what if I told you the stop loss wasn't needed? What if you could control your risk while also increasing your returns?

To do this, we'll introduce a new concept: continuous trading. This will be added to the starter system model that we have built up over the past few articles (Part 1 and Part 2) which will take away our stop loss safety blanket!

Drop the Stop

I don't typically recommend trading without a stop loss in your system. There are some strategies where it's imperative and it would just be a matter of time before you blow up your account if you're not using one.

However, we're working with Rob Carver's Starter System, which is a trend following system. Trend following allows you this luxury without massively increasing your risk.

We do this by exiting trades when the trend reverses rather than when a stop loss gets hit. This keeps us in trades longer, possibly giving us a shot at larger returns.

In the plot below, we see how this plays out.

starter-system3-no-stop-loss-1.png

This strategy (which we'll run later) entered the position on June 18th by going short (blue triangle). We ran this with a stop and with a trend reversal exit. The stop loss limit is plotted above the price (dashed blue line).

The short trade pays off quickly and we see it drop from $15.43 where it entered to $11.09 within a month for a 28% gain. Then the price reverses, coming within a few cents of hitting our stop by the end of July.

Thankfully, it didn't and the price started falling again to a low of $7.22 by the end of September. Then it bounces back again, this time hitting our stop at $9.51 on October 10th. And we're out of the trade.

We got a great, 38% profit on that one! But, the trend continued with us on the sidelines

The price rebounded, but it kept falling all the way to $3.71 (this was the 2001 stock market crash after all). The trend signal didn't reverse until February when the trade closed out at $6.08 for a 61% profit.

This is what continuous trading allows you to do.

Of course, this won't always play out this way - there are cases where the stop loss will exit on a reversal sooner - but this does tend to happen more often than not, making this technique a positive addition to your trend following trading bot.

This is Heresy!

The reason we would spend our time analyzing this well thought-out strategy, is because it’s interesting (and could make you some money). No stop loss in a careful, systematic strategy to exit trades. You don’t see that every day.

If you’re already angry, heated, or scared by this idea — we don’t care.

Hunting Big-Game Outliers

Trend following is all about getting a few large returns by jumping on trends and holding on for as long as it takes.

When you think about it, that's really how most investors make it big. They jump on some company and ride the trend all the way up. Maybe they identify these companies via their fundamentals, or just got lucky, or were following a systematic approach - it doesn't matter. They bought in and rode it to riches.

We don't know what's going to deliver for us, so we just trade all the trends that come our way and stay on until it reverses.

starter-system3-trading-skew.png

Just because your system will get you out of a position when the trend flips doesn't mean you can just forget risk control. It just puts the burden onto your position sizing.

In Carver's system, he has a pre-defined risk level (12%, although we can raise it with these multiple signal systems).

We don't bet too much so that we never lose too much of our capital if a trend reverses quickly.

The Trend Following System

If you have been following along with this series, this all ought to be familiar to you. If not, go back and read the other articles or get Carver's book and dive into the deep end.

Ok, now that you've done that, we're going to skip over the system details and jump to the changes.

Previously, we had exited a trade on a stop loss. Now, our exit rule becomes:

  • Exit a long position if the signal < 0
  • Exit a short position if the signal > 0

We're going to stick with our multi-signal entry/exit. To keep the code to a minimum, we can just inherit from the StarterSystem class we defined here and update the run() method:

class ContinuousStarterSystem(MultiSignalStarterSystem):
    '''
    Carver's Starter System without stop losses and multiple entry rules.
    Adapted from Rob Carver's Leveraged Trading: https://amzn.to/3C1owYn
    '''
    def __init__(self, ticker: str, signals: dict, target_risk: float = 0.12,
                starting_capital: float = 1000, margin_cost: float = 0.04,
                short_cost: float = 0.001, interest_on_balance: float = 0.0, 
                start: str = '2000-01-01', end: str = '2020-12-31', 
                shorts: bool = True, weights: list = [],
                *args, **kwargs):
        super().__init__(ticker=ticker, signals=signals, 
                         target_risk=target_risk, margin_cost=margin_cost, 
                         short_cost=short_cost, start=start, end=end,
                         interest_on_balance=interest_on_balance,
                         starting_capital=starting_capital, shorts=shorts,
                         weights=weights)

    def run(self):
        position = np.zeros(self.data.shape[0])
        cash = position.copy()
        for i, (ts, row) in enumerate(self.data.iterrows()):
            if any(np.isnan(row.values)):
                cash[i] += self._calcCash(cash[i-1], position[i], 
                    row['Close'], row['Dividends']) if i > 0 \
                        else self.starting_capital
                continue

            # Propagate values forward
            position[i] = position[i-1]
            cash[i] += self._calcCash(cash[i-1], position[i], 
                                    row['Close'], row['Dividends'])
            signal = self._getSignal(row[self.signal_names].values)
            
            if signal > 0:
                if position[i] <= 0:
                    cash[i] += position[i] * row['Close']
                    position[i] = self._sizePosition(cash[i], 
                        row['Close'], row['STD'])
                    cash[i] -= position[i] * row['Close']
            elif signal < 0:
                if position[i] >= 0:
                    cash[i] += position[i] * row['Close']
                    if self.shorts:
                        position[i] = -self._sizePosition(cash[i], 
                            row['Close'], row['STD'])
                        cash[i] -= position[i] * row['Close']
                    else:
                        position[i] = 0
            else:
                # Remain neutral if signal == 0
                cash[i] += position[i] * row['Close']
                position[i] = 0

        self.data['position'] = position
        self.data['cash'] = cash
        self.data['portfolio'] = self.data['position'] * self.data['Close'] \
            + self.data['cash']
        self.data = calcReturns(self.data)

We'll initialize this the same way, with a dictionary of signals, and then we're off!

sig_dict = {
    'MAC' : {
        0: {'fast': 8,
            'slow': 32},
        1: {'fast': 16,
            'slow': 64},
        2: {'fast': 32,
            'slow': 128},
        3: {'fast': 64,
            'slow': 256}
    },
    'MBO': {
        0: 20,
        1: 40,
        2: 80,
        3: 160,
        4: 320
    }
}

For ease of comparison, we'll test this model against our random ticker, HAL from the last post, and see if we get a boost in our metrics.

We'll use our getStratStats function to look at the results (also in previous posts, just trying to keep the copy/paste to a minimum).

ticker = 'HAL'
sys_cont = ContinuousStarterSystem(ticker, sig_dict)
sys_cont.run()
sys_disc = MultiSignalStarterSystem(ticker, sig_dict)
sys_disc.run()

strat_stats = pd.DataFrame(
    getStratStats(sys_cont.data['strat_log_returns']),
    index=['Continuous'])
strat_disc = pd.DataFrame(
    getStratStats(sys_disc.data['strat_log_returns']),
    index=['Stop Loss'])
buy_hold_stats = pd.DataFrame(
    getStratStats(sys_cont.data['log_returns']),
    index=['Buy and Hold'])

stats = pd.concat([strat_stats, strat_disc,
                   buy_hold_stats])
stats
carver-system-3-stats.png

The continuous model gives us a boost to returns and Sharpe ratio. In fact, that's the big benefit Carver pushes in his book, a 0.03 boost to your average Sharpe ratio when trading like this vs with a stop loss.

I can't recreate Carver's results here (I don't know what instruments he traded or what time periods) but I have seen a similar boost across multiple securities.

Below we have the equity curves:

carver-system-3-plots-1024x675.png

They stick pretty close to one another, but the continuous system slowly outperforms the stop loss system over the long run.

Build Your Trading Bot

Of course, none of this is guaranteed. This is just a single backtest.

Your trading bot - if you choose to build one like this - may perform much better (or worse) depending on the specific parameters employed and the your choice of instruments.

We give you the ability to test your ideas quickly across a wide set of instruments.

We've got more to do on this system though. There are ways to get more returns (for less risk) and we're going to tie it into an account so you can run it yourself.

If that interests you, be sure to check out our free demo so you can build your own, customized trading bot with no-code and deploy it to trade in the markets!

You can skip all of this work and be up and running in a few minutes!