4 practical methods to set your stop-loss when algo-trading Bitcoin
Tags: bitcoin, algotrading, trading, python
Published: 2024-02-23 11:01:31

Many traders stress the importance of setting a stop-loss before opening a trade. However, as a quant, I'm sure you are well aware of its significance.

There are two main reasons for using a stop-loss:
-  Setting it at the beginning of a trade
-  Implementing a trailing stop to exit open positions

**Note #1**: It's worth noting that a stop order can also be used to open trades, but that is a more advanced technique that we won't be discussing in this tutorial.

**Note #2**: As with all my tutorials, I will be using the open-source and free Python language and the Jesse framework. Both are great tools for getting started in algo trading.

Whether your strategy uses a trailing stop or exits at a specific price, it doesn't matter at this stage. The key is to always set a stop-loss below your entry price. In my opinion, any strategy that doesn't incorporate this is flawed.

### Why is the exact stop-loss price so crucial?
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 position 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:

Imagine 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 going to answer with the code:

```python
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:

```py
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 trade, but my position size is doubled, and so is the potential profit if it turns out to be a profitable trade. However, a tighter stop-loss means you'll get stopped out of your trades more often, reducing the win rate.
You want your stop-loss not to be too tight, nor too loose.

I have created a [small website](https://positionsizingcalculator.netlify.app) that allows you to experiment with this formula to gain a full understanding of how position sizing works.

Now, I will discuss four methods I use to determine the precise stop-loss in my algorithmic strategies.

### 1. ATR Indicator
The [Average True Range](https://www.investopedia.com/terms/a/atr.asp) is my preferred indicator for establishing a dynamic stop-loss. Initially, it may appear daunting on a chart:

![ATR indicator](https://raw.githubusercontent.com/jesse-ai/storage/master/practical-methods-to-set-your-stop-loss-when-algo-trading-bitcoin/1.png)
(ATR indicator on TradingView)

The ATR value fluctuates with price volatility, making it ideal for setting stop-loss levels.

> The stop-loss price should be positioned to avoid being affected by market noise, as volatility and noise are interconnected.

Utilizing ATR in algorithmic trading is simpler than manual trading. In the following example, designed for a long trade, I place my stop-loss `3*ATR` from the entry price:

```python
# Obtain the current candle's ATR indicator value
atr = ta.atr(self.candles)

# Enter at the current price using a market order
entry = self.price 

stop = entry - (atr * 3)
```

The multiplier may need adjustment based on the trading timeframe. I selected 3 for the `4h` timeframe; for shorter timeframes, reduce the multiplier.
### 2. Moving Average

Moving averages are like the "hello world" of technical trading, but not everyone knows they can also be used for stop-loss.

For instance, we could employ two EMAs in our strategy: one with a shorter period for entry and another with a longer period for stop-loss.

![Moving Average](https://raw.githubusercontent.com/jesse-ai/storage/master/practical-methods-to-set-your-stop-loss-when-algo-trading-bitcoin/2.png) (3h timeframe ETHUSD - blue line: EMA50 - Purple line: EMA100)

In the above example, we might have purchased at the EMA50 during market downturns and utilized EMA100 as our stop-loss.

```python
import jesse.indicators as ta

entry = ta.ema(self.candles, 50)
stop = ta.ema(self.candles, 100)
```

This strategy is complex and requires careful optimization, but if executed correctly, it could offer a favorable risk-to-reward ratio.

### 3. The Previous N Bars' Lowest Price

The market has a short-term memory, recalling price levels from previous candles, sometimes up to a few days.

Using the lowest price of the previous N bars as a reference level affected by noise could be a sound stop-loss approach.

Identifying the lowest of N bars is straightforward visually:

![Moving Average](https://raw.githubusercontent.com/jesse-ai/storage/master/practical-methods-to-set-your-stop-loss-when-algo-trading-bitcoin/3.png) (The purple arrow indicates entry price - Blue line indicates the stop-loss price)

Regarding the code, with the Jesse framework, determining the lowest price of the last N=20 bars can be achieved easily:

```python
last_20_lows = self.candles[-20:, 4]

previous_low = np.min(last_20_lows)
```

Note that `self.candles` returns a numpy array, as explained in Jesse's documentation.

### 4. Previous Day's Low

This method is simple to implement and can be effective, particularly for day traders.

Initially, you must instruct Jesse to load candles for a `1D` timeframe in your `routes.py` file's `extra_candle` list. Here's an example for `BTC-USDT`:

```python
all_daily_candles = self.get_candles(self.exchange, self.symbol, '1D')

previous_day_candle = all_daily_candles[-2]

previous_day_candle_low = previous_day_candle[4]
```

### Conclusion

Determining the best stop-loss method among those mentioned is subjective. Experimenting with each method when developing a new strategy can yield varying results. Different methods may perform well based on the market and timeframe. Using [Jesse's optimize mode](https://docs.jesse.trade/docs/optimize/#strategy-optimization), can automate the selection of the stop-loss method for you so make sure to take advantage of it.