Adaptive Cycle Toolkit (ACT) - Indicator Primer ACT is Metastock on high-energy. It places powerful, adaptive experts and indicators within the simple, intuitive Metastock framework. They rapidly adjust to the speed and noise of the market s trends, cycles and drift, helping an analyst quickly assess market conditions. Applying them, a trader may: Identify trends quickly. Know when the market is cycling. Know when the market is noisy, and perhaps stand aside. Pinpoint extreme prices with the Fisher transform These techniques are based on the research of noted quantitative analyst and author, John Ehlers. ACT achieves these results because its methods are dynamic. They are based on sound concepts derived from signal processing mathematics. Traditionally, Metastock tools have accepted only static inputs. Markets are not static. ACT s methods to identify trends and cycles: Are among the most responsive techniques available, period, Have the same intuitive Excel-like feel and use of Metastock formulas, Allow complex adaptive indicators to be built by simply stacking functions - an easy to learn Lego block approach to building advanced custom indicators, Process very fast under demanding real-time situations. ACT is easy to use. You don t need to: work for NASA to apply these techniques, learn a complex programming language, convert to an expensive lease product from a competitor to achieve most, if not all, of these benefits. ACT is meant for the novice and advanced traders. Novice traders may apply the power of adaptive experts and methods quickly and effortlessly, Advanced traders may create and test complex adaptive methods quickly while limiting or eliminating the need for programming assistance. As your experience grows, ACT supports your growth.
Basic Concepts: Markets change quickly. Adapting to these changes can be critical to you as a trader. Many traders believe signal processing techniques hold part of the answer. Several trading experts have developed such techniques from the following basic model: Price = Trend Content + Cycle Content. If Cycle Length can be accurately measured from Cycle Content, they believe the Cycle Length can be used as a period input to make indicators more accurately measure market conditions. An analyst can use this concept to create adaptive indicators for a single time scale, apply it to create adaptive long term filters of short-term indicators, or both. ACT has two methods for rapidly measuring cycle length: the Homodyne method, and the Cybernetic method. The Homodyne method is responsive and smooth. The Cybernetic method is more responsive, but not as smooth. In fact, it may be the most responsive method available to measure cycle length. Either method provides a cycle period length that is measured at each price bar, and may be used to make ACT s experts and indicators adaptive. Please note: the cycle length measured at each price bar may change. However, ACT does not retroactively recalculate each indicator (the LastValue function in Metastock s function list does retroactively recalculate). Instead, ACT maintains the history of each price bar s indicator calculation based on the cycle length measured at that bar. The current cycle length is only applied to indicator calculations for the current bar. This approach maintains the dynamic history of each indicator. Otherwise, we would be recalculating the history of an indicator with 20/20 hindsight. Homodyne Period: The Homodyne method only requires the choice of price input for cycle measurement (i.e., median price, close, etc.) to compute the cycle length. Cybernetic Period: The Cybernetic method requires some insight, but is easy to apply with a little effort. It is worth the effort because it is extremely responsive to rapidly changing market conditions. Here are the basic ideas behind the inputs: Function Name: Cybernetic Cycle Period Format: ExtFml( "ADSI.CyberCyclePeriod", Prices, alphas, deltaphaselows, deltaphasehighs) Input 1: Prices. (suggested input is Median Price)
Input 2: alphas. The alpha factor "cuts off" the frequencies which are extracted from price for measuring the cycle content. (recall: Price = Trend Content + Cycle Content). Cycle content is used to measure cycle length. Higher frequencies are associated with shorter cycle lengths. The higher the alpha, the higher the frequencies used for cycle measurement. An alpha of 0.18 considers frequencies at about a cycle length of 11 & above. An alpha of 0.09 considers frequencies at about a cycle length of 22 & above. An alpha of.07 considers frequencies at about a cycle length of 28 & above, and so on. (See Alpha Conversion Table attached for an explanation of how alphas are related to length). The variable is range bound between 0.0 and 1.0. An alpha of.18 does not necessarily equal a cycle of 11 bars. An alpha of.09 does not necessarily equal a cycle of 22 bars, and so on for other alphas. It would be true only if the cycle content exactly equaled the content for a pure cycle of that length (e.g., if the cycle content in a price series using an alpha cutoff of.18 exactly equaled the cycle content for a pure 11 bar cycle). It may not, and probably does not. In the case of this alpha =.18, the extracted content may equal that of an 11 bar cycle or longer. The alpha simply limits the content measured. The Cybernetic Cycle Period uses this output to determine the number of times the content rotates through a trigonometric circle. (the angle in a cycle rotates 360 degrees each time a cycle is completed.) This measures the cycle length. Input 3: DeltaPhaseLows. (suggested input 0.10) This is a value (in radians) that determines the an upper bound for the period length. A lower value allows longer cycles to be measured. For example, a value of 0.1 only allows cycles shorter than about 60 bars to be measured. First, a little math refresher: a circle has 2pi units (radians) in it. Since pi equals 3.14, 2pi equals 6.28. A six bar cycle will rotate through 2pi ten times as fast as a 60 bar cycle (fewer price bars are required to complete a shorter cycle). Thus, if we divide 6.28 by 6, we get approximately 1.05. If we divide 6.28 by 60, we get 0.10. This lower DeltaPhaseLow just sets an artificial limit on the longest cycle we let our technique measure. In this case, if the cycle length measured were higher than 60, the 0.10 limit would set the cycle length to equal 60. If a user preferred to allow the longest cycle lengths measured to be longer (assuming a longer cycle actually existed in the data), they could adjust this. For example, using a factor of.0785 (6.28/80) would allow a maximum cycle length of 80 to be measured
from the cycle content. Understand, if the cycle content did not contain a cycle as long as 80 bars, the cycle length would be the length measured, not 80. Alternatively, if a user preferred to allow the longest cycle lengths measured to be shorter (assuming a shorter cycle actually existed in the data), they could adjust this. For example, using a factor of.157 (6.28/40) would allow a maximum cycle length of 40 to be measured from the cycle content. In this case, if the cycle length measured were higher than 40, the 0.157 limit would set the cycle length to equal 40. Understand, if the cycle content did not contain a cycle as long as 40 bars, the cycle length would be the length measured, not 40. Input 4: DeltaPhaseHighs. (suggested input 1.05) This is a value (in radians) that determines a lower bound for the period length. A higher value allows shorter cycles to be measured. For example, a value of 1.05 only allows cycles greater than about 6 bars to be measured. If a user preferred to allow the shortest cycle lengths measured to be longer than 6 bars to be measured (assuming a longer cycle actually existed in the data), they could adjust this. For example, using a factor of.5233 (6.28/12) would return a minimum cycle length of 12 from the cycle length calculations. Understand, if the cycle content contained a cycle shorter than 12 bars, the cycle length computed would be 12, not the shorter length. Why all this fuss about these two inputs? Simply put, they set limits on the cycle lengths that can be measured. If you want to allow a broad range of cycle length measurements, set these inputs to be wide. For example, if you wanted the longest cycle length measured to be 100 and the shortest to be 4, then set the DeltaPhaseLow to.0628 (6.28/100) and DeltaPhaseHigh to be 1.57 (6.28/4). Remember these are boundaries. The actual cycle length measured will be whatever is measured, and will likely fall in between these limits. Applications: OK, the real reason you are reading this --- APPLICATION, APPLICATION, APPLICATION. Example 1: You want a dynamic simple moving average, say for example never shorter than 6 bars, never longer than 60 bars. It is this easy: a) name a variable, say pd for period b) choose a cycle length function (Homodyne or Cybernetic Cycle Period) c) use the ACT simple moving average function
Let s try this with the Homodyne method: We ll use median price as input for prices in the Homodyne, but we could have used the close() price. We ll use median price as the data array input for the simple moving average function, but we could have used close(), or for that matter any other value we want to average (e.g. another indicator), and we ll input the variable we defined pd in the periods field. pd: = ExtFml( "ADSI.HomodyneCyclePeriod", MP() ); ExtFml( "ASI.SMA", MP(), pd); You re done. Wasn t that easy? You now have an adaptive simple moving average. No need to keep tweaking your period length as the market changes. These functions do it for you. Let s try the same thing with the Cybernetics Cycle Period: We ll use median prices as our input, an alpha of.28 (cuts off frequencies less than 7 bars in length, and a DeltaPhaseLow of 0.10 and a DeltaPhaseHigh of 1.05 (as described in our discussion above on the Cybernetic Cycle Period) pd: = ExtFml( "ADSI.CyberCyclePeriod", MP(), 0.28, 0.10, 1.05); ExtFml( "ASI.SMA", MP(), pd); Now your adaptive average is based on the Cybernetics Cycle Period. Again, you now have an adaptive average based on two lines of code. Trust us, the code underneath this if written in a programming language is very, very long and complicated!!!!! Example 2: You want a dynamic measure of the Signal to Noise Ratio (SNR), say for example never shorter than 6 bars, never longer than 60 bars. The SNR is a measure of whether prices are moving efficiently or just drifting. It is this easy:
a) name a variable, say pd for period b) choose a cycle length function (Homodyne or Cybernetic Cycle Period) c) use the ACT Signal to Noise function Let s try this with the Homodyne method: We ll use median price as input for prices in the Homodyne, but we could have used the close() price. We ll use median price as the data array input for the SNR function, but we could have used close(), and we ll input the variable we defined pd in the periods field. We ll set an exponential smoothing alpha of 0.25. This is an exponential smoothing factor applied at the end of the calculation. A larger alpha results in a smoother final output. This value is range bound between 0.0 and 1.0. Note: this is not the same alpha discussed above for frequency cutoff. Our apology for having to use the same term with two different meanings, but John Ehlers uses the term this way. Don t despair! The detailed manual describes for each indicator when alpha refers to cutoff frequency, and when it refers to an exponential smoothing factor. pd: = ExtFml( "ADSI.HomodyneCyclePeriod", MP() ); ExtFml( "ADSI.SNR", MP(), pd, 0.25); You re done. Wasn t that easy? You now have an adaptive SNR. No need to keep tweaking your period length as the market changes. These functions do it for you. Let s try this with the Cybernetics Cycle Period: We ll use median prices as our input, an alpha of.28 (cuts off frequencies less than 7 bars in length, and a DeltaPhaseLow of 0.10 and a DeltaPhaseHigh of 1.05 (as described in our discussion above on the Cybernetic Cycle Period) pd: = ExtFml( "ADSI.CyberCyclePeriod", MP(), 0.28, 0.10, 1.05); ExtFml( "ADSI.SNR", MP(), pd, 0.25); Now your SNR is based on the Cybernetics Cycle Period. Again, you now have an SNR based on two lines of code. If the programmer s code underneath the simple moving average is long, a programmer s code behind this would be a mile long!!! (a yard maybe?)
Example 3: Let s try to find the HHV (highest high) over an adaptive period. Easy. We ll just use the Cybernetic Cycle Period this time, and the same input values we used for it before. pd: = ExtFml( "ADSI.CyberCyclePeriod", MP(), 0.28, 0.10, 1.05); ExtFml( "ASI.HHV", MP(), pd); Now your HHV is based on the Cybernetics Cycle Period. Example 4: Let s get a little tricky here. After all, now you re an expert. This time we re going to find the HHV of an SNR over an adaptive period We ll just use the Cybernetic Cycle Period this time, and the same input values we used for it before. pd: = ExtFml( "ADSI.CyberCyclePeriod", MP(), 0.28, 0.10, 1.05); pf: = ExtFml( "ADSI.SNR", MP(), pd, 0.25); ExtFml( "ASI.HHV", pf, pd); Now you have the highest high value of an SNR based on the Cybernetics Cycle Period. Please note: for the SNR function, we used the same layout and variables for it as discussed in example #2. Also, our choice of names for the variable pf is arbitrary. It could have been pa, pb, etc anything but pd since it is already used, or any other variable name which Metastock already reserves for use (like MP for median price). Example 5: Let s try a unique function from ACT, a Laguerre Stochastics. The Laguerre Stochastics is a unique variant of the traditional Stochastics indicator. It uses Laguerre transformed prices to compute the Stochastic. The Laguerre Stochastic is not included in Ehlers work. The Dynamic Market Lab has extended his research to create this indicator.
The Laguerre Stochastic is a very smooth, highly responsive oscillator. Its unique design allows it to respond surprisingly well in both trending and cyclical markets. This is rare for an oscillator. Ehlers suggests crosses above the 20% line are usually followed by rising prices, and crosses below the 80% line are usually followed by falling prices. Indicator Name: Laguerre Stochastics (Cybernetic Analysis) Function Name: Laguerre Stochastics Format: ExtFml( "ADSI.LaguerreStoch", Prices, # of elements,gammas) Input 1: Prices. (suggested input is Median Price) Input 2: # of elements. This input can be any integer between (and including) 3 and 8. It represents the number of elements used in the calculation of the filter. A fewer number of elements results in a more responsive filter. Due to the nature of the internal calculations, this value must be a constant, and cannot be variable, as with most other ADSI inputs. Input 3: gammas. The gamma input is an exponential smoothing factor applied after the Laguerre Filter and is range bound between 0.0 and 1.0. A smaller the gamma results in less smoothing. A value around 0.5 is recommended, but you can adjust this. The gamma can be made adaptive with a little more effort. Indicator Formula: _DML_ADSI_Laguerre Stoch ExtFml("ADSI.LaguerreStoch", MP(), 4, 0.5); Now you have an extremely unique oscillator that rapidly changes at turns, yet flatlines above 80 in uptrends, and below 20 in downtrends. In fact, Michael Barna, an associate of John Ehlers, developed a simple system based on using this indicator alone. Conclusion: Thank you for your time and attention. We have just scratched the surface of ACT s potential. Most anything you want to do you can. The limits and combinations of ideas are virtually limitless. Remember how many different designs you could easily build with Lego blocks. Same thing here. This code is adaptable, stackable (see example 4 again), interchangeable, powerful, and fun. For advanced users, you can use these functions to write many types of loops (see the manual) not possible in Metastock, until now. Use these tools to create your own experts and explorations, or try the six experts included in ACT. They are based on John Ehlers work as well. The code is open source, and you can change inputs to them. Have fun!!