2008 Mar: Measuring Cycle Periods

ICE Data Services -

ChRSpectrum.efs, DCTunedBypassFilter.efs  

EFSLibrary - Discussion Board  

File Name: ChRSpectrum.efs, DCTunedBypassFilter.efs

Description:
These studies are based on the March 2008 article, Measuring CyclePeriods, by John F. Ehlers.

Formula Parameters:

ChRSpectrum.efs

  • Show Dominant Cycle: false
  • Dominant Cycle Color: blue
  • Dominant Cycle Size: 2

DCTunedBypassFilter.efs

  • Sine Color: red
  • Cosine Color: cyan
  • Sine Thickness: 2
  • Cosine Thickness: 2

Notes:
The related article is copyrighted material. If you are not a subscriber of Stocks & Commodities, please visit www.traders.com.

Download File:
ChRSpectrum.efs
DCTunedBypassFilter.efs



EFS Code:

ChRSpectrum.efs

/***************************************
Provided By : eSignal (c) Copyright 2008
Description:  Measuring Cycle Periods 
              by John Ehlers

Version 1.0  1/04/2008

Notes:
* March 2008 Issue of Stocks and Commodities Magazine
* Study requires version 8.0 or later.


Formula Parameters:                     Default:
Show Dominant Cycle                     false
Dominant Cycle Color                    blue
Dominant Cycle Size                     2
*****************************************************************/

function preMain() {
    setStudyTitle("Channelized Receiver Spectrum ");
    setShowCursorLabel(false);
    setShowTitleParameters(false);    
    // Dominant Cycle properties
    setPlotType(PLOTTYPE_CIRCLE, 51);
    setDefaultBarBgColor(Color.black, 0);

    var fp1 = new FunctionParameter("bShowDC", FunctionParameter.BOOLEAN);
        fp1.setName("Show Dominant Cycle");
        fp1.setDefault(false);
    var fp2 = new FunctionParameter("nDC_color", FunctionParameter.COLOR);
        fp2.setName("Dominant Cycle Color");
        fp2.setDefault(Color.blue);
    var fp3 = new FunctionParameter("nDC_thick", FunctionParameter.NUMBER);
        fp3.setName("Dominant Cycle Size");
        fp3.setLowerLimit(1);
        fp3.setDefault(2);    
}

// Global Variables
var bVersion  = null;    // Version flag
var bInit     = false;   // Initialization flag
var xPrice = null;
var xHP = null;
var xCleanData = null;
var aDB = new Array(51);
var aReturn = new Array(52);  // return array

var nDelta = 0.1;
var nBeta = 0;
var nGamma = 0;
var nAlpha = 0;
var nMaxAmpl = 0;
var nNum = 0;
var nDenom = 0;
var nDC = 0;
var nDomCyc = 0;

var aDC  = new Array(10);
var aQ          = new Array(51);
var aI          = new Array(51);
var aReal       = new Array(51);
var aOlderI     = new Array(51);
var aOldReal    = new Array(51);
var aOlderReal  = new Array(51);
var aImag       = new Array(51);
var aOldQ       = new Array(51);
var aOlderQ     = new Array(51);
var aOldImag    = new Array(51);
var aOlderImag  = new Array(51);
var aAmpl       = new Array(51);
var aOldI       = new Array(51);
var aOldAmpl    = new Array(51);

for (var j = 0; j < 51; j++) {
    aQ[j] = 0;          
    aI[j] = 0;          
    aReal[j] = 0;       
    aOlderI[j] = 0;     
    aOldReal[j] = 0;
    aOlderReal[j] = 0;
    aImag[j] = 0;
    aOldQ[j] = 0;
    aOlderQ[j] = 0;
    aOldImag[j] = 0;
    aOlderImag[j] = 0;
    aAmpl[j] = 0;
    aOldI[j] = 0;
    aOldAmpl[j] = 0;
}

