Author: Coded by Witold Wozniak
Sinewave

This technical indicator is designed to help traders identify underlying cyclical patterns in financial markets by filtering out "noise" and highlighting the recurring waves of price action. Based on cybernetics analysis principles, it seeks to transform complex price movements into a clean, readable sine wave.

Core Logic and Workflow

The script processes market data through several distinct stages to arrive at its final visual output:

1. Data Preparation (Price Averaging) Instead of looking at every individual price tick, the logic first identifies the midpoint of each candle (the average between the high and low prices). This stabilizes the initial data set, ensuring that extreme spikes or wicks don't disproportionately skew the results.

2. Smoothing and Filtering The raw price data is passed through a smoothing calculation. By weighing recent prices against slightly older ones, the tool removes minor fluctuations. This creates a "cleaner" trendline that makes it easier to see the larger movements of the market without getting distracted by short-term volatility.

3. Cycle Identification and Calculation The heart of the script lies in its cycle detection. It uses a specific mathematical formula to calculate the frequency and phase of the market's movement. It looks for repeating patterns and calculates the "DC Phase"—essentially determining where we currently stand within the current market cycle (e.g., are we at the peak, the trough, or in the middle of a transition?).

4. Sine Wave Generation Once the cycle is identified, the script translates that data into two distinct visual lines:

  • The Primary Sine Wave: This represents the current rhythmic movement of the market. It helps traders visualize the "ebb and flow" of price action.
  • The Lead Sine Wave: This serves as a predictive component. By shifting the phase of the wave forward, it acts as a leading indicator to help anticipate where the cycle might be heading next based on its current momentum.

Practical Summary for Traders

By converting messy price charts into smooth, oscillating waves, this tool allows you to see the market's "heartbeat." Rather than reacting to every minor price change, you can observe the broader cyclical behavior. The two lines work together to show you where the current cycle is and provide a visual cue on where that cycle is likely moving toward next.

Miscellaneous
Implements a curve of type %1
13 Views
0 Downloads
0 Favorites
Sinewave
//+------------------------------------------------------------------+
//|                                                     Sinewave.mq4 |
//|                                                                  |
//| Sinewave                                                         |
//|                                                                  |
//| Algorithm taken from book                                        |
//|     "Cybernetics Analysis for Stock and Futures"                 |
//| by John F. Ehlers                                                |
//|                                                                  |
//|                                              contact@mqlsoft.com |
//|                                          http://www.mqlsoft.com/ |
//+------------------------------------------------------------------+
#property copyright "Coded by Witold Wozniak"
#property link      "www.mqlsoft.com"

#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 Red
#property indicator_color2 Blue

#property indicator_minimum -1
#property indicator_maximum 1
#property indicator_level1 0

double Sine[];
double LeadSine[];
double Cycle[];
double Smooth[];

extern double Alpha = 0.07;
int buffers = 0;
int drawBegin = 0;

double tempReal, rad2Deg, deg2Rad;

int init() {
    drawBegin = 8;
    initBuffer(Sine, "Sine", DRAW_LINE);
    initBuffer(LeadSine, "Lead", DRAW_LINE);
    initBuffer(Cycle);
    initBuffer(Smooth);
    IndicatorBuffers(buffers);
    IndicatorShortName("Sinewave [" + DoubleToStr(Alpha, 2) + "]");      
    tempReal = MathArctan(1.0);
    rad2Deg = 45.0 / tempReal;
    deg2Rad = 1.0 / rad2Deg;
    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;
        Cycle[s] = (1.0 - 0.5 * Alpha) * (1.0 - 0.5 * Alpha) * (Smooth[s] - 2.0 * Smooth[s + 1] + Smooth[s + 2]) 
            + 2.0 * (1.0 - Alpha) * Cycle[s + 1]
            - (1.0 - Alpha) * (1.0 - Alpha) * Cycle[s + 2];    
        double period = iCustom(0, 0, "CyclePeriod", Alpha, 0, s);
        int DCPeriod = MathFloor(period);
        double RealPart = 0.0;
        double ImagPart = 0.0;
        for (int count = 0; count < DCPeriod; count++) {
            RealPart += MathSin(deg2Rad * 360.0 * count / DCPeriod) * Cycle[s + count];
            ImagPart += MathCos(deg2Rad * 360.0 * count / DCPeriod) * Cycle[s + count];
        }
        double DCPhase;
        if (MathAbs(ImagPart) > 0.001) {
            DCPhase = rad2Deg * MathArctan(RealPart / ImagPart);
        }
        if (MathAbs(ImagPart) <= 0.001) {
    	      if (RealPart >= 0.0) {
    	          DCPhase = 90.0;
    	      } else { 
    	          DCPhase = -90.0;
    	      }
        }
        DCPhase += 90.0;
        if (ImagPart < 0) {
            DCPhase += 180.0;
        }
        if (DCPhase > 315.0) {
            DCPhase -= 360.0;
        }        
        Sine[s] = MathSin(DCPhase * deg2Rad);
        LeadSine[s] = MathSin((DCPhase + 45.0) * deg2Rad);
    }
    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