Figuring out the Hilbert transform and putting it to good use? That's one of my bucket list items!
So imagine my surprise as I was scrolling through the programming language docs and I saw not one but NINE different commands related to HT! It turned out to be both unfortunate and ironic that the manual explains the value of the Hilbert transform, yet it gives very little information on how to use those same functions. Heck, some of the entries (ht_trendmode, ht_dcperiod, ht_dcphase) don't even say what they actually do! :)
Hey, I'm not here to beat you down. HA! Honestly, I'm happy that you not only implemented these functions, but that you also bundled them into your basic install package without any special downloads, tiers, etc. But I'm going to need something more if I'm actually going to be able to use these functions. (And I can only find one trading object that even makes mention of HT.)
So, here's my big ask. And I ask not only for my own benefit, but for others:
Might I trouble you for a few programming examples? If would go a long ways if you could demonstrate the interesting things that people are able to do with the HT functions. For your consideration, here are some ideas. Mind you, I haven't given this much thought, except for the last item. I'd really be interested to see what functions are used (and how) to pull off item #3...
1. Provide information on the dominant cycle found inside a short array of asset's ticker data.
...and describe if the market is trending.
...and if so, what the trend line looks like.
...and how noisy that trend is.
2. Determine if the price series is approaching, at, or past a cycle peak.
...and estimate how many candles we'd have to wait until the next peak.
3. Advance the phase angle of a ticker data stream (perhaps 30 to 45 degrees).
...and then feed it into a complimentary tool such as RSI.
Anyhow, thanks again for including these functions. Anything you can do to further explain these functions would be really REALLY appreciated!
For those unfamiliar with the topic, we are discussing QuantShare's Hilbert Transform functions which can be used to represent a series of numbers (such as daily stock prices) as waveforms. Representing financial numbers as waveforms allows you to apply modern-day signal processing algorithms to the data, potentially offering any number of uncommon insights into financial numbers.
The Hilbert transform functions included in QuantShare are: HT_DCPERIOD, HT_DCPHASE, HT_LEADSINE, HT_PHASORPHASE, HT_PHASORQUADRATURE, HT_SINE, HT_TRENDLINE, HT_TRENDMODE, and HT_TRANSFORM.
The only Hilbert transform trading object on QuantShare (as of July, 2020) is "Stocks in UP Trend" is a Watch List by srishail. https://www.quantshare.com/item-786-stocks-in-up-trend
I've started looking at the various functions. Here's what I discovered so far:
Although not required, typical market data may benefit greatly from some *careful* data smoothing before using the functions below. I'm currently using Zlema (close,5) to smooth out the rough edges in my data set without creating any additional lag (which is important). Note: Zlema() isn't installed with QuantShare. You will find it in the download section as "Zero-Lag Exponential Moving Average" by Tom Huggens.
HT_DCPeriod (ARRAY close) - Based on your closing prices (or the array you provided), this function returns the period (length) of the most dominant waveform it detects. This period is useful to us because a number of other standard indicators operate at their very best (quicker detection, maximum gain) when set to a period that matches the length of the dominant cycle period (divided by two or by four in some cases). In the case of RSIs and stochastics, these are said to work best when set to half of the current ht_dcperiod.
Four things to keep in mind when using HT_DCPeriod:
1. Values returned by this function are NOT integers (whole numbers like 23 and 38). They are real number (like 13.42994), so some functions (indicators) may round the number up, some may round the number down, and others may simply stop working if you give them a real number for a period. It seems smarter to do any rounding yourself. My belief is that in most cases, you're going to want to round to the _closest_ number. If so, you'd might use the following functions:
period=Round (Ht_DCPeriod(),0); // Whole period.
period2=Round (Ht_DCPeriod() /2,0); // Half period. NOTE: That's TWO COMMA ZERO not TWO POINT ZERO.
period4=Round (Ht_DCPeriod() /4,0); // Quarter period.
2. The values produced by the HT_DCPeriod function are (approximately) 10 to 40. You may want to be aware of this if you're using HT_DCPeriod for other uses, or if you just wanted to know how far it could adjust the period by.
3. HT_DCPeriod does not provide a single value that describes a stock, bond, currency pair, etc. Instead, for each and every point along price series (such the daily stock chart for IBM), it provide a new value. If you were to plot HT_DCPeriod, each column should have a different value (assuming you were working with an ordinary stock price chart).
4. When given a long enough series of price data to work with, even if it is not able to detect a dominant cycle at the current position, it will pull in some of the price data that's before or after the present time in order to provide a reasonable and stable Ht_DCPeriod() value to work with.
HT_TrendMode (ARRAY close) - Uses the Hilbert Transform to determine when the provided data is in Cycle Mode (returns a 0) or Trend Mode (returns a 1). According to Ehlers, a market will switch back and forth between Trend Mode and Cycle Mode, and as it does, your tools and your trading strategy should change with it. I've noted that some algorithms disable their Hilbert Transform functions while trend mode is active.
CYCLE MODE
========
ACTIONS: Buy at the cycle valley. Sell at the cycle peak.
INDICATORS: Oscillators (RSI, Stochastics, etc)
ENDS: When actual prices deviate from predicted values
TREND MODE
=========
ACTIONS: Buy and hold when the trend is up. Sell and hold when the trend is down.
INDICATORS: Smoothing indicators (such as moving averages, parabolic SAR, etc)
ENDS: Lasts until HT_TrendLine crosses the (closing) price of the security
HT_TrendLine (ARRAY close) - Also known as the MESA Instantaneous Trendline. Appears much like a Moving Average, but with minimal lag compared to ordinary moving averages. Created by removing the Dominant Cycle (the primary sine wave detected by the Hilbert Transform) from the price series.
HT_DCPhase (ARRAY close) - Returns the phase of the dominant cycle. Output ranges from -45 to 315 (representing 360 degrees). If the actual price data matches predicted values, then the output should should be a smooth constant increase from minimum to maximum. When that doesn't happen, it is a sign that cycle mode should end and trend mode should begin. A (rapid) transition from the largest value to the smallest value is used to detect the start of a new cycle (when in cyclic mode).
HT_LeadSine (ARRAY close) - "The sine of the phase angle advanced by 45 degrees." Quoting from Market Mode Strategies.doc by John Ehlers from MESA Software, "A clear, unequivocal cycle mode indicator can be generated by plotting the Sine of the measured phase angle advanced by 45 degrees. This leading signal crosses the sinewave 1/8th of a cycle BEFORE the peaks and valleys of the cyclic turning points, enabling you to make your trading decision in time to profit from the entire amplitude swing of the cycle." This indicator by itself can be treated as an overbought/oversold indicator when above 0.85 and below -0.85.
I'd appreciate help with code that would plot a waveform from the Phase and Period of a Hilbert Transform. Anyone want to give it a shot?
How to calculate a frequency (waveform)
A = Amplitude
2*pi/B = Period
C = Phase Shift (positive is to the left)
D = Vertical Shift
x = Time since waveform began
y = A sin(B(x + C)) + D
There are numerous indicators which use the Hilbert Transform functions. This one provides access to the basic Hilbert Transform outputs (sine, leadsine, dominant cycle, and trendmode detection) along with a number of additional triggers for you to take advantage of. Don't let simple fool you. This makes some amazing predictions, especially on the 1 minute chart (the longer timeframes are increasingly less likely to remain in Cycle Mode where its predictions hold the most power; weekly charts rarely stay in Cycle Mode).
The only extra download you may need is for the Zlema() function. Search for, download, and install the "Zero-Lag Exponential Moving Average" Indicator before using the script below. If you are not able to obtain the Zlema function, there are instructions for using the Close function in its place.
When the Hilbert Transform function is active and working, it is said to be in Cycle Mode. Otherwise, when real-world data deviates significantly from the predicted values, it is said to enter Trend Mode. Trend Mode lasts until the Hilbert Transform Trendline (not plotted) crosses the Zlema() function, and then it enters back into Cycle Mode. In the chart, Cycle Mode has a white background and Trend Mode has a grey background. Cycle Mode seems to be most common on the 1m chart and least common on the weekly chart. See the HT_TrendMode description (further above) for additional information.
A pair of blue vertical lines appears thee different times in the provided screenshot. This represent the start of a new prediction by the Hilbert Transform function. A dominant cycle is said to be most accurate when it first appears. (Although you should probably check to see if the Hilbert Transform functions are in Cycle Mode before taking advantage of the latest prediction.) When the market closely follows a predicted cycle, the red and black lines will move up and down together, and the blue line will steadily proceed from the bottom of one prediction to the top of the next.
The red line (leadsine value) represents the sine of the measured phase angle which is advanced by 45 degrees. While in cycle mode, the red and black lines will typically cross 1/8th of a cycle before a peak or valley in the price of the market prices you are tracking.
The bottom center of the graph says "HILBERT TRANSFORM [15]". The number inside the brackets reports the period of the Dominant Cycle wherever the mouse last hovered over.
1. The Hilbert Transform algorithm entering and exiting Trend Mode and Cycle Mode.
2. A new dominant cycle (waveform prediction)
3. Buy/sell signals when the (black) sine and (red) leadsine curves cross.
4. Buy/sell signals when the leadsine indicator goes below -0.85 or above 0.85.
Be aware that (as with any other function), you should not take action based upon a single indicator. If you intended on using one or more of these indicators, you need to pair them with a complimentary indicator to help compensate for any problems.
// Hilbert Transform Waveforms (as popularized by John Ehlers).
// Implemented in QuantShare by Josh McCormick on July 13th, 2020.
// This formula plots the sine, leadsine, and the dominant cycle's phase.
// Injects three potential BUY indicators and three potential SELL indicators.
// Displays when the Hilbert Transform is in Trend Mode (grey background) or Cycle Mode (white background).
// Displays when a new dominant cycle has been applied (with a double vertical blue line).
// We want to smooth the closing price data with Zero-Lag Exponential Moving Average.
// Download it here: https://www.quantshare.com/item-1607-zero-lag-exponential-moving-average
// If you do not have the Zlema() function, comment out the Zlema function (two lines down).
series=close;
series=Zlema(close, 5);
// Here are the rest of the variables.
period=Round (Ht_DCPeriod(series),0); // Values are integers between 10 and 50.
period2=Round (period/2,0); // Values are integers between 5 and 25.
period4=Round (period/4,0); // Values are integers between 3 and 12.
sine = HT_Sine(series); // Values are real numbers ranging from -1 to 1.
leadsine = HT_LeadSine(series); // Values are real numbers ranging from -1 to 1.
dcphase = (Ref(HT_DCPhase(series),0)+45)*2; // Values are real numbers randing from 0 to 720 (degrees).
trendmode= HT_TrendMode(series); // Values are either 0 (false) or 1 (true).
cyclemode= 1 - trendmode; // Values are either 0 (false) or 1 (true).
newcycle0=ref(dcphase,1) > 630 and ref(dcphase,0)<90; // Values are either 0 (false) or 1 (true).
newcycle1=ref(dcphase,0) > 630 and ref(dcphase,-1)<90; // Values are either 0 (false) or 1 (true).
// Fill the entire pane (top to bottom, left to right). Put a title box at the bottom of the chart.
PrintChart("HILBERT TRANSFORM [".period."]", "", BottomCenter, colorBlack, colorBlack, colorWhite, 255);
UpdateSettings("Top-Bottom Chart Margin", 0);
SetScale (-1,1);
// It is important to know if we're in Trend Mode or Cycle Mode.
// These indicators may be considerably less reliable in Trend Mode.
// In Cycle Mode, the graph is normal (solid lines on a white background).
// In Trend Mode, the background is greyed out and the lines are lighter.
Plot1(100.5*trendmode,-100.5*trendmode,"trendmode","trendmode",colorBlack|50,colorBlack,colorBlack,ChartLine,StyleNoScale|StyleHideYAxisValue|StyleHideValues|StyleWidth2);
// This indicator predicts upturns and downturns based upon the HT_Sine and HT_LeadSine indicators crossing.
// This should be paired with other indicators. Do not use this by itself.
PlotArrow(cyclemode*(sine<0)*cross (sine,leadsine), '?SELL?', BelowLow, colorRed);
PlotArrow(cyclemode*(sine>0)*cross (sine,leadsine), '?SELL?', AboveHigh, colorRed);
PlotArrow(cyclemode*(sine>0)*cross (leadsine,sine), '?BUY?', AboveHigh, colorGreen);
PlotArrow(cyclemode*(sine<0)*cross (leadsine,sine), '?BUY?', BelowLow, colorGreen);
Plot(leadsine, "LEADSINE", colorRed, ChartLine, StyleWidth3);
UpdateColor (trendmode,colorRed|75);
Plot(sine, " SINE", colorBlack, chartLine, StyleWidth3);
UpdateColor (trendmode,colorBlack|75);
// Mark a new cycle with double blue vertical lines.
// This is a *potential* sign of an upcoming behavioral change in market prices
Plot1(1*newcycle0,-1*newcycle0,"NEW CYCLE","",colorBlue,colorGray,ColorBlue,chartbar,StyleHideValues|StyleHideYAxisValue);
Plot1(1*newcycle1,-1*newcycle1,"NEW CYCLE","",colorBlue,colorGray,ColorBlue,chartbar,StyleHideValues|StyleHideYAxisValue);
Plot(dcphase, "DCPHASE", colorBlue, chartLine, StyleWidth2|StyleOwnScale);
UpdateColor (trendmode,colorBlue|75);
// This indicator is described in the John Ehlers%u2019 book "Cycle Analytics for Traders".
// Flag "overbought" and "oversold" territories at 0.85 and -0.85.
// Should be paired with other indicators. Do not use this by itself.
PlotArrow(cross (-0.85,leadsine), '!buy!',BelowLow, colorRed);
PlotArrow(cross (leadsine,0.85), '!sell!',AboveHigh, colorGreen);
ADDITIONAL LINES TO CONSIDER ADDING TO YOUR MAIN PRICE CHART:
// Please consider copying, and pasting these lines into your main stock chart. But they're completely optional.
// Displays a zero-lag exponential moving average which (typically) connects your closing prices.
series = Zlema(close, 5);
plot(series, "Zlema", colorBlack, ChartLine, StyleDotted|StyleWidth4);
// Display the Hilbert Transform trendline (also known as the MESA Instantaneous Trendline)
// Note that Trend Mode ends and Cycle Mode begins when the trendline intersects with the zero-lag exponential moving average.
trendline = HT_TrendLine (series);
plot (trendline, "TL", colorLightBlue, chartLine, StyleWidth3|StyleDotted);
Trading financial instruments, including foreign exchange on margin, carries a high level of risk and is not suitable for all investors. The high degree of leverage can work against you as well as for you. Before deciding to invest in financial instruments or foreign exchange you should carefully consider your investment objectives, level of experience, and risk appetite. The possibility exists that you could sustain a loss of some or all of your initial investment and therefore you should not invest money that you cannot afford to lose. You should be aware of all the risks associated with trading and seek advice from an independent financial advisor if you have any doubts.