function main(bShowDC, nDC_color, nDC_thick) {
    if (bVersion == null) bVersion = verify();
    if (bVersion == false) return;    

    var nPeriod = 0;
    var n = 0;
    var nMaxPwr = 0;
    var nNum = 0;
    var nDenom = 0;
    var nDominantCycle = 0;
    var Color1 = null;
    var Color2 = null;
    var nState = getBarState();


    //Initialization
    if (bInit == false) {
        drawTextPixel(0, 0, "                                                    ", null, 
            Color.lightgrey, Text.RELATIVETOTOP|Text.RELATIVETOLEFT, null, 12, "bkg");
        setDefaultBarFgColor(nDC_color, 51);
        setDefaultBarThickness(nDC_thick, 51);
        xPrice = hl2();
        xHP = efsInternal("calcHP", xPrice);
        xCleanData = efsInternal("calcCleanData", xHP, xPrice);  // Smooth HP
        bInit = true;
    }

    if (nState == BARSTATE_NEWBAR) {
        aDC.pop();
        aDC.unshift(nDC);
    }


    if (nState == BARSTATE_NEWBAR) {
        nPeriod = 8;
        for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
            aOlderI[nPeriod]    = aOldI[nPeriod];
            aOldI[nPeriod]      = aI[nPeriod];
            aOlderQ[nPeriod]    = aOldQ[nPeriod];
            aOldQ[nPeriod]      = aQ[nPeriod];
            aOlderReal[nPeriod] = aOldReal[nPeriod];
            aOldReal[nPeriod]   = aReal[nPeriod];
            aOlderImag[nPeriod] = aOldImag[nPeriod];
            aOldImag[nPeriod]   = aImag[nPeriod];
            aOldAmpl[nPeriod]   = aAmpl[nPeriod];
        }
    }


    var nHP = xHP.getValue(0);
    var nCleanData = xCleanData.getValue(-50);
    if (nHP == null || nCleanData == null) return;
    
    nDelta = -.015 * getCurrentBarCount() + .5;
    if (nDelta < .15 ) {
        nDelta = .15;
    }
    

    if (getCurrentBarCount() > 6 ) {
        nPeriod = 8;
        for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
            nBeta = Math.cos((2*Math.PI)/nPeriod);
            nGamma = 1 / Math.cos((((2*Math.PI)+(2*Math.PI)) * nDelta) / nPeriod);
            nAlpha = nGamma - Math.sqrt(nGamma*nGamma - 1);
            aQ[nPeriod] = (nPeriod / 6.283185)*(xCleanData.getValue(0) - xCleanData.getValue(-1));
            aI[nPeriod] = xCleanData.getValue(0);
            aReal[nPeriod] = .5*(1 - nAlpha)*(aI[nPeriod] - aOlderI[nPeriod]) + nBeta*(1 + nAlpha)*aOldReal[nPeriod] - nAlpha*aOlderReal[nPeriod];
            aImag[nPeriod] = .5*(1 - nAlpha)*(aQ[nPeriod] - aOlderQ[nPeriod]) + nBeta*(1 + nAlpha)*aOldImag[nPeriod] - nAlpha*aOlderImag[nPeriod];
            aAmpl[nPeriod] = (aReal[nPeriod]*aReal[nPeriod] + aImag[nPeriod]*aImag[nPeriod]);
        }
    }
    
    

    
    nMaxAmpl = aAmpl[10];
    nPeriod = 8;
    for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
        if (aAmpl[nPeriod] > nMaxAmpl) {
            nMaxAmpl = aAmpl[nPeriod];
        }
    }
    
    
    nPeriod = 8;
    for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
        if (nMaxAmpl != 0 && (aAmpl[nPeriod] / nMaxAmpl) > 0 ) {
            aDB[nPeriod] = -10 * Math.log(.01 / (1 - .99*aAmpl[nPeriod] / nMaxAmpl)) / Math.log(10);
        }
        if (aDB[nPeriod] > 20 ) {
            aDB[nPeriod] = 20;
        }       
    }

    nNum = 0;
    nDemon = 0;
    nPeriod = 8;
    for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
        if (aDB[nPeriod] <= 3 ) {
            nNum = nNum + nPeriod*(20 - aDB[nPeriod]);
            nDenom = nDenom + (20 - aDB[nPeriod]);
        }
        if (nDenom != 0 ) {
            nDC = nNum / nDenom;
            aDC[0] = nDC;
        }
    }



    nDomCyc = Median(aDC, 10);
    if (bShowDC == true) {
        aReturn[51] = nDomCyc;
    }

    //Plot the Spectrum as a Heatmap
    nPeriod = 8;
    for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
        if (aDB[nPeriod] <= 10) {
            Color1 = 255;
            Color2 = Math.round(255*(1 - aDB[nPeriod]/10));
        }
        if (aDB[nPeriod] > 10) {
            Color1 = Math.round(255*(2 - aDB[nPeriod]/10));
            Color2 = 0;            
        }        
        aReturn[nPeriod] = nPeriod;
        setDefaultBarFgColor(Color.RGB(Color1 , Color2, 0), nPeriod);
        setDefaultBarThickness(4, nPeriod);
    }
    
    //  aReturn[51]  // contains the Dominant Cycle value
    
    return aReturn;
}



