Detecting Consolidation Ranges with Price Extremes and Trend Lines
Summary
The discussion considers how to identify a sideways price range that follows an upward move using OHLC data. One proposed geometric method first marks local highs and lows over a chosen time scale, then connects extrema with lines that do not cross the observed price path. Candidate lines can be compared by their angles and shared supporting points; combinations of upper and lower lines can then describe chart structures such as channels or triangles. The answer also suggests representing patterns through combinations of line features, while another response points to matrix flag labeling as an alternative framework.
The approach is a conceptual direction rather than a tested detector or ready-to-use implementation. It depends on choices such as the time scale, what counts as a local extreme, and the tolerance for treating line angles as similar. The contributor notes that realistic thresholds are difficult to set, and the thread offers no performance evaluation or evidence that detected formations predict future returns.
Key ideas
- Mark local price highs and lows at a selected time scale to generate candidate pattern points.
- Connect extrema with lines that stay on the appropriate side of the price path.
- Use line angles, shared extrema, and supporting points to identify possible boundaries and formations.
- Combine upper and lower boundary lines to describe structures such as ranges or triangles.
- Detection depends on threshold choices and requires validation before use as a trading signal.
Tags
Full text
# Detect pattern from OHLC data in Python
# Detect pattern from OHLC data in Python
I'm trying to create a script that, from standard OHLC data, finds patterns. The specific pattern i'm looking for right now is sideways movement after a move up, here is an example:
So basically my code should detect when price is inside a box like the ones above.
I know this is not easy to do and i'm not looking for someone to give their code, i just need some help finding a general direction or some sources/library on this matter, if there is any.
My idea was the following: detect when price is rising, and if price, after rising, starts moving between an X and Y interval (so without going too much up or down), label it as a range (which is what i'm looking for). I think this should work, but i have no idea how to put that down in code.
Here is what i have:
```
import copy
import urllib
import numpy as np
import pandas as pd
import cfscrape
import json
import datetime
from datetime import datetime as dt
BU = cfscrape.create_scraper()
URL = "https://api.binance.com/api/v1/klines?&symbol=ADABTC&interval=1h&limit=250"
ResultRaw = BU.get(URL, timeout=(10, 15)).content
Result = json.loads(ResultRaw)
for x in Result:
TimeUnix = float(x[0]) / float(1000)
K = datetime.datetime.fromtimestamp(TimeUnix)
x[0] = K
Variation = Result.index(x)
Previous = Variation-1
Variation = ((float(x[4])-float(x[1]))/float(x[1]))*100
print(Variation)
df = pd.DataFrame([x[:6] for x in Result],
columns=['Date', 'Open', 'High', 'Low', 'Close', 'Volume'])
format = '%Y-%m-%d %H:%M:%S'
df['Date'] = pd.to_datetime(df['Date'], format=format)
df = df.set_index(pd.DatetimeIndex(df['Date']))
df["Open"] = pd.to_numeric(df["Open"],errors='coerce')
df["High"] = pd.to_numeric(df["High"],errors='coerce')
df["Low"] = pd.to_numeric(df["Low"],errors='coerce')
df["Close"] = pd.to_numeric(df["Close"],errors='coerce')
df["Volume"] = pd.to_numeric(df["Volume"],errors='coerce')
```
Here is what i'm doing:
- Retrieve data
- Make it JSON data
- For every row, determine how much the price changed in terms of percentage, this is what `Variation` does
- Make it a Pandas dataframe
Any kind of help is appreciated!
## Answer by lehalle (score 9, accepted)
https://quant.stackexchange.com/a/55463
As far as I know there is no library. With some other researchers, we implemented this 20 years ago in scheme (yes, it was long ago, when Lisp, and not python, was the language of AI).
Our methodology (that was really fast), was the following
- you need a time scale, one week for instance
- mark all the local minima and local maxima at the time scale
- now you need to form lines passing by two of them and not crossing the "price line", if you think a little bit about it; to be efficient you can only join local minima together of local maxima together, hence you need one code that you can run twice, once you "inverted" the price (ie $\times (-1)$). once you detect that the line linking $m_i$ to $m_j$ crosses the "price line", you can remove from your list a lot of $m_k$ where $k>j$ if they are above the $[m_i,m_j)$ line
- now you have a collection of lines linking two (not mandatorily consecutive) local minima $(m_i,m_j)$ together, you "just" have to have the angle with the horizontal axe of each line check that lines having one local minimum in common have the "same angle" (you need a threshold to make two angles different; if you want to be realistic, computing the correct threshold is tricky) now you have a list of lines containing 3 local minima you can iterate
- at the stage you have a large collection of lines, characterized by a starting point and a stopping point (where they cross the line of price or one local extremum) its angle with the $x$ axis its number of "supporting points" (note that if you have 3 "aligned points", you have 3 different lines: 2 with 2 points and one with 3 points)
- you need to write a "regex" language to create combination of such lines, like an open triangle is: one upper line and one lower line, with a positive open angle, spanning the at least 3 dates in common a head-and-shoulders is made of three lines: two upper (resp. lower) lines with "almost symmetric" angles and an "almost horizontal" lower (resp. upper) line, spanning at least 5 dates in common
If you implement it, please send me a copy of your code ;{)}
[EDIT] It seems that there is a medium post, pointing on a quantopian code, that is very close to my description. Nevertheless, the code seems to be very poor.
For instance, here is one line of code to find local maxima (60 days) in pandas:
`prices.iloc[np.where((prices.rolling(60,center=True).max()==prices).values)[0],:]`
Whereas in the quantopian code they have 20 complex lines of code (should be 2 since they do min and max). My advice is to reimplement, frankly it is not that complex.
## Answer by Jacques Joubert (score 2)
https://quant.stackexchange.com/a/55557
Could you possibly use the matrix flag labelling technique? The following provides some documentation and you can always design your own custom flags.
I think it will be a good tool to investigate: https://mlfinlab.readthedocs.io/en/latest/labeling/labeling_matrix_flags.htmlShown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.