A Comprehensive Guide to a New Volatility Trading Strategy
Written on
Understanding the Essentials of Trading
Trading encompasses a blend of research, execution, risk management, and performance assessment. The majority of our efforts focus on the initial two aspects: identifying and applying a profitable strategy. This article introduces a risk indicator designed to also generate trading signals.
Following the success of my previous publication, I've released a new book that explores advanced trend-following indicators and strategies. The book includes a dedicated GitHub page for constantly updated code and features original colors optimized for print. If this piques your interest, check out the Amazon link below, or contact me via LinkedIn for a PDF version.
Introduction to Volatility
To grasp the concept of Pure Pupil Volatility, it's crucial to first understand volatility itself, a fundamental notion in finance that provides a significant advantage in the markets. However, accurately measuring and forecasting volatility can be challenging. While it's particularly vital in options trading, its importance spans various trading domains. Traders rely on volatility to execute trades and manage risks, while quantitative analysts and risk managers depend on it to perform their analyses.
To illustrate the concept of volatility, consider the graph below that compares a high volatility simulated time series with a low volatility one.
You can create this visual representation in Python using the following code snippet:
# Importing the necessary libraries
import numpy as np
import matplotlib.pyplot as plt
# Creating high volatility noise
hv_noise = np.random.normal(0, 1, 250)
# Creating low volatility noise
lv_noise = np.random.normal(0, 0.1, 250)
# Plotting
plt.plot(hv_noise, color='red', linewidth=1.5, label='High Volatility')
plt.plot(lv_noise, color='green', linewidth=1.5, label='Low Volatility')
plt.axhline(y=0, color='black', linewidth=1)
plt.grid()
plt.legend()
The different categories of volatility include:
- Historical Volatility: The realized volatility over a specific time frame. Although it's retrospective, it frequently serves as a predictor for future volatility.
- Implied Volatility: Defined simply, it's the measure that, when used in the Black-Scholes equation, provides the market price of an option. It reflects the anticipated future volatility as perceived by market participants.
- Forward Volatility: This refers to volatility expected over a defined future period.
- Actual Volatility: The current level of volatility, also known as local volatility, which is often complex to calculate and lacks a specific time frame.
The most fundamental form of volatility is the "Standard Deviation," a cornerstone of descriptive statistics and a key element in several technical indicators, including Bollinger Bands. To grasp the concept of standard deviation, we first need to define variance:
Variance is the square of the deviations from the mean (a measure of dispersion). By squaring the deviations, we ensure that the distances from the mean remain non-negative. The final step involves taking the square root to align the measure with the mean's units, facilitating direct comparisons.
In simplified terms, the Standard Deviation represents the average distance from the mean that we expect to observe in a time series analysis.
Creating the Pure Pupil Volatility Indicator
The Pure Pupil Volatility Indicator (PPVI) is a straightforward tool that utilizes standard deviation to gauge fluctuations while maximizing the use of available data. It is typically applied using a rolling window of three periods. Here are the steps to construct the indicator:
- Calculate a rolling 3-period standard deviation on the Highs.
- Calculate a rolling 3-period standard deviation on the Lows.
- Determine the rolling 3-period maximum values based on step one.
- Determine the rolling 3-period maximum values based on step two.
The PPVI consists of two lines: one for upside volatility and the other for downside volatility. The accompanying plot illustrates that while these lines are correlated, they differ, as they assume that volatility behaves differently in rising and falling markets.
In the plot, the blue line indicates volatility related to Highs, while the red line represents Lows. To create the indicator, you need OHLC data arranged in an array, and you can implement it using the following code snippet:
def adder(Data, times):
for i in range(1, times + 1):
new = np.zeros((len(Data), 1), dtype=float)
Data = np.append(Data, new, axis=1)
return Data
def deleter(Data, index, times):
for i in range(1, times + 1):
Data = np.delete(Data, index, axis=1)return Data
def jump(Data, jump):
Data = Data[jump:, ]
return Data
def volatility(Data, lookback, what, where):
Data = adder(Data, 1)
for i in range(len(Data)):
try:
Data[i, where] = (Data[i - lookback + 1:i + 1, what].std())except IndexError:
passData = jump(Data, lookback)
return Data
def ma(Data, lookback, close, where):
Data = adder(Data, 1)
for i in range(len(Data)):
try:
Data[i, where] = (Data[i - lookback + 1:i + 1, close].mean())except IndexError:
passData = jump(Data, lookback)
return Data
def pure_pupil(Data, lookback, high, low, where):
Data = volatility(Data, lookback, high, where)
Data = volatility(Data, lookback, low, where + 1)
for i in range(len(Data)):
try:
Data[i, where + 2] = max(Data[i - lookback + 1:i + 1, where])except ValueError:
passfor i in range(len(Data)):
try:
Data[i, where + 3] = max(Data[i - lookback + 1:i + 1, where + 1])except ValueError:
passData = deleter(Data, where, 2)
return Data
The indicator can be effectively utilized for risk management or as part of a broader trading strategy, as discussed in the following section. For risk management, the blue line can serve as a stop-loss level for short trades, while the red line can act as a stop-loss for long trades, representing a method of volatility optimization.
If you are interested in exploring more technical indicators and strategies, consider my book titled "The Pure Pupil Volatility Bands Strategy."
Creating the Pure Pupil Bands
Inspired by Bollinger Bands, the Pure Pupil Bands is a volatility indicator designed to function similarly. To create the Pure Pupil Bands, follow these steps:
- Calculate a 3-period simple moving average of the market price.
- Add the result from step one to the PPVI high values multiplied by two.
- Subtract the result from step one from the PPVI low values multiplied by two.
This will yield bands that envelop prices akin to Bollinger Bands.
def pure_pupil_bands(Data, close, where):
Data = ma(Data, lookback, close, where)
Data[:, where + 1] = Data[:, where] + (2 * Data[:, 4])
Data[:, where + 2] = Data[:, where] - (2 * Data[:, 5])
Data = deleter(Data, 4, 3)
return Data
The trading conditions are straightforward: go long (buy) when the market closes at or below the lower band and short (sell) when it closes at or above the upper band.
To implement the signal function, you can use the following code:
def signal(Data, close, upper_band, lower_band, buy, sell):
for i in range(len(Data)):
if Data[i, close] < Data[i, lower_band] and Data[i - 1, close] > Data[i - 1, lower_band]:
Data[i, buy] = 1if Data[i, close] > Data[i, upper_band] and Data[i - 1, close] < Data[i - 1, upper_band]:
Data[i, sell] = -1return Data
To visualize the signals, the following function can be used:
def ohlc_plot_candles(Data, window):
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=3)
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=3)
if Chosen[i, 3] == Chosen[i, 0]:
color_chosen = 'black'
plt.vlines(x=i, ymin=Chosen[i, 3], ymax=Chosen[i, 0] + 0.00001, color=color_chosen, linewidth=6)
plt.grid()
Using the signal_chart function, you can create a visual representation of the trading signals:
def signal_chart(Data, close, what_bull, what_bear, window=500):
Plottable = Data[-window:, ]
fig, ax = plt.subplots(figsize=(10, 5))
ohlc_plot_candles(Data, window)
for i in range(len(Plottable)):
if Plottable[i, what_bull] == 1:
x = i
y = Plottable[i, close]
ax.annotate(' ', xy=(x, y),
arrowprops=dict(width=9, headlength=11, headwidth=11, facecolor='green', color='green'))elif Plottable[i, what_bear] == -1:
x = i
y = Plottable[i, close]
ax.annotate(' ', xy=(x, y),
arrowprops=dict(width=9, headlength=-11, headwidth=-11, facecolor='red', color='red'))
If you're interested in further articles related to trading strategies, consider subscribing to my DAILY Newsletter. This free plan offers access to my Medium articles, additional trading strategies, coding lessons, and a complimentary PDF copy of my first book. Expect 5–7 articles weekly with a paid subscription and 1–2 with the free plan.
Evaluating the Trading Strategy
With the signal generation complete, we can now approximate how the algorithm would have executed buy and sell orders, allowing us to simulate its historical performance without hindsight bias. This process involves calculating returns and analyzing performance metrics, starting with the Signal Quality metric.
Signal quality measures market reaction after a specified time following a signal, resembling a fixed holding period strategy. It assesses market timing by comparing the market level at a given time point with the entry level.
# Choosing a Holding Period for a trend-following strategy
period = 2
def signal_quality(Data, closing, buy, sell, period, where):
Data = adder(Data, 1)
for i in range(len(Data)):
try:
if Data[i, buy] == 1:
Data[i + period, where] = Data[i + period, closing] - Data[i, closing]if Data[i, sell] == -1:
Data[i + period, where] = Data[i, closing] - Data[i + period, closing]except IndexError:
passreturn Data
# Applying the Signal Quality Function
my_data = signal_quality(my_data, 3, 6, 7, period, 8)
positives = my_data[my_data[:, 8] > 0]
negatives = my_data[my_data[:, 8] < 0]
# Calculating Signal Quality
signal_quality = len(positives) / (len(negatives) + len(positives))
print('Signal Quality = ', round(signal_quality * 100, 2), '%')
A signal quality of 56.61% indicates that out of 100 trades, a profitable outcome can be expected in 56 of those instances, excluding transaction costs. Always conduct thorough back-testing and trust your analysis, as strategies may not work universally for everyone.
Final Thoughts
Recently, I've embarked on an NFT collection aimed at supporting various humanitarian and medical initiatives. The Society of Light features limited collectibles, with a portion of each sale directed to the associated charity. Here are some benefits of purchasing these NFTs:
- High-potential gain: By focusing on marketing and promoting The Society of Light, I aim to maximize their secondary market value.
- Art collection and portfolio diversification: Owning avatars that symbolize good deeds is rewarding. Investing can combine profit with altruism.
- Flexible charitable giving: Allocate funds to your preferred causes.
- Free book offer: Buyers of any NFT will receive a complimentary copy of my latest book.
To support this cause against Polio, click here to buy Angelique.