Jenkins Cycle

link to .ts file (1 of 2)

#hint: <b>Jenkins Cycle Volume</b> \n This study indicates a possible trend reversal after the cummulative volume range specified by the user is reached.\n

#hint jenkins_range: The number of shares traded for a trend reversal.

#hint length: The number of trading days per year.

##################################################################################

##

## This code is based on some of the cyclic and harmonic methodology theory developed

## by Michael S. Jenkins. Ken Hodor modified the cyclic indicator based on trade volume

## for the SPY and implemented his approach in TradeStation. This is an implementation

## of the approach Ken presented at the August 22, 2015 San Diego Investools Meeting.

##

## Every 1.1 Billion shares of SPY traded represents a possible trend reversal.

##

## Original Implementation: Ken Hodor - TradeStation Easy Language

## 09/16/2015 Implemented by Tim Sayre - ThinkorSwim thinkScript

##

## NO ACTUAL OR IMPLIED WARRANTIES OFFERED - USE AT YOUR OWN DISCRETION

##################################################################################

declare lower;

input jenkins_range = 1100000000; ## Ken Hodor determined 1.1 billion shares traded fit the data set.

def length = 252; ## Trading days per year.

input showApproxDaysRemainLabel = yes; ## Shows/Hide Label with approximate number of bars until reversal.

def cycle_dir;

def cumulative_vol;

def debug_label;

def bar_vol = GetValue( volume, 0 );

## Only need these values at the first bar, but not sure how else to keep this tidy except by

## using the Compound Value function w/o thus preventing the calculation for every bar.

## The variable isn't needed afterwards so just copying the previous bar value into the current bar value.

def avg_daily = ( fold i = 0 to length with vol_sum = 0 do vol_sum + GetValue( volume, i ) ) / length;

def lo_idx = GetMinValueOffset( low, length );

def vol_to_low = CompoundValue( 1, vol_to_low[1], fold j = 0 to length - lo_idx with vol = 0 do vol + GetValue( volume, j ) );

## Checks to see if odd or even number to determine initial direction.

def cur_dir = CompoundValue( 1, cycle_dir[1], If( floor( vol_to_low / jenkins_range ) % 2 == 0, 1, -1 ) );

## If it is first bar then we need to calculate initial volume based on location of lowest low bar.

## Otherwise we use the previous bars value for cumulative volume.

def hist_vol = CompoundValue( 1, cumulative_vol[1], vol_to_low % jenkins_range );

## Check to see if we need to reverse direction or not.

if ( hist_vol + bar_vol > jenkins_range ) then {

## Account for cycle reversal.

cumulative_vol = hist_vol + bar_vol - jenkins_range;

cycle_dir = cur_dir * (-1);

## debug

debug_label = no;

} else {

cumulative_vol = hist_vol + bar_vol;

cycle_dir = cur_dir;

## debug

debug_label = no;

}

plot JenkinsVol = If ( cycle_dir == 1, 0, 1 ) + cycle_dir * cumulative_vol / jenkins_range;

JenkinsVol.SetPaintingStrategy( PaintingStrategy.LINE_VS_POINTS );

JenkinsVol.SetLineWeight( 2 ); ## Range from 1 to 5 ThinkScript imposed.

## Display for approximate number of bars remaining in the cycle.

def remain = ( jenkins_range - cumulative_vol ) / avg_daily;

AddLabel( showApproxDaysRemainLabel, "Approx. Days Remaining - " + Round( remain, 2 ), Color.WHITE );

#### debug ####

## Just change this out for other variables.

AddChartBubble( debug_label, 1.0, AsText( cycle_dir, NumberFormat.TWO_DECIMAL_PLACES ), Color.WHITE );

link to kJenkinsUpperSTUDY (2 of 2)

#hint: <b>Jenkins Cycle Volume</b> \n This study draws a trendline on tbe upper chart based on the logic from kJenkinsSTUDY.ts

#hint jenkins_range: The number of shares traded for a trend reversal.

#hint length: The number of trading days per year.

##################################################################################

##

## This code is a companion script to kJenkinsSTUDY.ts. This cdodee draws a trend

## line on the upper price chart based on the logic described in kJenkinsSTUDY.ts.

## Please reference the header in thgat script for a description of the logic.

## Original Implementation: Ken Hodor - TradeStation Easy Language

