Traders' Tip text
Voting is a trend and buzzword of the second half of 2020. This month's Traders' Tips article by F. Arden Thomas on voting has come in due time, even though its voting indicator doesn’t consider elections or their impact on the markets. His multi-timeframe voting is an interesting concept that applies to many common indicators like the RSI or ADX, not just the Stochastic.
Firstly, a note regarding his so called "Quarter Quarterly" scale. A quarter is 13 weeks, so it’s roughly a "3.25 times Weekly" or "16.25 Daily" scale (given there are 5 trading days in a week). Since Bi-Weekly and Monthly scales contain 10 and 22 trading days (respectively), it doesn't look like the new scale would be that necessary to bring much difference from either Bi-Weekly or Monthly.
Out of the box, Wealth-Lab does not support custom chart scales like Bi-Weekly or Half-Quarterly. Alhtough the scales like Bi-Weekly or Quarter Quarterly could be accomplished fairly easily using the
EOD Scaling Provider (a Wealth-Lab addon), we felt it would make more sense if the voting process considered intraday data instead. As a result, our aggregate voting indicator polls for the 21-period Stochastic readings on 60-minute, Daily, Weekly, Monthly, Quarterly and Yearly time frames.
The code below requires intraday data which you can get for free or on a subscription basis from different providers such as Tiingo, Alpha Vantage or DTN IQFeed. We use a modified version of author’s Example 2 which can take multiple positions in the same symbol.
Strategy rules:
- Long setup: Buying pressure >= 5
- Buy tomorrow at open each time when selling pressure is greater than 0
- Sell tomorrow at open if selling pressure = 0
Figure 1. Sample entries on a Daily chart of Halliburton. Data provided by Tiingo, source: IEX exchange.As seen on Figure 1, the trading system just marks the entries. You can make it more reactive by relaxing the exit condition - for example, require a greater selling pressure to sell (e.g. >= 1).
If you're interested in more trading systems of the kind that operate in multiple time frames, explore the classic and built-in "Elder Triple Screen" and
"RSI Trifecta" strategies. Just like this month's strategy and many other contributed by the Wealth-Lab community, you can download and execute them in Wealth-Lab. To do it, choose "Download" from "Open Strategy" dialog (Ctrl-O).
WealthScript Code (C#)
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
namespace WealthLab.Strategies
{
public class TradersTips_Nov2020 : WealthScript
{
protected override void Execute()
{
int Period = 21;
var ls = LineStyle.Solid;
HideVolume();
// Access the symbol from a DataSet whose base scale is intraday. Do not synch yet!
Bars i60 = GetExternalSymbol("Tiingo (Minute,60)", Bars.Symbol, false);
// Apply the indicator in the intraday scale
DataSeries sto_60 = StochK.Series(i60, Period); sto_60.Description = "60-minute";
SetScaleDaily();
DataSeries sto_d = StochK.Series(Bars, Period); sto_d.Description = "Daily";
SetScaleWeekly();
DataSeries sto_w = StochK.Series(Bars, Period); sto_w.Description = "Weekly";
SetScaleMonthly();
DataSeries sto_m = StochK.Series(Bars, Period); sto_m.Description = "Monthly";
RestoreScale();
DataSeries sto_q = StochK.Series(BarScaleConverter.ToQuarterly(Bars), Period);
DataSeries sto_y = StochK.Series(BarScaleConverter.ToYearly(Bars), Period);
sto_q.Description = "Quarterly"; sto_y.Description = "Yearly";
sto_60 = Synchronize( sto_60);
sto_d = Synchronize( sto_d); sto_w = Synchronize( sto_w);
sto_m = Synchronize( sto_m); sto_q = Synchronize( sto_q); sto_y = Synchronize( sto_y);
//Determine the first valid bar
var start = Math.Max(sto_60.FirstValidValue,
Math.Max(sto_d.FirstValidValue,
Math.Max(sto_w.FirstValidValue,
Math.Max(sto_m.FirstValidValue,
Math.Max(sto_q.FirstValidValue, sto_y.FirstValidValue)))));
ChartPane sPane = CreatePane( 20, false, true);
PlotSeries( sPane, sto_60, Color.Peru, ls, 1);
PlotSeries( sPane, sto_d, Color.Chartreuse, ls, 1);
PlotSeries( sPane, sto_w, Color.Gainsboro, ls, 1);
PlotSeries( sPane, sto_m, Color.Sienna, ls, 1);
PlotSeries( sPane, sto_q, Color.IndianRed, ls, 1);
PlotSeries( sPane, sto_y, Color.NavajoWhite, ls, 1);
DataSeries buyVote = new DataSeries(Bars, "Buy Voting");
DataSeries sellVote = new DataSeries(Bars, "Sell Voting");
for (int bar = 1; bar < Bars.Count; bar++)
{
if (sto_60bar < 20) buyVotebar++;
if (sto_dbar < 20) buyVotebar++;
if (sto_wbar < 20) buyVotebar++;
if (sto_mbar < 20) buyVotebar++;
if (sto_qbar < 20) buyVotebar++;
if (sto_ybar < 20) buyVotebar++;
if (sto_60bar > 80) sellVotebar++;
if (sto_dbar > 80) sellVotebar++;
if (sto_wbar > 80) sellVotebar++;
if (sto_mbar > 80) sellVotebar++;
if (sto_qbar > 80) sellVotebar++;
if (sto_ybar > 80) sellVotebar++;
}
ChartPane vPane = CreatePane( 40, false, true );
PlotSeries( vPane, buyVote, Color.Blue, ls, 1);
PlotSeries( vPane, sellVote, Color.Red, ls, 1);
DrawHorzLine( vPane, 20, Color.Blue, LineStyle.Dashed, 1);
DrawHorzLine( vPane, 80, Color.Red, LineStyle.Dashed, 1);
bool setup = false; int setupBar = -1;
//Start trading only after all DataSeries are complete
for (int bar = start; bar < Bars.Count; bar++)
{
bool buySetup = buyVotebar >= 5 && sellVotebar == 0;
bool buyTrigger = sellVotebar > 0;
for (int pos = ActivePositions.Count - 1; pos >= 0; pos--)
{
Position p = ActivePositionspos;
if (buyVotebar == 0)
SellAtMarket( bar + 1, p);
}
if (!setup)
{
if (buySetup)
{
setup = true;
setupBar = bar;
}
}
if (setup)
{
if (buyTrigger)
if ( BuyAtMarket( bar + 1) != null )
setup = false;
SetBackgroundColor( bar, Color.FromArgb(30, Color.Green));
}
}
}
}
}
Gene Geren (Eugene)
Wealth-Lab team