Traders' Tip text
The Price Zone Oscillator system, as presented in Walid Khalil's and David Steckler's article "Entering The Price Zone", is available as a free download to Wealth-Lab users as well as many other ready-made trading Strategies. To start exploring its potential of switching gears and trading in both the trending and rangebound markets, all it takes is to click the "Download" button in Wealth-Lab's "Open Strategy" dialog.
Figure 1. A Wealth-Lab Developer 6.2 chart showing the Price Zone Oscillator strategy in action applied to a Daily chart of Walt Disney Co. (
DIS).
Although the new complementary oscillator implementation is pretty straightforward, the accompanying system rules have to function in different market regimes and cover such events as positive and negative price/oscillator divergences. The complexity of their implementation is hidden in an additional library,
"Community Components", available for download to Wealth-Lab customers from our site www.wealth-lab.com (
"Extensions" section). On Figure 1, users can see the divergence lines drawn on the chart (the traditional way) and as a "binary wave" to be used by mechanical trading systems.
WealthScript Code (C#)
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
using Community.Components; // Divergence Between Two DataSeries (Detect, Plot)
namespace WealthLab.Strategies
{
public class PZOStrategy : WealthScript
{
private StrategyParameter paramPeriod;
public PZOStrategy()
{
paramPeriod = CreateParameter("PZO Period", 14, 2, 252, 2);
}
protected override void Execute()
{
int period = paramPeriod.ValueInt;
DataSeries R = new DataSeries( Bars, "R" );
DataSeries TV = EMA.Series( Close, period, EMACalculation.Modern );
DataSeries PZO = new DataSeries( Bars, "PZO" );
ADX adx = ADX.Series( Bars,14 );
EMA ema = EMA.Series( Close, 60, EMACalculation.Modern );
for(int bar = period; bar < Bars.Count; bar++) {
Rbar = Math.Sign( Closebar - Closebar-1 ) * Closebar;
}
DataSeries VP = EMA.Series( R, period, EMACalculation.Modern );
for(int bar = period; bar < Bars.Count; bar++) {
if( TVbar != 0 )
PZObar = 100 * VPbar / TVbar;
}
ChartPane pzoPane = CreatePane( 30, true, true );
PlotSeriesOscillator( pzoPane, PZO, 60, -60, Color.Red, Color.Blue, Color.Black, LineStyle.Solid, 1 );
DrawHorzLine( pzoPane, 60, Color.DarkGreen, LineStyle.Dotted, 2 );
DrawHorzLine( pzoPane, -60, Color.Red, LineStyle.Dotted, 2 );
DrawHorzLine( pzoPane, 40, Color.DarkGreen, LineStyle.Solid, 1 );
DrawHorzLine( pzoPane, -40, Color.Red, LineStyle.Solid, 1 );
DrawHorzLine( pzoPane, 0, Color.DarkBlue, LineStyle.Solid, 1 );
ChartPane divPane = CreatePane( 30, true, true );
SeriesHelper sh = new SeriesHelper(this);
DataSeries pd = sh.PlotPeakDivergence(3, PricePane, High, 4d, pzoPane, PZO, 4d);
PlotSeries(divPane, pd, Color.Blue, LineStyle.Solid, 2);
DataSeries td = sh.PlotTroughDivergence(3, PricePane, Low, 4d, pzoPane, PZO, 4d);
PlotSeries(divPane, td, Color.Red, LineStyle.Solid, 2);
ChartPane adxPane = CreatePane( 30, true, true );
PlotSeries(adxPane, adx, Color.Purple, LineStyle.Histogram, 2);
DrawHorzLine(adxPane, 18, Color.Red, LineStyle.Dashed, 2 );
PlotSeries(PricePane, ema, Color.Blue, LineStyle.Solid, 1);
int start = Math.Max(adx.FirstValidValue,period);
start = Math.Max( start, ema.FirstValidValue );
for(int bar = start; bar < Bars.Count; bar++)
{
bool bull = adxbar > 18 && Closebar > emabar;
bool bear = adxbar > 18 && Closebar < emabar;
bool osc = adxbar < 18;
if( bull ) SetBackgroundColor( bar, Color.FromArgb( 30, Color.Blue ) );
if( bear ) SetBackgroundColor( bar, Color.FromArgb( 30, Color.Red ) );
if( osc ) SetBackgroundColor( bar, Color.FromArgb( 30, Color.Green ) );
if (IsLastPositionActive)
{
Position p = LastPosition;
if( p.PositionType == PositionType.Long ) {
if( p.EntrySignal.ToLower().Contains("uptrend") ) {
if( PZObar > 60 && TurnDown( bar, PZO ) ||
( Closebar < emabar && PZObar < 0 ) ||
(pdbar <= -1.0 && PZObar < 40.0) )
SellAtMarket( bar+1, p, "trend sell" );
}
else if( p.EntrySignal.ToLower().Contains("buy nontrend") ) {
if( PZObar > 40.0 ) {
if( adxbar > 18 )
SellAtMarket( bar+1, p, "nontrend sell rule #1" );
}
else {
if( PZObar < -5 )
SellAtMarket( bar+1, p, "nontrend sell rule #2" );
}
}
}
else {
if( p.EntrySignal.ToLower().Contains("downtrend") ) {
if( PZObar < -60 && TurnUp( bar, PZO ) ||
( Closebar > emabar && PZObar > 0 ) ||
(tdbar <= -1.0 && PZObar > -40.0) )
CoverAtMarket( bar+1, p, "trend cover" );
}
else if( p.EntrySignal.ToLower().Contains("short nontrend") ) {
if( PZObar < -40.0 ) {
if( adxbar > 18 )
CoverAtMarket( bar+1, p, "nontrend cover rule #1" );
}
else {
if( PZObar < -5 && CrossOver( bar, PZO, 15 ) )
CoverAtMarket( bar+1, p, "nontrend cover rule #2" );
}
}
}
}
else
{
bool buy = bull && ( CrossOver( bar, PZO, -40 ) || CrossOver( bar, PZO, 0 ) );
bool shrt = bear && ( CrossUnder( bar, PZO, 40 ) || CrossUnder( bar, PZO, 0 ) );
bool nt_buy = osc && (CrossOver( bar, PZO, -40 ) || CrossOver( bar, PZO, 15 ));
bool nt_shrt = osc && (CrossUnder( bar, PZO, 40 ) || CrossUnder( bar, PZO, -5 ));
if( buy ) {
SetBarColor( bar, Color.Blue );
BuyAtMarket( bar+1, "buy uptrend" );
}
else if( shrt ) {
SetBarColor( bar, Color.Red );
ShortAtMarket( bar+1, "short downtrend" );
}
else if( nt_buy ) {
SetBarColor( bar, Color.Cyan );
BuyAtMarket( bar+1, "buy nontrend" );
}
else if( nt_shrt ) {
SetBarColor( bar, Color.Orange );
ShortAtMarket( bar+1, "short nontrend" );
}
}
}
}
}
}