Mastering the Morning and Evening Star Candlestick Patterns
Written on
Chapter 1: Introduction to Candlestick Patterns
Candlestick patterns are essential for traders to understand, as they provide insights into market psychology. While relying solely on these patterns may lead to inconsistent results, they serve as valuable components within a broader trading strategy. In this article, we will explore the intricacies of a three-candle pattern, complete with code examples, and perform back-testing both with and without risk management to evaluate its profitability.
To enhance your trading knowledge, I have recently released a new book following the success of "New Technical Indicators in Python." This book offers a deeper exploration of complex trading strategies, accompanied by a dedicated GitHub page for updated code. For those interested, feel free to reach out on LinkedIn or check the link below.
Section 1.1: Understanding Candlestick Charts
Candlestick charts rank among the most popular methods for visually analyzing time series data. They convey more information than standard line charts and offer better interpretability than bar charts. Although numerous Python libraries exist for charting, I have created a straightforward function to manually plot candlesticks without relying on external libraries.
The OHLC data—representing Open, High, Low, and Close prices—forms the core of our analysis. Having these four values together allows for a more accurate representation of market reality. Below is a summary table for hypothetical security OHLC data.
Our goal is to visualize this data to identify price trends. We will begin by creating basic line plots before advancing to candlestick visualizations. You can either download this data manually or automate the process using Python. For those with an Excel file containing OHLC data, the following code snippet can be used for import:
import numpy as np
import pandas as pd
# Importing the Data
my_ohlc_data = pd.read_excel('my_ohlc_data.xlsx')
# Converting to Array
my_ohlc_data = np.array(my_ohlc_data)
Creating basic line plots in Python is simple and requires just a single line of code. First, ensure you have imported the matplotlib library, then call the function to plot the data.
# Importing the necessary charting library
import matplotlib.pyplot as plt
# The syntax to plot a line chart
plt.plot(my_ohlc_data, color='black', label='EURUSD')
# Adding the label created above
plt.legend()
# Adding a grid
plt.grid()
Now that we have explored how to create standard line charts, let's elevate our approach to candlestick charts. The key is to visualize vertical lines representing price movements.
The first video titled "My Morning Trading Routine For a Quick $1,750 Day" provides insights into effective trading routines and strategies that can yield significant daily returns.
Section 1.2: Constructing Candlestick Charts
To create candlestick charts without complications, consider the following steps:
- Select a lookback period, which determines how many data points to display.
- Plot vertical lines for each data point, marking the highs and lows. The vlines function in matplotlib will aid in this.
- Establish color conditions: if the closing price exceeds the opening price, apply a green color; if not, use red for bearish candles and black for Doji candles.
- Finally, plot the vertical lines using the conditions set for the minimum and maximum closing prices.
Here's an example function for generating a candlestick chart:
def ohlc_plot(Data, window, name):
Chosen = Data[-window:, ]
for i in range(len(Chosen)):
plt.vlines(x=i, ymin=Chosen[i, 2], ymax=Chosen[i, 1], color='black', linewidth=1)
if Chosen[i, 3] > Chosen[i, 0]:
color_chosen = 'green'
plt.vlines(x=i, ymin=Chosen[i, 0], ymax=Chosen[i, 3], color=color_chosen, linewidth=4)
if Chosen[i, 3] < Chosen[i, 0]:
color_chosen = 'red'
plt.vlines(x=i, ymin=Chosen[i, 3], ymax=Chosen[i, 0], color=color_chosen, linewidth=4)
if Chosen[i, 3] == Chosen[i, 0]:
color_chosen = 'black'
plt.vlines(x=i, ymin=Chosen[i, 3], ymax=Chosen[i, 0], color=color_chosen, linewidth=4)
plt.grid()
plt.title(name)
Using this function, you can visualize candlestick patterns effectively.
The Morning Star and Evening Star Patterns
The Morning Star pattern consists of three candles: a large bearish candle, followed by a small-bodied candle, and concluding with a large bullish candle. This pattern signifies a shift in market sentiment from bearish to bullish, suggesting a buying opportunity at the close of the third candle.
Conversely, the Evening Star pattern also comprises three candles: a large bullish candle, a small-bodied candle, and a final large bearish candle. This pattern indicates a sentiment shift from bullish to bearish, implying a selling opportunity at the close of the third candle.
The second video titled "Morning Flush Day Trading Strategy Explained (Gap Trading)" delves into specific strategies for day trading, particularly focusing on gap trading techniques.
Creating a Scanning Algorithm
Our next objective is to develop an algorithm that identifies these patterns and simulates buy and sell orders, allowing us to back-test the strategy. For the Morning Star pattern, we need to meet the following criteria:
- The first candle must be a large bearish candle.
- The second candle should be a small-bodied candle, preferably a Doji.
- The third candle must be a large bullish candle.
Similarly, for the Evening Star pattern, the conditions are:
- The first candle must be a large bullish candle.
- The second candle should be a small-bodied candle, ideally a Doji.
- The third candle must be a large bearish candle.
# Defining the minimum width of the first and third candles
side_body = 0.0010
# Defining the maximum width of the second candle
middle_body = 0.0003
# Signal function
def signal(Data):
for i in range(len(Data)):
# Morning Star
if Data[i - 2, 3] < Data[i - 2, 0] and (Data[i - 2, 0] - Data[i - 2, 3]) > side_body and (abs(Data[i - 1, 3] - Data[i - 1, 0])) <= middle_body and Data[i, 3] > Data[i, 0] and (Data[i, 3] - Data[i, 0]) > side_body:
Data[i, 6] = 1
# Evening Star
if Data[i - 2, 3] > Data[i - 2, 0] and (Data[i - 2, 3] - Data[i - 2, 0]) > side_body and (abs(Data[i - 1, 3] - Data[i - 1, 0])) <= middle_body and Data[i, 3] < Data[i, 0] and (Data[i, 3] - Data[i, 0]) > side_body:
Data[i, 7] = -1
This function takes an array of OHLC data and fills designated columns with signals for buying or selling based on the established criteria.
To add columns to an array, you can use the following code snippet:
def adder(Data, times):
for i in range(1, times + 1):
z = np.zeros((len(Data), 1), dtype=float)
Data = np.append(Data, z, axis=1)
return Data
# Using the function to add 10 columns
my_data = adder(my_data, 10)
If you're interested in advanced technical indicators and creating strategies with Python, my best-selling book on Technical Indicators may be of interest to you.
Chapter 2: Strategy Creation and Back-Testing
A robust research methodology involves back-testing indicators to determine their effectiveness as part of your existing trading framework. The following conditions will guide our initial strategy:
- Go long (buy) when the bullish pattern is confirmed by a buy order at the close of the third candle. Hold this position until another signal arises or risk management kicks in.
- Go short (sell) when the bearish pattern is confirmed by a sell order at the close of the third candle. Maintain this position until further signals or risk management dictates otherwise.
The equity curves generated by this strategy, without risk management, reveal valuable insights.
Incorporating a 1:5 risk-reward ratio, based on the Average True Range (ATR) indicator, yields results that remain consistent with previous interpretations.
It's important to note that utilizing this strategy independently may not yield significant value, and signals may be infrequent. In my personal experience, I tend to assign less weight to this candlestick pattern unless observed over a longer time horizon, such as weekly charts.
A Word on Risk Management
When I refer to an ATR-based risk management system, I mean that the algorithm follows specific steps regarding the position it takes.
For a long (buy) position:
- The algorithm places a buy order upon receiving a signal.
- It monitors price fluctuations, initiating a profit exit order when the high reaches a specified multiple of the ATR value at the time of the trade. A loss exit is triggered when the low meets a different multiple.
For a short (sell) position:
- The algorithm places a short sell order after generating a signal.
- It keeps track of price movements, executing a profit exit when the low reaches a specific multiple of ATR, while a loss exit is triggered at the high.
The plot below illustrates the ATR I typically use, calculated through an exponential moving average rather than the original smoothed moving average.
With the latest ATR value around 0.0014 (14 pips), a buy order can be structured as follows:
- Buy at the current market price.
- Set a take profit at the current market price + (2 x 14 pips).
- Establish a stop loss at the current market price - (1 x 14 pips).
Here's the code I use for the ATR indicator:
def ema(Data, alpha, lookback, what, where):
alpha = alpha / (lookback + 1.0)
beta = 1 - alpha
# First value is a simple SMA
Data = ma(Data, lookback, what, where)
# Calculating first EMA
Data[lookback + 1, where] = (Data[lookback + 1, what] * alpha) + (Data[lookback, where] * beta)
# Calculating the rest of EMA
for i in range(lookback + 2, len(Data)):
try:
Data[i, where] = (Data[i, what] * alpha) + (Data[i - 1, where] * beta)except IndexError:
passreturn Data
def eATR(Data, lookback, high, low, close, where):
# True Range calculation
for i in range(len(Data)):
try:
Data[i, where] = max(Data[i, high] - Data[i, low],
abs(Data[i, high] - Data[i - 1, close]),
abs(Data[i, low] - Data[i - 1, close]))
except ValueError:
pass
Data[0, where] = 0
Data = ema(Data, 2, lookback, where, where + 1)
return Data
Conclusion
As you follow my articles, you'll notice that many indicators I develop or optimize yield a high success rate on average. This is largely due to the risk management techniques I employ. However, market unpredictability often leads traders to blame technical analysis for their failures.
I regularly share my trading logs on Twitter, maintaining transparency regarding results. I never promise returns or assert exceptional skill. My indicators are tested in my personal trading, ensuring unbiased research.
Always conduct your back-tests. Despite providing functional code for indicators, remain skeptical of widely-held beliefs. My methods may work for me, but they might not suit everyone.
The key takeaway is that while market prices are challenging to predict, market reactions can often be anticipated. This understanding allows us to form educated hypotheses about potential market movements without overreaching in predictions.
In summary, the strategies outlined are realistic when the trading environment is optimized. They are intended not just for trading but also to inspire innovative trading ideas, moving beyond conventional analysis methods.