Empower Automated Stock Trading With Pattern Recognition
Empower Automated Stock Trading With Pattern Recognition
Empower Automated Stock Trading With Pattern Recognition
Chang | D…
Photo by AbsolutVision on Unsplash
During the course of developing an automated trading system, pattern recognition is one
of the most important elements. Once the system has learned to correctly identify
various patterns, more options are opened up while designing a trading strategy that
suits an individual. To enable the functionality of a trading system step by step, this
article will extend the applications of the global recursive trading pattern recognition
algorithm with channel patterns. With such an implementation or similar, a stock
trading system should be able to:
automatically label stock data with chart patterns for the machine to learn from and
eventually automatically generate trading strategies after integrating with other
elements.
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55de… 1/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
For readers who want to test the code while reading, the full code base is included near
the bottom of this article.
What are the challenges for trading systems to recognize stock trading
patterns?
When manually drawing the stock trading patterns based on a set of rules, the outcome
is never 100% objective. The rules are tweaked with human perception, as in any system.
This fact doesn’t necessarily mean the trades are negatively affected. As opposed, human
expertise in this subject increases the odds to win, on the occasion of unusual chart
patterns. However, manual creation of chart patterns imposes two challenges for the
enablement of the automation of trading systems:
More generally, batch production of stock data sets with labeled chart patterns and the
robustness of such production are two primary challenges for an automated algorithm
trading system.
On the contrary, the algorithm in this article can directly visualize chart patterns and
automatically label stock data at scale, and eventually automatically generate trading
strategies after being integrated with other components in a trading system. This
algorithm is a global recursive approach to identify trading chart patterns. In the linked
article, an implementation to visualize and label support and resistance is introduced. In
this article, the application of this algorithm will be extended to recognize channels.
1. Find the pattern on the entire data range, which is range(0, l+1)
initially, where l is the length of the data range.
2. If there are, detect the first point (P0) that breaks the global
pattern from step one. The pattern is broken whenever at least one of
the two thresholds is penetrated.
- The validity of the pattern
5. Set the new whole data range as range(Pi, l+1), repeat step two to
step five. Stop when no more breaking point is found for the whole data
range
Channels are based on parallel trending lines, i.e. parallel support and resistance
pairs
A pair of support and resistance is considered parallel if their slope difference is less
than the threshold s.
According to the definition, the first step is to find trend lines. We will modify
the trendlineSeeker class in the linked article above. The main purpose of the
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55de… 3/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
modification is to add the functionality to return both support and resistance at the same
time. Besides, it will support multiple tickers as inputs. The modified code block is
included below.
class trendlineSeeker:
def __init__(self, symbols, flag='all'):
self.symbols = symbols
self.start = '2019-08-29'
self.end = '2021-08-21'
self.validationWindowUpper = 48
self.validationWindowLower = 48
self.distortionThresholdUpper =
0.15
self.distortionThresholdLower = 0.15
if flag == 'all':
self.flag = [flag]
self.data = None
self.previousTrendlineBreakingPoint = None
self.currentTrendlineBreakingPoint = None
self.refinedTrendlines = {}
def get_data(self):
df = pd.DataFrame()
NY = 'America/New_York'
self.previousTrendlineBreakingPoint = 0
self.currentTrendlineBreakingPoint = len(self.data) + 1
def getCurrentSymbol(self):
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55de… 4/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
def getCurrentRange(self):
df = self.data.copy().loc[(self.data['row number'] >=
self.previousTrendlineBreakingPoint) & (self.data['row number'] <
self.currentTrendlineBreakingPoint), :]
return df
if flag == 'upper':
distortionThreshold = self.distortionThresholdUpper
if flag == 'lower':
distortionThreshold = self.distortionThresholdLower
possibleTrendBreakingPoints = currentdf.loc[(currentdf.loc[:,
(symbol, "close")] < (1-distortionThreshold)*(slope*currentdf['row
number'] + intercept)) | (currentdf.loc[:, (symbol, "close")] >
(1+distortionThreshold)*(slope*currentdf['row number'] + intercept)),
'row number']
return possibleTrendBreakingPoints
if flag == 'upper':
if flag == 'lower':
if flag == 'upper':
validationWindow
= self.validationWindowUpper
if flag == 'lower':
validationWindow
= self.validationWindowLower
localPossibleTrendlineBreakingPoints =
possibleTrendlineBreakingPoints
i = 1
int(localPossibleTrendlineBreakingPoints[0])
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55de… 5/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
if self.currentTrendlineBreakingPoint -
self.previousTrendlineBreakingPoint < validationWindow:
self.currentTrendlineBreakingPoint = len(self.data) + 1
- i
i += 1
currentdf = self.getCurrentRange()
localPossibleTrendlineBreakingPoints =
self.trendlineBreakingPoints(symbol, flag, currentdf, slope, intercept)
self.refinedTrendlines[symbol][flag]
[str(self.previousTrendlineBreakingPoint)] = {'slope': slope,
'intercept': intercept,'starting row':
self.previousTrendlineBreakingPoint, 'ending row':
self.currentTrendlineBreakingPoint - 1}
self.previousTrendlineBreakingPoint =
self.currentTrendlineBreakingPoint
self.currentTrendlineBreakingPoint = len(self.data) + 1
def vizTrend(self):
pltCount = 0
tempAxis.plot(self.data.index,self.data.loc[:,
(symbol, "close")], label=f'{symbol} price action')
tempAxis.plot(
self.data.index.values[trendline['starting row']:trendline['ending
row']],trendline['slope']*self.data['row number'][trendline['starting
row']:trendline['ending row']] + trendline['intercept'],
label=f'{self.data.index.values[trendline["starting row"]]}-
{self.data.index.values[trendline["ending row"]-1]}')
pltCount += 1
plt.show()
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55de… 6/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
self.get_data()
self.refinedTrendlines[symbol] = {}
self.refinedTrendlines[symbol][flag] = {}
while True:
currentRange = self.getCurrentRange()
trendline = self.trendlineForCurrentRange(symbol,
flag, currentRange)
possibleTrendlineBreakingPoints =
self.trendlineBreakingPoints(symbol, flag, currentRange, *trendline)
if len(possibleTrendlineBreakingPoints) == 0:
self.refinedTrendlines[symbol][flag]
else:
self.refineTrendlineForCurrentRange(symbol,
flag, possibleTrendlineBreakingPoints)
self.previousTrendlineBreakingPoint = 0
self.currentTrendlineBreakingPoint = len(self.data) + 1
if viz: self.vizTrend()
The following channelSeeker class inherits the attributes from trendlineSeeker to return
all support and resistance trendlines. In the demo, the threshold s in the definition for
channel pattern above is self.slopeDiffThreshold = 8*math.pi/180 . And the channel
breaking signal p is self.channelBreakingThreshold = 0.1 . Therefore, when a pair of
support and resistance trends has slopes with less than 8 degrees difference and no
ticker point is above or below the current channel range, a channel is recorded and
visualized.
class channelSeeker(trendlineSeeker):
self.slopeDiffThreshold = 8*math.pi/180
self.channelBreakingThreshold = 0.1
self.channels = {}
trendlines = self.refinedTrendlines
upperTrends = trendlines[symbol]['upper']
lowerTrends = trendlines[symbol]['lower']
if (np.abs(uSlope-lSlope) <
self.slopeDiffThreshold) and (uIntercept-lIntercept > 0) and
range(max(uStart, lStart), min(uEnd, lEnd)+1):
upperViolation =
self.channelBreakingPoints(symbol, uSlope, uIntercept, start, end,
self.channelBreakingThreshold, flag='upper')
lowerViolation =
if upperViolation.any() or lowerViolation.any():
continue
else:
channelId = f'{start}'
self.channels[symbol][channelId] = {}
self.channels[symbol][channelId]['start'] =
start
self.channels[symbol][channelId]['end'] =
end
self.channels[symbol][channelId]
['slopeUpper'] = uSlope
self.channels[symbol][channelId]
['slopeLower'] = lSlope
self.channels[symbol][channelId]
['interceptUpper'] = uIntercept
self.channels[symbol][channelId]
['interceptLower'] = lIntercept
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55de… 8/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
else:
continue
if viz == True:
print(self.channels)
self.vizChannel()
if flag == 'upper':
violationCondition = self.data.loc[:,
(symbol,'close')].iloc[start:end] > (1 + tolerance)*
(slope*self.data['row number'].iloc[start:end]+1.0*intercept)
if flag == 'lower':
violationCondition = self.data.loc[:,
(symbol,'close')].iloc[start:end] < (1 - tolerance)*
(slope*self.data['row number'].iloc[start:end]+1.0*intercept)
def vizChannel(self):
pltCount = 0
tempAxis.plot(self.data.index,self.data.loc[:, (symbol,
"close")], label=f'{symbol} price action')
self.data.index.values[channelProperties['start']:channelProperties['end']
channelProperties['slopeUpper']*self.data['row number']
[channelProperties['start']:channelProperties['end']] +
channelProperties['interceptUpper'])
tempAxis.plot(
self.data.index.values[channelProperties['start']:channelProperties['end']
number'][channelProperties['start']:channelProperties['end']] +
channelProperties['interceptLower'])
pltCount += 1
plt.show()
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55de… 9/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
For the sake of completeness, the fully functional code structure, including the
modified trendlineSeeker class is included below.
import math
import pandas as pd
import numpy as np
class trendlineSeeker:
...
class channelSeeker:
...
if __name__ == '__main__':
# ts = trendlineSeeker(['AAPL'], flag='all')
# ts.runTrendlineSeeker(viz = True)
cs = channelSeeker(['AAPL'])
cs.runChannelSeeker(viz=True)
Sample records as the output of previous code will be in the following format.
AAPL channel with channel breaking threshold = 10%, slope divergence threshold = 8˚
Please note that the recognized channels changes along with the parameters in the
generalized definition of trend and channel patterns. After adding more relaxations, i.e.
increasing the thresholds distortionThresholdUpper -> 0.20, s -> 15*math.pi/180, p ->
0.2 , more support and resistance pairs meet the criteria as shown below.
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55d… 11/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
AAPL channel with channel breaking threshold = 20%, slope divergence threshold = 15˚
Conclusion
This application of the recursive global approach is able to capture significant channels
in trading data. With a different set of thresholds, certain channels will be included or
excluded. Since the outputs of this application can be used further as inputs of another
learning algorithm, these thresholds can be optimized as parameters while training these
learning algorithms.
The major advantage of this application is the inherited recursiveness from the algorithm
and the added objectiveness while defining the channel pattern. They help tackle the
aforementioned two major challenges, i.e. data set generation and human biases in data
set.
The main disadvantage would be the lacking of human expertise on special occasions. In
a real-world scenario, this could mean slightly lower trading frequency or a few trades
less. However, this is not necessarily negative on the trading result since this
disadvantage, on the other side, means only patterns within control are captured and
considered in a trading strategy. Also combining multiple patterns or with indicators can
be a mediation.
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55d… 12/13
2/4/22, 3:08 PM Empower automated stock trading with pattern recognition — Identify channels with a recursive algorithm | by J. K. Chang | D…
Endnote
Trendlines and channels are just two types among all patterns. Moreover, pattern
recognition is merely one of many options/indications while creating a trading strategy.
Long story short, quite a journey ahead towards an automated trading system.
In my next article, instead of bumping into more technical details in patterns, indicators
or system software development, I will first write a guideline for designing a trading
system. It will introduce all the elements in an automated trading system and how they
are integrated together for designing trading strategies.
If you have any questions or any specific topics in your mind, feel free to leave a
comment.
https://medium.datadriveninvestor.com/empower-automated-stock-trading-with-pattern-recognition-identify-channels-with-a-recursive-algo-55d… 13/13