Often times you hear about the importance of setting a stop-loss before opening trades. But if you are a quant, I assume you already know the importance of it.
You may use stop-loss for two reasons:
Note #1: A stop order can be used for opening trades too, which is an advanced usage of a stop order. I will not be talking about that in this tutorial.
Whether your strategy uses (some kind of) a trailing stop to exit or it exits at a specific price, it doesn't matter for now. But the idea of setting a stop-loss below your entry price is just non-negotiable. In my opinion, your strategies are flawed if they don't use it.
Let's say you decide to use a stop-loss. But what would be your exact stop price? Does it really matter? Yes! It is crucial actually.
While increasing the margin of your stop-loss will increase the win-rate of your strategy, it will reduce the size of your position. Smaller positions sizes mean smaller profit in the long term. And of course, long-term profit is what algo-trading is all about.
I'll explain this with an example:
Image your total capital is 10,000 and you intend to risk 3% of it per trade. Let's say your strategies tell you to enter the market at $100, and to set your stop-loss at $80 (in this article I'm covering ways to determine the exact price). How much should the size of your position be?
Since talk is cheap, I'm gonna anwer with the code:
entry_price = 100 stop_price = 80 risk_percentage = 0.03 capital_size = 10000 risk_per_qty = 100 - 80 # 20 position_size = ((risk_percentage * capital_size) / risk_per_qty) * entry_price position_qty = position_size / entry_price # 15
Thus the position quantity should be 15 so that I only risk 3% of my capital which is $300. Now let's see what will happen if I tighten my stop-loss and still risk 3% ($300). Let's say I put my stop loss at $90 instead:
entry_price = 100 stop_price = 90 risk_percentage = 0.03 capital_size = 10000 risk_per_qty = 100 - 90 # 10 position_size = ((risk_percentage * capital_size) / risk_per_qty) * entry_price position_qty = position_size / entry_price # 30
Note that I'm still risking $300 per each trade but my position size is doubled, and so is the possible profit (if it turns to be a profitable trade). But of course, a tighter stop-loss means you'll get stopped out of your trades more often which means the win-rate will be reduced.
You want your stop-loss not be too tight, neither too loose.
I have created a small website that lets you play with this formula to fully understand how position sizing works.
Now I want you to talk about 4 ways that I use to determine the exact stop-loss in my algo strategies.
The Average True Range is my favorite indicator for setting a dynamic stop-loss. On a chart, it might seem a little scary at first:
(ATR indicator on TradingView)
As you can see, the ATR value changes as the volatility of the price does. This is the key reason why I'm using it for stop-loss.
The stop-loss price must be set at a level to avoid getting hit by market noise. Volatility and noise go hand in hand.
Using ATR is actually easier when algo-trading than in trading manually. In below example which is for a long trade, I set my stop-loss
3*ATR away from the entry price:
# get the ATR indicator value for current candle atr = ta.atr(self.candles) # enter at current price with a market order entry = self.price stop = entry - (atr * 3)
Depending on the timeframe you are trading, you might need to change the multiplier. I used 3 for the
4h timeframe. For smaller timeframes, you need to decrease the multiplier.
Moving averages are like the "hello world" of technical trading. But not all know that they can use them for stop-loss too.
For example, we could use two EMAs in our strategy, one with a smaller period for entry, and one with a bigger period for stop-loss.
(3h timeframe ETHUSD - blue line: EMA50 - Purple line: EMA100)
In the above example, we could have bought at the EMA50 which would have been when there was blood on the market, and used EMA100 as our stop-loss.
import jesse.indicators as ta entry = ta.ema(self.candles, 50) stop = ta.ema(self.candles, 100)
This is a tricky strategy and requires careful optimizing; but if done right, it could give you a high risk to reward ratio.
The market has a short-term memory. It remembers the price levels of previous candles up to a few days sometimes. I can't put my finger on the fact why this stop-loss method works, but it usually does. You could use the lowest price of the previous N bars as a minimum level you would expect the price affected by noise to reach. Hence it might be a good idea to put your stop-loss either at that level or even slightly below it.
Determining the lowest of N bars is easy with the naked eye:
(The purple arrow indicates entry price - Blue line indicates the stop-loss price)
What about the code? Well, I use the Jesse framework, and it's easy to accomplish this. Let's say we want to use the lowest price of the last N=20 bars:
# "4" is the index of low of the candle in Jesse's strategy API. # for more, read https://docs.jesse-ai.com/docs/strategies/api.html#current-candle last_20_lows = self.candles[-20:, 4] previous_low = np.min(last_20_lows)
self.candles returns a numpy array as is explained in Jesse's documentation.
This one is the simplest and easiest to write the code for; and yet it works pretty well sometimes. Especially if you're a day trader.
First, you need to tell Jesse to load candles for
1D timeframe at your
extra_candle list. Here's an example for
# My trading route is "4h". routes = [ ('Bitfinex', 'BTCUSD', '4h', 'TrendFollowingStrategy'), ] # I need to add an extra route to "extra_candles" below: extra_candles = [ ('Bitfinex', 'BTCUSD', '1D'), ]
Now in the strategy, first I select all daily candles, then the previous day's candle, and then pick the low price of it (index=4):
# docs for self.get_candles: # https://docs.jesse-ai.com/docs/strategies/api.html#get-candles all_daily_candles = self.get_candles(self.exchange, self.symbol, '1D') # notice that "-1" would have have given me the current candle, # hence "-2" gives me the one before that which is yesterday's previous_day_candle = all_daily_candles[-2] previous_day_candle_low = previous_day_candle
The final question might be, which one of the mentioned methods is the best? Well, I can't say for sure. What I personally do, is to try them all out every time I develop a new strategy.
You'll be surprised how much the result varies. Each method might work well on a specific market and timeframe. For example, the ATR method has worked well for me on
BTCUSD on the
4h timeframe; and the moving average method has worked well on
ETHUSD on a
You could also use Jesse's optimize mode and let the algorithm decide which stop-loss method to use! The optimize mode however is not out yet. Make sure to subscribe to be notified when it is released.