The Adaptive Cyber Cycle is a sophisticated technical analysis tool designed to help traders identify underlying trends and cyclical movements in the financial markets. Based on the cybernetics principles outlined by John F. Ehlers, this script moves beyond standard fixed-period indicators by attempting to "adapt" to the changing speed of market cycles in real-time.
Core Logic and Functionality
1. Adaptive Period Detection The primary strength of this tool is its ability to adjust its sensitivity automatically. Rather than using a static timeframe (like a simple 14-day average), the script calculates a dynamic period based on an "Alpha" value. This allows the indicator to speed up when the market is moving rapidly and slow down during periods of consolidation, helping to filter out "market noise" that often leads to false signals.
2. Price Smoothing and Data Processing Before calculating the final cycle, the script processes raw price data (the midpoint between the high and low of each candle) through a weighted smoothing formula. This ensures that sudden, erratic price spikes do not cause the indicator to jump erratically. It looks at a window of previous data points to create a balanced view of the current price momentum.
3. The Cycle Calculation The script utilizes a modified Commodity Channel Index (CCI) logic. By applying the adaptively calculated period to this CCI framework, it generates a "Cycle" value. This represents the current rhythmic movement of the asset—essentially showing whether the market is currently in an upward or downward phase relative to its recent history.
4. Trigger and Visual Feedback To make the data actionable for the user, the script provides two main visual components:
- The Cycle: A primary visual representation of the current market rhythm.
- The Trigger: A secondary value derived from the previous cycle state. By comparing these two, traders can better identify "turning points" or momentum shifts.
How it Benefits the Trader
Because markets are rarely constant—sometimes moving in fast waves and other times in slow trends—a fixed indicator often fails because it is either too fast (noisy) or too slow (delayed). This script solves that problem by being adaptive. It seeks to stay "in sync" with the market's natural pulse, providing a clearer picture of the current trend while attempting to neutralize the random fluctuations of day-to-day trading.
//+------------------------------------------------------------------+
//| AdaptiveCyberCycle.mq4 |
//| |
//| Adaptive Cyber Cycle |
//| |
//| Algorithm taken from book |
//| "Cybernetics Analysis for Stock and Futures" |
//| by John F. Ehlers |
//| |
//| contact@mqlsoft.com |
//| http://www.mqlsoft.com/ |
//+------------------------------------------------------------------+
//mod cci
#property copyright "Coded by Witold Wozniak"
#property link "www.mqlsoft.com"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red
#property indicator_level1 100
#property indicator_level2 -100
#property indicator_levelcolor DarkSlateGray
double Cycle[];
double Trigger[];
double Smooth[];
//extern int CCI_Period = 14;
extern int CCI_Price = 5;
extern double Alpha = 0.07;
int buffers = 0;
int drawBegin = 0;
int init() {
drawBegin = 8;
initBuffer(Trigger, "Trigger", DRAW_HISTOGRAM);
initBuffer(Cycle, "Cycle", DRAW_HISTOGRAM);
initBuffer(Smooth);
IndicatorBuffers(buffers);
IndicatorShortName("cci Adaptive Cyber Cycle [" + DoubleToStr(Alpha, 2) + "]");
return (0);
}
int start() {
if (Bars <= drawBegin) return (0);
int countedBars = IndicatorCounted();
if (countedBars < 0) return (-1);
if (countedBars > 0) countedBars--;
int s, limit = Bars - countedBars - 1;
for (s = limit; s >= 0; s--) {
Smooth[s] = (P(s) + 2.0 * P(s + 1) + 2.0 * P(s + 2) + P(s + 3)) / 6.0;
double period = iCustom(0, 0, "CyclePeriod", Alpha, 0, s);
// double alpha1 = 2.0 / (period + 1.0);
Cycle[s] = iCCI(NULL,0,period,CCI_Price,s);
if (s > Bars - 8) {
Cycle[s] = (P(s) - 2.0 * P(s + 1) + P(s + 2)) / 4.0;
}
Trigger[s] = Cycle[s + 1];
}
return (0);
}
double P(int index) {
return ((High[index] + Low[index]) / 2.0);
}
void initBuffer(double array[], string label = "", int type = DRAW_NONE, int arrow = 0, int style = EMPTY, int width = EMPTY, color clr = CLR_NONE) {
SetIndexBuffer(buffers, array);
SetIndexLabel(buffers, label);
SetIndexEmptyValue(buffers, EMPTY_VALUE);
SetIndexDrawBegin(buffers, drawBegin);
SetIndexShift(buffers, 0);
SetIndexStyle(buffers, type, style, width);
SetIndexArrow(buffers, arrow);
buffers++;
}
Comments