// calcHP globals
var nPrevHP = null;
var nCurrHP = null;

function calcHP(x) {
    var nAlpha1 = (1 - Math.sin((2*Math.PI)/40)) / Math.cos((2*Math.PI)/40);
    var nHP = null;
    
    if (getCurrentBarCount() <= 5 ) {
        nCurrHP = x.getValue(0);
        return nCurrHP;
    } else {
        if (x.getValue(-1) == null) return null;
        if (getBarState() == BARSTATE_NEWBAR) nPrevHP = nCurrHP;
        nCurrHP = ( 0.5*(1 + nAlpha1)*(x.getValue(0) - x.getValue(-1)) + nAlpha1*nPrevHP );
        return nCurrHP;
    }

}


function calcCleanData(x, xP) {  //SmoothHP
    if (getCurrentBarCount() == 1 ) {
        return 0;
    } else if (getCurrentBarCount() <= 7 ) {
        return xP.getValue(0) - xP.getValue(-1);
    } else {
        return (  x.getValue(0) + 
                  2*x.getValue(-1) + 
                  3*x.getValue(-2) + 
                  3*x.getValue(-3) + 
                  2*x.getValue(-4) + 
                  x.getValue(-5)    ) / 12;
    }
}


function Median(myArray, Length) {
    var aArray = new Array(Length);
    var nMedian = null;
    
    for (var i = 0; i < Length; i++) {
        aArray[i] = myArray[i];
    }
    
    aArray = aArray.sort(compareNumbers);
    
    nMedian = aArray[Math.round((Length-1)/2)];

    return nMedian;
}

function compareNumbers(a, b) {
   return a - b
}


function verify() {
    var b = false;
    if (getBuildNumber() < 779) {
        drawTextAbsolute(5, 35, "This study requires version 8.0 or later.", 
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "error");
        drawTextAbsolute(5, 20, "Click HERE to upgrade.@URL=http://www.esignal.com/download/default.asp", 
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "upgrade");
        return b;
    } else {
        b = true;
    }
    
    return b;
}


DCTunedBypassFilter.efs

/***************************************
Provided By : eSignal (c) Copyright 2008
Description:  Measuring Cycle Periods 
              by John Ehlers

Version 1.0  1/04/2008

Notes:
* March 2008 Issue of Stocks and Commodities Magazine
* Study requires version 8.0 or later.


Formula Parameters:                     Default:
Sine Color                              red
Cosine Color                            cyan
Sine Thickness                          2
Cosine Thickness                        2    
*****************************************************************/

function preMain() {
    setStudyTitle("Dominant Cycle Tuned Bypass Filter ");
    setShowTitleParameters(false);    
    setCursorLabelName("Sine", 0);
    setCursorLabelName("Cosine", 1);

    var fp1 = new FunctionParameter("nS_color", FunctionParameter.COLOR);
        fp1.setName("Sine Color");
        fp1.setDefault(Color.red);
    var fp2 = new FunctionParameter("nC_color", FunctionParameter.COLOR);
        fp2.setName("Cosine Color");
        fp2.setDefault(Color.cyan);
    var fp3 = new FunctionParameter("nS_thick", FunctionParameter.NUMBER);
        fp3.setName("Sine Thickness");
        fp3.setLowerLimit(1);
        fp3.setDefault(2);    
    var fp4 = new FunctionParameter("nC_thick", FunctionParameter.NUMBER);
        fp4.setName("Cosine Thickness");
        fp4.setLowerLimit(1);
        fp4.setDefault(2);    
}

// Global Variables
var bVersion  = null;    // Version flag
var bInit     = false;   // Initialization flag
var xPrice = null;
var xHP = null;
var xCleanData = null;
var aDB = new Array(51);

