Debunking Myths: Trading breakouts

Norman Fung
9 min readApr 30, 2024

--

[This is not investment advice, do your own research. Assume I am here to lie to you.]

This article tries to put some science behind trading breakouts. This article is the purpose of last article (Time Series slicer and Price Pattern extractions). It’s worth mention I see others for example Code Trader done something similar, coding is much simpler. So, why the additional complexities? Because time series segment can be used in many ways. This article, is one application. You can also feed the segments to neural nets: Segment predictions. As soon as your strategies are able to percept candles on aggregated basis, possibilities are endless.

Casually look around there’s no shortage of “Cheat Sheets” like this.

From https://www.studocu.com/

Further, different traders draw the wedges differently. For example Mar-Apr 2024 is that a “Descending Triangle”? “Symmetrical Triangle”?

And does it matter? Think about it, “Bullish Wedge” is considered Bullish Continuation? Drawn slightly different “Descending Triangle” is a “Bearish Continuation”?

Is there any truth behind this? Can we back this up with statistics? Or refute it? My hunch is, when prices converge, what typically follows is break up or down. Now, I think you will have better odds to bet that it will break up during bull market, and break down during bear market.

btw it’s always good to get some basic intuitions before diving into algorithms, coding and anything complicated. Intuition First.

Back test approach as follows. We’d trade BTC.

Entry criteria

Criteria 1: Trade with the trend

We use 90d EMA as our north star.

If price above 90d EMA, we consider we’re in a bullish trend. We’d long only.

If price below 90d EMA, we consider we’re in a bearish trend. We’d short only.

Criteria 2: Whenever price converging, we make entry. What’s “Converging”, we check “last segment”, see if it is classified as one of:

  • rising_converging (If above 90d EMA)
  • falling_converging (If below 90d EMA)
  • sideway_converging

Based on Criteria 1, we either long or short depending on 90d EMA. And where’re the segments coming from? We slice time series (trailing prices) into segments using techniques (we take the actual code) described in my earlier article.

Question for you, why not simply aggregate hourly candles into say weekly candles (Instead of segments), for example Jessia used simple candles for head-n-shoulder detection?

  • If you use candles aggregation approach, you’re assuming constant segment width
  • you’re not taking into account “converging” or “parallel” channels

You will find “Segments” in this file: BTCUSDT_locandles_w_segments_2021–02–27–00–00–00_2024–04–24–00–00–00_1d.csv

“class” column contains segment classification

start_dates” control date when test starts. “lo_how_many_candles_values” defines the primary sliding window used in back tests.

lo_how_many_candles_values = [ (‘1h’, 24, 24*1150) ]

‘1h’ : Hourly candles

“24” : Sliding window size is 24 hourly candles

“24*1150”: test period is 24 hrs x 1150, or 1150 days.

Many of the other parameters such as “hi_how_many_candles_values” (Higher time frame sliding window definition), “ema_short_slope_threshold_values”, “rsi_upper_threshold_values” are not used for this project. And note “compute_candles_stats” calculates a lot of things (Hurst exponent, ATR, RSI, MACD…etc) from candles that’s not actually used in this project (I used them for other trades). Why I keep them in the code? You can however easily extend and add additional signals as entry/exit criteria.

Criteria 3: Do we have cash?

entry_percent_initial_cash_values” defines order notional: 80% of initial cash (“initial_cash_values”). Please be reminded,

  • We’re not trading bigger and bigger order notional as we make money. So, gains are not “Reinvested

target_order_notional = initial_cash * entry_percent_initial_cash/100

  • strategy will stop if total equity (cash + position, “gloabl_state.total_equity”) drop below this minimum order notional.
  • For this experiment we only trade one ticker, and we don’t give considerations to things like Kelly Criterion.

Exit criteria

Take Profit (TP) Criteria: Whenever price breaches Bollinger upper or lower band. Parameter that controls this is: boillenger_std_multiples_values

Actually probably what will work better is to ride the winning’s much longer, here are two non mutually exclusive alternatives:

  • Option 1. do NOT TP when you hit upper band, but tighten trailing SL instead
  • Option 2. do NOT TP, until price breaks EMA

Stop Loss (SL) Criteria: “unurealized_pnl_live” is evaluated using:

  • candles low: If you’re sitting on long position
  • candles high: If you’re sitting on short position

So we’re taking a pessimistic view. On the contrary, TP uses close price for evaluation, it’s neither optimistic nor pessimistic.

Note you can do this as this is single legged trade. For two legged trades (statsarb for example), you have to use “close” price for both TP and SL (Instead of highs or lows) as highs on one leg most probably happens at different time to lows on the second leg.

Parameter that controls this is “sl_percent_values”: 3%

Why 3%? You can run back tests on various SL values in brute force manner to see what works best. Alternatively, you can look at hour-on-hour, day-to-day changes. Yes I can hear traders screaming 3% is too tight, well do-your-own-research, try alternatives like ATR multiples as adaptive SL? Or unwind positions in clips in a more gradual manner? Also it depends on your trade’s timeframe, if your strategy avg signal life is two weeks, then 3% definitely too tight.