## 12/18/2015 Implemented by Tim Sayre - ThinkorSwim thinkScript

##

## NO ACTUAL OR IMPLIED WARRANTIES OFFERED - USE AT YOUR OWN DISCRETION

##################################################################################

declare upper;

input jenkins_range = 950000000; ## Ken Hodor determined 950 million shares traded fit the data set. (12/18/2015)

input length = 252; ## Trading days per year.

def cycle_dir;

def cumulative_vol;

def debug_label;

def bar_vol = GetValue( volume, 0 );

## Only need these values at the first bar, but not sure how else to keep this tidy except by

## using the Compound Value function w/o this preventing the calculation for every bar.

## The variable isn't needed afterwards so just copying the previous bar value into the current bar value.

def avg_daily = ( fold i = 0 to length with vol_sum = 0 do vol_sum + GetValue( volume, i ) ) / length;

def lo_idx = GetMinValueOffset( low, length );

def vol_to_low = CompoundValue( 1, vol_to_low[1], fold j = 0 to length - lo_idx with vol = 0 do vol + GetValue( volume, j ) );

## Checks to see if odd or even number to determine initial direction.

def cur_dir = CompoundValue( 1, cycle_dir[1], If( Floor( vol_to_low / jenkins_range ) % 2 == 0, 1, -1 ) );

## If it is first bar then we need to calculate initial volume based on location of lowest low bar.

## Otherwise we use the previous bars value for cumulative volume.

def hist_vol = CompoundValue( 1, cumulative_vol[1], vol_to_low % jenkins_range );

## Check to see if we need to reverse direction or not.

def peak_val;

def peak_high;

def peak_low;

if ( hist_vol + bar_vol > jenkins_range ) then {

## Account for cycle reversal.

cumulative_vol = hist_vol + bar_vol - jenkins_range;

cycle_dir = cur_dir * (-1);

## Optimized plot to display line to make it closest to horizontal.

## This methodology is intended to mimic Ken Hodor's TradeStation EasyLanguage implimentation.

##draw a line from previous Jenkins max limit to current Jenkins max limit.

if cycle_dir > 0 or BarNumber() == 1 then {

peak_val = Double.NaN;

} else if ( low <= peak_high[1] && low >= peak_low[1] ) then {

peak_val = low; ## try to make it horizontal.

} else if ( peak_low[1] <= high && peak_low[1] >= low ) then {

peak_val = peak_low[1]; ## try to make it horizontal.

} else if ( high <= peak_high[1] && high >= peak_low[1]) then {

peak_val = high; ## try to make it horizontal.

} else if ( peak_high[1] <= high && peak_high[1] >= low ) then {

peak_val = peak_high[1]; ## try to make it horizontal.

} else {

peak_val = ( high + low ) / 2;

}

peak_high = high;

peak_low = low;

## debug

debug_label = no;

} else {

## Not a peak so just pull previous values forward until we need them for a peak.

cumulative_vol = hist_vol + bar_vol;

cycle_dir = cur_dir;

peak_val = Double.NaN;

peak_high = peak_high[1];

peak_low = peak_low[1];

## debug

debug_label = no;

}

plot line_JenkinsPeak = peak_val;

line_JenkinsPeak.enableApproximation();

line_JenkinsPeak.SetPaintingStrategy( PaintingStrategy.LINE );

line_JenkinsPeak.SetLineWeight( 1 ); ## Range from 1 to 5 ThinkScript imposed.

line_JenkinsPeak.SetDefaultColor( Color.YELLOW );

plot dot_JenkinsPeak = peak_val;

dot_JenkinsPeak.SetPaintingStrategy( PaintingStrategy.POINTS );

dot_JenkinsPeak.SetLineWeight( 3 ); ## Range from 1 to 5 ThinkScript imposed.

dot_JenkinsPeak.SetDefaultColor( Color.YELLOW );

AddVerticalLine( if !isNaN( peak_val ) then yes else no, "", Color.WHITE, Curve.SHORT_DASH );

#### debug ####

## Just change this out for other variables.

AddChartBubble( debug_label, 1.0, AsText( cycle_dir, NumberFormat.TWO_DECIMAL_PLACES ), Color.WHITE );

AddChartBubble( if debug_label && !isNaN( peak_val ) then yes else no, close, peak_val, Color.WHITE );