Understanding Market Gaps and Trading in Python
Written on
Chapter 1: Introduction to Market Gaps
Market gaps play a crucial role in the dynamics of price movements. Their frequency can vary significantly across different markets. For example, in the foreign exchange market, gaps often appear at the start of trading after weekends or following major news announcements. In contrast, stock markets typically experience gaps more frequently from day to day. This article will delve into various types of market gaps and illustrate how to create a Python scanner that detects them, employing the established trading strategy of "filling the gaps."
I recently published a new book following the success of my previous release. It includes sophisticated trend-following indicators and strategies, along with a GitHub repository for ongoing code updates. Additionally, this new edition features original colors optimized for printing costs. If this topic piques your interest, feel free to check out the Amazon link below, or reach out to me on LinkedIn if you prefer the PDF version.
Chapter 1.1: Understanding Gaps
A market gap refers to a discontinuity in price levels. For instance, if a market is trading at $100 and suddenly jumps to $102 without any trades at $101, a gap is created. This phenomenon is visually represented in charts as empty spaces between candlesticks. Observe the chart below for GBPUSD, highlighting the gap in gray between two candlesticks.
Gaps can arise from both fundamental and technical factors, but our primary focus will be on recognizing and trading these gaps. In the forex market, the most noticeable gaps typically occur during weekends. Although the market operates continuously for five days, these gaps can appear as substantial candlesticks on charts, but we will adhere to the conventional definition of gaps.
We refer to trading strategies based on gaps as "Playing the Gap."
Types of Gaps
Distinguishing between the different types of gaps can be challenging:
- Common Gap: Usually occurs in sideways markets and is likely to be filled due to the market's tendency to revert to the mean.
- Breakaway Gap: Similar to a common gap but occurs above a resistance level or below a support level, indicating a new trend's acceleration.
- Runaway Gap: Appears during a trend, reinforcing it as a continuation pattern.
- Exhaustion Gap: Typically found at the end of a trend near support or resistance levels, suggesting a potential reversal.
It’s important to note that personal experience informs many of these definitions; some sources argue that common gaps are the least likely to be filled. Additionally, the similarities between runaway and exhaustion gaps can lead to hindsight bias, making them hard to differentiate at the moment they occur.
Chapter 1.2: Analyzing Gaps in GBPUSD
The chart below illustrates a breakaway gap on GBPUSD, which emerged after a bullish triple bottom reversal pattern and surpassing a resistance level, suggesting the likelihood of continued upward movement.
In this article, we will assume that all gaps should be filled, treating all detected gaps as common gaps. Several theories exist regarding why gaps tend to fill:
- A reaction driven by excessive optimism or pessimism can lead traders to counteract the gap, a phenomenon known as Irrational Exuberance, first articulated by Alan Greenspan.
- Gaps that form near support or resistance levels may prompt a reversal.
Chapter 2: Developing a Gap Scanner
Just as humans can visually detect common gaps, we can create a recursive algorithm in Python to automate this process. Our focus will be on hourly data from 2010 onward. One critical variable for our scanner is the width of the gap.
Defining the Width
The width variable sets the threshold for what constitutes a gap. In hourly forex data, a gap of 1 or 2 pips may not be significant, so we will define a minimum gap of 5 pips for trading purposes. Considering a spread of 0.2, the maximum profit on an EURUSD trade would be 4.8 pips, or $4.8 on a mini lot account with 1:100 leverage. This profit estimate assumes our target is to fill the gap, meaning if we identify a 5 pip gap, we can anticipate a gain of 4.8 pips after accounting for the spread.
Here’s the scanner function:
width = 0.0005 # 5 pips Gap example for Hourly OHLC data
def signal(Data, opening, close, width, buy, sell):
for i in range(len(Data)):
if Data[i, opening] < Data[i - 1, close] and abs(Data[i, opening] - Data[i - 1, close]) >= width:
Data[i, buy] = 1
if Data[i, opening] > Data[i - 1, close] and abs(Data[i, opening] - Data[i - 1, close]) >= width:
Data[i, sell] = -1
return Data
Explanation of the Signal Function
The signal function considers four variables:
- Data: The OHLC time series in array form, ideally a numpy array.
- closing: The column holding the closing price (C in OHLC).
- opening: The column holding the opening price (O in OHLC).
- width: The minimum distance between the closing price and the new opening price to qualify as a gap.
- buy and sell: The columns for buy and sell orders, with 1 indicating a buy trigger and -1 indicating a sell trigger.
If you are interested in more technical indicators and strategies, my book might be of interest.
Back-Testing the Strategy
Now, it's time to back-test this strategy to assess the predictability of pure gap trading. The trading rules are as follows:
- Long (Buy): Enter when a bullish gap is detected—this is a gap down anticipated to fill upwards when the market high reaches the low of the preceding candle.
- Short (Sell): Enter when a bearish gap is identified—a gap up expected to fill downwards when the market low reaches the high of the preceding candle.
- Trades are opened and closed either upon filling the gap or at the next signal.
The following illustrations demonstrate scenarios where gaps need to be filled, guiding the decision to sell or buy based on the opening price's relation to previous closing prices.
The first video, "Gap Trading [1/4] Python Gap Scanner and mplfinance," provides a comprehensive overview of the gap trading approach, including practical coding examples for implementing a gap scanner in Python.
Signal Quality Assessment
The following function evaluates the quality of signals generated by our strategy:
def signal_quality(Data, buy, sell, where):
for i in range(len(Data)):
try:
if Data[i, buy] == 1:
for a in range(i, len(Data)):
if Data[a, 1] >= Data[i - 1, 2]:
Data[a, where] = Data[i - 1, 2] - Data[i, 0]
break
elif Data[a, sell] == -1:
Data[a, where] = Data[a, 0] - Data[i, 0]
break
elif Data[i, sell] == -1:
for a in range(i, len(Data)):
if Data[a, 2] <= Data[i - 1, 1]:
Data[a, where] = Data[i, 0] - Data[i - 1, 1]
break
elif Data[a, buy] == 1:
Data[a, where] = Data[i, 0] - Data[a, 0]
break
except IndexError:
pass
return Data
Next, we apply the signal quality function to our data to assess the positive and negative outcomes of our trades.
my_data = signal_quality(my_data, 6, 7, 8)
positives = my_data[my_data[:, 8] > 0]
negatives = my_data[my_data[:, 8] < 0]
signal_quality = len(positives) / (len(negatives) + len(positives))
print('Signal Quality = ', round(signal_quality * 100, 2), '%')
Some markets exhibit a higher frequency of gaps, which can be leveraged through more intricate strategies.
The second video, "Detecting Price Trends in Python - Higher Highs, Higher Lows," dives into the nuances of identifying price trends, enhancing your understanding of market movements.
Conclusion and Final Thoughts
While the signal quality metrics provided should not be interpreted as guarantees of profitability, they offer insights into the potential effectiveness of the gap trading strategy. It’s essential to conduct thorough back-tests before implementing any trading strategy live.
I advocate for self-discovery in trading; understanding the underlying concepts and creating your own strategies is vital. My refusal to present specific back-testing results encourages readers to explore and refine their own methods.
An Invitation to Make a Difference
I have recently launched an NFT collection aimed at supporting various humanitarian and medical causes. "The Society of Light" consists of limited-edition collectibles, with a portion of each sale directly benefiting charitable organizations associated with the avatar.
- High-Potential Gains: By focusing on marketing for "The Society of Light," I aim to enhance their value in secondary markets, with a portion of royalties also going to charity.
- Art Collection and Portfolio Diversification: Owning avatars that symbolize positive contributions is rewarding. Investing can align with altruistic goals.
- Flexible Donations: This offers a way to allocate funds to various charities.
- Complimentary Book: Each NFT purchase includes a free PDF copy of my latest book.
Click here to buy the Unnamed NFT and support the cause of providing water access to those in need.