You can explore more adaptive approach to SL by stopping with multiples of ATR (Average True Range), already precomputed in “compute_candles_stats

After you run the back test, there’re two key output:

  1. Look for trade extract, a file “backtest_converging_wedge_strategy_BTC_20210301_trades.csv” — it comes from data frame “pd_flattenned_trades”. From here we plot equity curve. The csv is also very useful as you can dig into trade details and put pivot table over it.

2. Tear sheet from Quantstats report

Strategy Risk

Remember our North Star is 90d EMA? You only

  • long when close>90d EMA
  • short when close<90d EMA

As such most of the losses would come from long entries but when market keep chopping down towards 90d EMA. Vice versa. Example Mar-May 2024 BTC. That’s when trend following will bleed.

Lets look at the result.

  1. Equity curve
  • Over timespan of three years, draw down looks small (When you zoom in, you may feel differently, especially if drawdown happens when you start live trading)
  • Flat places are when strategy idling (not trading). 2022 we’re making fewer entries, check the segment csv.

2. Tear Sheet (We use quantstats)

Return distribution

Mar 2021, Dec 2021 probably skewed return distribution but it’s safe to assume you can make 2–3% a month on average? Also remember gains are not re-invested (So denominator grows, but order notional stays constant), so percentage returns may look subdued in 2023–2024. Open the trade file and look at actual dollar amounts of gains.

3. Dig into trade file “backtest_converging_wedge_strategy_BTC_20210301_trades.csv”

First we try to breakdown pnl based on:

  • side: This is side of closing trade. So if “side” = buy, it means position is a short position (i.e. it made short entry when price below 90d EMA). If “side” = sell, it means position is a long position (i.e. it made long entry when price above 90d EMA)
  • reason: TP (take profit) or SL (stop loss)
  • last_lo_candles_segment_class: That’s segment classification. It’s “Last segment” at the point when stratetgy made entry.

Note,

  • side = buy (i.e. short position entered when price<90d EMA)

If you make entry using “falling_converging”, by notional, TP/SL = 5.69

  • side = sell (i.e. short position entered when price>90d EMA)

If you make entry using “rising_converging”, by notional, TP/SL = 4.27

If “sideway_converging”, you still make money but TP/SL slightly worse = 2.67

90% hit ratio (Gosh you must be rich?!)! But note that at 3% SL, you pay out more per losing trades than winning trade. So you cannot just look at hit ratio.

You need also look at average trade profit and loss for winning trades, vs losing trades. The way we traded, we need three TPs to cover one SL.

I further suggest you group by “trade_day”, to see if your losing days usually come from end of month because of things like GDP , PCE or FOMC announcements?

So, from back test, it seems to be supportive of using “Ascending Triangle” in a bull market, and “Descending Triangle” in a bear market.

On flip side, I won’t long on “Ascending Triangle” in a bear market. Or short “Descending Triangle” in a bull market. I encourage you change entry conditions and rerun the back test to prove this.

Yuke, you don’t want to short in a bull run, period.

Disclosure: I didn’t live trade this strategy, I like simpler trades, and also trades that make more entries, closing pnl in more frequent basis, even for lower Sharpe. But most of the back testing code came from another strategy that I do live trade: And back tests result resemble quite closely with profit and loss from live trading.

Some folks, split historical data into:

  • training set: From here you’d find the appropriate strategy parameters
  • validation set: From here, you’d determine if your back test is lying to you!

It’s just my personal references is first live trade in small amounts and compare on live basis, live pnl vs back tests.

This is very important as back test give you a bird eye view how you perform over longer span of time and also under different market regimes.

Closing remarks

There are many other hypothesis you can put to the test. Some of them will stand, some will fail. What you are looking for, is consistency:

If a signal loose money consistently, that’s great! As you should simply trade opposite direction.

A signal that’s not worth trading is: “Random Walks”.

So what next?

  • From sideway wedges, also sliding window’s global min/max, you can infer support and resistance levels. For example, can we hypothesis if a support level is broken (say by 1%?), we can safely assume momentum will carry us further down to next support level? Idea is many stop losses hiding a little bit below support levels?

But what played out eventual was: we bounced back to 64.5k hard and fast.

20240523 BTC
  • Can you not make more money simply arb’ing? When you arb, you long one leg and short another, risk is much lower. Why not just arb?

Question for You

Support level re-tested one, two, three times: Does it make it stronger (or weaker)? How do you back test it?

Faith shattering month of April 2024

Hours later:

Is this a dead cat bounce?

Wait is this a bull flag?! Or Descending Triangle?

The Code

“run_scenario” is the core of the back testing logic: It is where you’d find the loop that replays the candles, make entries, take profits, stop losses.

Google Colab:

Engineers

--

--