Traders' Tip text
Out of possible ways of detecting divergences, in our past "Traders' Tips" we have already presented two. One sophisticated technique which could be found in 2008-02 tip
"Trading Medium-Term Divergences" (Vervoort), detects and highlights divergences by any indicator. Since it relies on finding peaks and troughs, price must retrace by some amount before a peak/trough occurs. Another approach, found in 2008-07 tip
"Leader of the MACD" (Siligardos), is simplistic, identifying a divergence between price and indicator when it fails to confirm a price extreme (e.g. highest high). Relying on price action makes it act a tad quicker.
The system we're presenting in this issue catches bullish divergences of Asymmetric RSI with price based on the 2nd approach. As seen on Figure 1, two potentially profitable opportunities could be taken as a result of timely signaling from the 14-period ARSI, which in its turn seems to be really responsive -- as much as the half-period RSI.
Figure 1. Illustrating on a long trade in OIH ETF, the ARSI turns out to signal two timely bullish divergence trades.
Traders might like to explore the ARSI crossovers and crossunders, because the threshold levels are reached more timely than with the classic RSI. The strategy exits after 20 bars neutrally. It offers room for improvement, however a quick testing with 1000 bars of daily data on the diversified portfolio containing 16 most liquid ETFs turned out profitable.
Note that you can find ARSI in your Wealth-Lab installation, organized under the TASC Magazine Indicators group. This allows to quickly use it in Rule-based Strategies as an entry or exit condition without having to program a line of code yourself.
Figure 2. A chart that combines the portfolio equity curve with the drawdown chart indicates overall profitability of the approach.
Strategy Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
using TASCIndicators;
namespace WealthLab.Strategies
{
/*
ARSI divergence:
Price sets a lowest low but the indicator fails to confirm the new low and turns up
*/
public class ARSI_Divergence : WealthScript
{
private StrategyParameter paramHighest;
private StrategyParameter paramPeriod;
private StrategyParameter paramExitDays;
public ARSI_Divergence()
{
paramPeriod = CreateParameter("ARSI period", 14, 1, 100, 1);
paramHighest = CreateParameter("Highest high of", 20, 5, 50, 1);
paramExitDays = CreateParameter("Exit after", 20, 1, 50, 1);
}
protected override void Execute()
{
bool trough = false; int troughBar = -1;
int low = paramHighest.ValueInt;
int period = paramPeriod.ValueInt;
int days = paramExitDays.ValueInt;
ARSI arsi = ARSI.Series( Close, period );
Lowest indicatorLowest = Lowest.Series( arsi, low );
Lowest hLow = Lowest.Series( Low, low );
HideVolume(); LineStyle solid = LineStyle.Solid;
ChartPane arsiPane = CreatePane( 50, false, true );
PlotSeries( arsiPane, arsi, Color.Green, solid, 2 );
PlotSeries( arsiPane, RSI.Series( Close, period ), Color.Red, solid, 1 );
for(int bar = 80; bar < Bars.Count; bar++)
{
if (!IsLastPositionActive)
{
/* 1st trough: both price and indicator */
if( trough == false )
{
if( ( Lowbar-1 == Lowest.Series( Low, low )bar-1 )
& ( arsibar-1 == Lowest.Series( arsi, low )bar-1 )
& TurnUp( bar, Low ) & TurnUp( bar, arsi ) )
{
trough = true; troughBar = bar-1;
}
}
if( trough == true )
{
if( ( Lowbar != Lowest.Series( Low, low )bar )
& ( arsibar == Lowest.Series( arsi, low )bar ) )
trough = false;
}
/* 2nd trough: price low not confirmed by the indicator */
if( trough == true )
{
if( ( Lowbar-1 == Lowest.Series( Low, low )bar-1 )
& ( Lowbar-1 <= LowtroughBar )
& ( arsibar-1 != Lowest.Series( arsi, low )bar-1 )
& ( arsibar-1 > arsitroughBar ) &
TurnUp( bar, Low ) & TurnUp( bar, arsi ) )
{
trough = false;
BuyAtMarket( bar+1 );
/* Highlight divergence */
for (int b = troughBar; b <= bar; b++)
SetPaneBackgroundColor( arsiPane, b,
Color.FromArgb( 30, Color.LightGreen ) );
DrawLine( PricePane, troughBar, LowtroughBar,
bar-1, Lowbar-1, Color.Blue, solid, 2 );
DrawLine( arsiPane, troughBar, arsitroughBar,
bar-1, arsibar-1, Color.Red, solid, 2 );
}
}
} else
{
/* Exit after N days */
Position p = LastPosition;
if ( bar+1 - p.EntryBar >= days )
SellAtMarket( bar+1, p, "Timed" );
}
}
}
}
}