var nDelta = 0.1;
var nBeta = 0;
var nGamma = 0;
var nAlpha = 0;
var nMaxAmpl = 0;
var nNum = 0;
var nDenom = 0;
var nDC = 0;
var nDomCyc = 0;
var nValue1 = null;
var nValue1_1 = null;
var nValue1_2 = null;
var nValue2 = null;


var aDC  = new Array(10);
var aQ          = new Array(51);
var aI          = new Array(51);
var aReal       = new Array(51);
var aOlderI     = new Array(51);
var aOldReal    = new Array(51);
var aOlderReal  = new Array(51);
var aImag       = new Array(51);
var aOldQ       = new Array(51);
var aOlderQ     = new Array(51);
var aOldImag    = new Array(51);
var aOlderImag  = new Array(51);
var aAmpl       = new Array(51);
var aOldI       = new Array(51);
var aOldAmpl    = new Array(51);

for (var j = 0; j < 51; j++) {
    aQ[j] = 0;          
    aI[j] = 0;          
    aReal[j] = 0;       
    aOlderI[j] = 0;     
    aOldReal[j] = 0;
    aOlderReal[j] = 0;
    aImag[j] = 0;
    aOldQ[j] = 0;
    aOlderQ[j] = 0;
    aOldImag[j] = 0;
    aOlderImag[j] = 0;
    aAmpl[j] = 0;
    aOldI[j] = 0;
    aOldAmpl[j] = 0;
}

function main(nS_color, nC_color, nS_thick, nC_thick) {
    if (bVersion == null) bVersion = verify();
    if (bVersion == false) return;    

    var nPeriod = 0;
    var n = 0;
    var nMaxPwr = 0;
    var nNum = 0;
    var nDenom = 0;
    var nDominantCycle = 0;
    var Color1 = null;
    var Color2 = null;
    var nState = getBarState();


    //Initialization
    if (bInit == false) {
        setDefaultBarFgColor(nS_color, 0);
        setDefaultBarFgColor(nC_color, 1);
        setDefaultBarThickness(nS_thick, 0);
        setDefaultBarThickness(nC_thick, 1);
        xPrice = hl2();
        xHP = efsInternal("calcHP", xPrice);
        xCleanData = efsInternal("calcCleanData", xHP, xPrice);  // Smooth HP
        bInit = true;
    }

    if (nState == BARSTATE_NEWBAR) {
        aDC.pop();
        aDC.unshift(nDC);
        nValue1_2 = nValue1_1;
        nValue1_1 = nValue1;
    }


    if (nState == BARSTATE_NEWBAR) {
        nPeriod = 8;
        for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
            aOlderI[nPeriod]    = aOldI[nPeriod];
            aOldI[nPeriod]      = aI[nPeriod];
            aOlderQ[nPeriod]    = aOldQ[nPeriod];
            aOldQ[nPeriod]      = aQ[nPeriod];
            aOlderReal[nPeriod] = aOldReal[nPeriod];
            aOldReal[nPeriod]   = aReal[nPeriod];
            aOlderImag[nPeriod] = aOldImag[nPeriod];
            aOldImag[nPeriod]   = aImag[nPeriod];
            aOldAmpl[nPeriod]   = aAmpl[nPeriod];
        }
    }


    var nHP = xHP.getValue(0);
    var nCleanData = xCleanData.getValue(-50);
    if (nHP == null || nCleanData == null) return;
    
    nDelta = -.015 * getCurrentBarCount() + .5;
    if (nDelta < .15 ) {
        nDelta = .15;
    }
    

    if (getCurrentBarCount() > 6 ) {
        nPeriod = 8;
        for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
            nBeta = Math.cos((2*Math.PI)/nPeriod);
            nGamma = 1 / Math.cos((((2*Math.PI)+(2*Math.PI)) * nDelta) / nPeriod);
            nAlpha = nGamma - Math.sqrt(nGamma*nGamma - 1);
            aQ[nPeriod] = (nPeriod / 6.283185)*(xCleanData.getValue(0) - xCleanData.getValue(-1));
            aI[nPeriod] = xCleanData.getValue(0);
            aReal[nPeriod] = .5*(1 - nAlpha)*(aI[nPeriod] - aOlderI[nPeriod]) + nBeta*(1 + nAlpha)*aOldReal[nPeriod] - nAlpha*aOlderReal[nPeriod];
            aImag[nPeriod] = .5*(1 - nAlpha)*(aQ[nPeriod] - aOlderQ[nPeriod]) + nBeta*(1 + nAlpha)*aOldImag[nPeriod] - nAlpha*aOlderImag[nPeriod];
            aAmpl[nPeriod] = (aReal[nPeriod]*aReal[nPeriod] + aImag[nPeriod]*aImag[nPeriod]);
        }
    }
    
    
    nMaxAmpl = aAmpl[10];
    nPeriod = 8;
    for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
        if (aAmpl[nPeriod] > nMaxAmpl) {
            nMaxAmpl = aAmpl[nPeriod];
        }
    }
    
    nPeriod = 8;
    for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
        if (nMaxAmpl != 0 && (aAmpl[nPeriod] / nMaxAmpl) > 0 ) {
            aDB[nPeriod] = -10 * Math.log(.01 / (1 - .99*aAmpl[nPeriod] / nMaxAmpl)) / Math.log(10);
        }
        if (aDB[nPeriod] > 20 ) {
            aDB[nPeriod] = 20;
        }       
    }

    nNum = 0;
    nDemon = 0;
    nPeriod = 8;
    for (nPeriod = 8; nPeriod <= 50; nPeriod++) {
        if (aDB[nPeriod] <= 3 ) {
            nNum = nNum + nPeriod*(20 - aDB[nPeriod]);
            nDenom = nDenom + (20 - aDB[nPeriod]);
        }
        if (nDenom != 0 ) {
            nDC = nNum / nDenom;
            aDC[0] = nDC;
        }
    }


    nDomCyc = Median(aDC, 10);
    if (nDomCyc < 8 ) {
        nDomCyc = 20;
    }

    nBeta = Math.cos((2*Math.PI)/nDomCyc);
    nGamma = 1 / Math.cos((((2*Math.PI)+(2*Math.PI)) * nDelta) / nDomCyc);
    nAlpha = nGamma - Math.sqrt(nGamma*nGamma - 1);
    nValue1 = .5*(1 - nAlpha)*(xCleanData.getValue(0) - xCleanData.getValue(-1)) + 
        nBeta*(1 + nAlpha)*nValue1_1 - nAlpha*nValue1_2;
    nValue2 = (nDomCyc / 6.28)*(nValue1 - nValue1_1);
    
    return new Array(nValue1, nValue2);
}



// calcHP globals
var nPrevHP = null;
var nCurrHP = null;

function calcHP(x) {
    var nAlpha1 = (1 - Math.sin((2*Math.PI)/40)) / Math.cos((2*Math.PI)/40);
    var nHP = null;
    
    if (getCurrentBarCount() <= 5 ) {
        nCurrHP = x.getValue(0);
        return nCurrHP;
    } else {
        if (x.getValue(-1) == null) return null;
        if (getBarState() == BARSTATE_NEWBAR) nPrevHP = nCurrHP;
        nCurrHP = ( 0.5*(1 + nAlpha1)*(x.getValue(0) - x.getValue(-1)) + nAlpha1*nPrevHP );
        return nCurrHP;
    }

}


function calcCleanData(x, xP) {  //SmoothHP
    if (getCurrentBarCount() == 1 ) {
        return 0;
    } else if (getCurrentBarCount() <= 7 ) {
        return xP.getValue(0) - xP.getValue(-1);
    } else {
        return (  x.getValue(0) + 
                  2*x.getValue(-1) + 
                  3*x.getValue(-2) + 
                  3*x.getValue(-3) + 
                  2*x.getValue(-4) + 
                  x.getValue(-5)    ) / 12;
    }
}


function Median(myArray, Length) {
    var aArray = new Array(Length);
    var nMedian = null;
    
    for (var i = 0; i < Length; i++) {
        aArray[i] = myArray[i];
    }
    
    aArray = aArray.sort(compareNumbers);
    
    nMedian = aArray[Math.round((Length-1)/2)];

    return nMedian;
}

function compareNumbers(a, b) {
   return a - b
}


function verify() {
    var b = false;
    if (getBuildNumber() < 779) {
        drawTextAbsolute(5, 35, "This study requires version 8.0 or later.", 
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "error");
        drawTextAbsolute(5, 20, "Click HERE to upgrade.@URL=http://www.esignal.com/download/default.asp", 
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "upgrade");
        return b;
    } else {
        b = true;
    }
    
    return b;
}