TRADERS’ TIPS

June 2024

Tips Article Thumbnail

For this month’s Traders’ Tips, the focus is Markos Katsanos’ article in this issue, “Is The Price REIT?” Here, we present the June 2024 Traders’ Tips code with possible implementations in various software.

You can right-click on any chart to open it in a new tab or window and view it at it’s originally supplied size, often much larger than the version printed in the magazine.

The Traders’ Tips section is provided to help the reader implement a selected technique from an article in this issue or another recent issue. The entries here are contributed by software developers or programmers for software that is capable of customization.


logo

TradeStation: June 2024

In the article “Is The Price REIT?” in this issue, Markos Katsanos provides an in-depth analysis of the REIT landscape and provides a weekly trading system for trading REIT stocks and REIT ETFs, centered around their correlation with interest rates.

The EasyLanguage code is provided here for the strategy. Within the “Strategy properties for all” window, the “Maximum number of bars study will reference” (MaxBarsBack) must be set to at least 100. The strategy requires three weekly symbols. Data1 should represent the REIT stock or REIT ETF for trading, while Data2 should correspond to SPY, and Data3 to $TNX.X.

// TASC JUNE 2024
// Weekly REIT Strategy
// Markos Katsanos

inputs:
	BBPeriod( 15 ),
	SDev( 2 ),
	TBars( 25 ),
	ChannelLength( 30 ),
	TNXPerc( 15 ),
	CorMax( 0.3 ),
	YieldMin( 2 ),
	ATRs( 1.5 ),
	MaxLossPerc( 8 );

variables:
	Yield( 0 ),
	Stoch( 0 ),
	TH( 0 ),
	TL( 0 ),
	TR( 0 ),
	ATR15( 0 ),
	LLT( 0 ),
	HHT( 0 ),
	TNXUp( 0 ),
	TNXDn( 0 ),
	LLBars( 0 ),
	LL( 0 ),
	PercUp( 0 ),
	Upper( 0 ),
	Cort( 0 ),
	Cors( 0 ),
	BBBOT( 0 ),
	BuyBB( false ),
	BuyTrend( false ),
	BuySignal( false ),
	Sell_1( false ),
	StrategyStop( false ),
	SellOB( false ),
	SellSignal( false );
	
Yield = Close of Data3 / 10;
Stoch = (Close - Lowest(Low, 10)) / (Highest(High, 10)
 - Lowest(Low, 10) + .0001) * 100;
Stoch = Average(Stoch, 3);

TH = MaxList(Close[1], High);
TL = MinList(Close[1], Low);
TR = TH - TL;
ATR15 = XAverage(TR, 15 * 2 -1);

LLT = Lowest(Close of Data3, TBars) of Data3;
HHT = Highest(Close of Data3, TBars) of Data3;
TNXUp = (Close of Data3 - LLT) / (LLT + .001) * 100;
TNXDn = (Close of Data3 - HHT) / (HHT + .001) * 100;
LL = Lowest(Low, 100);
PercUp = (Close - LL) / (LL + .001) * 100;
Upper = Highest(Close, ChannelLength)[1];
Cort = CoefficientR(Close, Close of Data3, 20);
Cors = CoefficientR(Close, Close of Data2, 20);
BBBOT = BollingerBand(Close, BBPeriod, -SDev);

StrategyStop = Close < Average(Close, 30)
 and Close < (1 - MAXLOSSPERC / 100 ) * Highest(Close, 2)
 and (Close of Data2  < (1 - MAXLOSSPERC / 100)
 * Close[1] of Data2 or Cors < 0);
 
BuyBB = (Low < BBBOT and Close > BBBOT + .2 * ATR15)
 and ((TNXDN < -TNXPERC
 and Cort < CorMax) or Yield < YieldMin)
 and Close > (High + Low) / 2
 and StrategyStop = false;
 
BuyTrend = Close > Upper and Close of Data2 >
 Average(Close of Data2, 20) of Data2
 and ( HighestBar(Close of Data3, ChannelLength) > 10
 or Cort > CorMax or Yield < YieldMin);
 
BuySignal = BuyBB or BuyTrend;

if BuySignal then
	Buy next bar at market;

Sell_1 = (TNXUp > TNXPerc or (Yield > 4 and TNXUp > 0))
 and Close < Highest(Close, 5) - ATRs * ATR15
 and BuyBB = false;
 
StrategyStop = Close < Average(Close, 30)
 and Close < (1 - MaxLossPerc / 100) * Close[1]
 and (Close of Data2 < (1 - MaxLossPerc / 100)
 * Close[1] of Data2 or Cors < 0);
SellOB = PercUp > 50 and Close < Highest(High, 3) - ATRs
 * ATR15 and Highest(Stoch, 3) > 90;

SellSignal = Sell_1 or SellOB or StrategyStop;

if SellSignal then
	Sell next bar at market;

A sample chart is shown in Figure 1.

Sample Chart

FIGURE 1: TRADESTATION. This TradeStation weekly chart of the Vanguard Real Estate ETF VNQ demonstrates the strategy applied.

This article is for informational purposes. No type of trading or investment recommendation, advice, or strategy is being made, given, or in any manner provided by TradeStation Securities or its affiliates.

—John Robinson
TradeStation Securities, Inc.
www.TradeStation.com

BACK TO LIST

logo

MetaStock: June 2024

Markos Katsanos’ article in this issue, “Is The Price REIT?” presents a system for trading REIT ETFs. Below are the MetaStock formulas for the backtest system. The article includes optimization variables, which must be defined in MetaStock’s System Tester (see Figure 2).

Name Description Minimum Maximum Step
OPT1 Bollinger Band Period 15 20 5
OPT2 Bollinger Band StDe 2 2 0.5
OPT3 Lookback period for TNX HH or LL 25 25 5
OPT4 Donchian Channel Length 30 30 5
OPT5 Minimum% TNX Change 15 25 5
OPT6 Maximum correlation for buy signal 0.2 0.3 0.1
OPT7 Minimum yield (TNX/10) 2 2 0.5
OPT8 ATR Stop Multiplier 1.5 1.5 0.5
OPT9 Maximum Stop Loss % 8 8 1

FIGURE 2: Metastock. Optimization variables can be defined in MetaStock’s system tester.

Those OPT variables must be replaced with numeric constants to use the formulas in a MetaStock exploration or MetaStock expert advisor.

Buy Order:
SPY:= Security("ONLINE:SPY", C);
TNX:= Security("ONLINE:TNX", C);

YLD:= TNX/10;
STO10:= Mov(Stoch(10,1),3,S);
ATR15:= Mov(ATR(1),15*2-1,E);

{ TNX HH &LL }
LLT:= LLV(TNX, OPT3);
HHT:= HHV(TNX, OPT3);
TNXUP:= (TNX-LLT)/(LLT+.001)*100;
TNXDN:= (TNX-HHT)/(HHT+.001)*100;

{ ETF HH & LL }
LL:= LLV(L,100);
PERCUP:= (C-LL)/(LL+.001)*100;
Upper:= Ref(HHV(C, OPT4),-1) ; { Donchian Upper Channel }

{ Correlations }
CORT:= Correl(C,TNX,20,0);
CORS:= Correl(C,SPY,20,0);

BBBOT:= BBandBot(C, OPT1, S, OPT2);

NoBuy:= C<Mov(C,30,S) AND C<(1-OPT9/100)*HHV(C,2) AND 
(SPY<(1-OPT9/100)*Ref(SPY,-1) OR CORS<0);

{ Buy Conditions }
BuyBB:= (L<BBBOT AND C>BBBOT+.2*ATR15) AND
((TNXDN<-OPT5 AND CORT<OPT6) OR YLD<OPT7)
AND C>(H+L)/2 AND NoBuy = 0;

BUYTrend:= C>UPPER AND SPY>Mov(SPY,20,S) AND 
(HHVBARS(TNX, OPT4)>10 OR CORT>OPT6 OR YLD<OPT7);

BuyBB OR BuyTrend

Sell Order:
SPY:= Security("ONLINE:SPY", C);
TNX:= Security("ONLINE:TNX", C);

YLD:= TNX/10;
STO10:= Mov(Stoch(10,1),3,S);
ATR15:= Mov(ATR(1),15*2-1,E);

LLT:= LLV(TNX, OPT3);
HHT:= HHV(TNX, OPT3);
TNXUP:= (TNX-LLT)/(LLT+.001)*100;
TNXDN:= (TNX-HHT)/(HHT+.001)*100;

LL:= LLV(L,100);
PERCUP:= (C-LL)/(LL+.001)*100;

CORT:= Correl(C,TNX,20,0);
CORS:= Correl(C,SPY,20,0);

BBBOT:= BBandBot(C, OPT1, S, OPT2);

NoBuy:= C<Mov(C,30,S) AND C<(1-OPT9/100)*HHV(C,2) AND 
(SPY<(1-OPT9/100)*Ref(SPY,-1) OR CORS<0);

{ Buy Conditions }
BuyBB:= (L<BBBOT AND C>BBBOT+.2*ATR15) AND
((TNXDN<-OPT5 AND CORT<OPT6) OR YLD<OPT7)
AND C>(H+L)/2 AND NoBuy = 0;

{ Sell Conditions }
Sell1:= (TNXUP> OPT5 OR (YLD>4 AND TNXUP>0) )
AND C<HHV(C,5)-OPT8*ATR15 AND BuyBB = 0;

STOP:= C<Mov(C,30,S) AND C<(1-OPT9/100)*Ref(C,-1)
AND (SPY<(1-OPT9/100)*Ref(SPY,-1) OR CORS<0);

SELLOB:= PERCUP>50 AND C<HHV(H,3)-OPT8*ATR(15) AND HHV(STO10,3)>90;

SELL1 OR SELLOB OR STOP

—William Golson
MetaStock Technical Support
www.MetaStock.com

BACK TO LIST

logo

NinjaTrader: June 2024

The REIT ETF strategy and indicator detailed in the article “Is The Price REIT?” in this issue by Markos Katsanos is available for download at the following link for NinjaTrader 8:

Once the file is downloaded, you can import the strategy and indicator into NinjaTrader 8 from within the control center by selecting Tools → Import → NinjaScript Add-On and then selecting the downloaded file for NinjaTrader 8.

You can review the strategy’s source code in NinjaTrader 8 by selecting the menu New → NinjaScript Editor → Strategies from within the control center window and selecting the “REITETFStrategy” file.

A sample chart displaying the indicator and strategy is shown in Figure 3.

Sample Chart

FIGURE 3: NINJATRADER. This demonstrates the REIT ETF strategy backtested on a VNQ weekly chart from January 1, 2007 to April 16, 2024, displaying results from January, 2020 to April 2024.

NinjaScript uses compiled DLLs that run native, not interpreted, to provide you with the highest performance possible.

—Brandon Haulk
NinjaTrader, LLC
www.ninjatrader.com

BACK TO LIST

logo

RealTest: June 2024

In the article “Is The Price REIT?” in this issue, author Markos Katsanos offers a strategy to trade REIT ETFs. The code shown below implements the author’s technique in RealTest (mhptrading.com).

Import:	
	// definition of data needed by this script (run once to import and create local file)
	
	DataSource:	Norgate
	IncludeList:	VNQ, IYR, RWR, ICF {"reits"}	// named list of REIT ETFs
	IncludeList:	SPY, %TNX, %FFYE	// other symbols used
	StartDate:	2006-01-01	// import at least two extra years
	EndDate:	Latest
	SaveAs:	reit_test.rtd

Settings:
	// settings to use when running tests
	
	DataFile:	reit_test.rtd	// the file created by import
	StartDate:	2009-01-31	// test date range
	EndDate:	2024-01-31
	BarSize:	Weekly	// use weekly bars
	RiskFreeRateSym:	%FFYE	// fed funds rate	
	CashIntPct:	-0.05	// assume %FFYE - 0.5% interest on free cash

Parameters:
	// constants used in data or strategy formulas
	
	BBPeriod:	from 15 to 20 step 5 def 15	// equivalent to AmiBroker "Optimize" statement
	SD:	2	// or can just state single values
	TBars:	25
	CL:	30
	TNXPerc:	15
	CorMax:	0.3
	YLDMin:	2
	ATRS:	1.5
	MaxLossPerc:	8
	
Data:
	// arrays to calculate before any tests are run
	
	// external symbols
	SPY:	Extern($SPY, C)
	TNX:	Extern($%TNX, C)
	// stochastics (internal calcs match author's method)
	STOCH:	STOC(10, 3)
	// ATR (ditto - Wilder's smoothing is used)
	ATR15:	ATR(15)
	// TNX HH & LL
	LLT:	LLV(TNX, TBars)
	HHT:	HHV(TNX, TBars)
	TNXUP:	(TNX - LLT) / (LLT + .001) * 100
	TNXDN:	(TNX - HHT) / (HHT + .001) * 100
	// ETFs HH & LL
	LL:	LLV(L, 100) // no need to check BarNum < 100 since 2 extra years were imported
	PERCup:	(C - LL) / (LL + .001) * 100
	Upper:	HHV(C, CL)[1]
	// Correlations
	CORT:	Correl(C, TNX, 20) // Pearson's
	CORS:	Correl(C, SPY, 20)
	BBottom:	BBBOT(BBPeriod, SD)
	// Entry/Exit conditions
	Stop:	C < MA(C,30) AND C < (1-MaxLossPerc/100) * C[1] AND (SPY < (1-MaxLossPerc/100) * SPY[1] OR CORS < 0)
	BuyBB:	(L < BBottom AND C > BBottom + .2 * ATR15) AND ((TNXDN < -TNXPerc AND CORT < CorMax) OR TNX < YLDMin) AND C > (H + L) / 2 AND not STOP
	BuyTrend:	C > Upper AND SPY>MA(SPY, 20) AND (SinceHigh(TNX, CL) > 10 OR CORT > CORMax OR TNX < YLDMin)
	Sell1:	(TNXUP >TNXPerc OR (TNX > 4 AND TNXUP > 0)) AND C < HHV(C, 5) - ATRS * ATR15 AND not BuyBB
	SellOB:	PERCup > 50 AND C < HHV(H, 3) - ATRS * ATR(15) AND HHV(STOCH, 3) > 90
	
Strategy: reit_etf
	// strategy definition (in this case a very simple one)
	
	Side:	Long
	EntrySetup:	InList("reits") and (BuyBB or BuyTrend)
	ExitRule:	Sell1 or SellOB or Stop

Note: To run the code for each REIT ETF separately, press “optimize” and select the “For each symbol” option.

This produces the output shown in Figure 4. Note that the results are similar but not identical to the author’s. The somewhat better stats are due to the fact that RealTest’s compounding model includes reinvestment of dividends and interest.

Sample Chart

FIGURE 4: REALTEST. The sample results for the REIT strategy are shown here from RealTest software.

—Marsten Parker
MHP Trading, Mhptrading.com
mhp@mhptrading.com

BACK TO LIST

logo

Wealth-Lab.com: June 2024

We’ve coded the REIT system’s trading rules given in Markos Katsanos’ article in this issue in C# for Wealth-Lab.

using WealthLab.Backtest;
using System;
using WealthLab.Core;
using WealthLab.Data;
using WealthLab.Indicators;
using System.Collections.Generic;

namespace WealthScript1 
{
    public class MyStrategy : UserStrategyBase
    {
        public MyStrategy()
        {
            AddParameter("Lookback period for TNX HH or LL", ParameterType.Int32, 25, 25, 25, 5);
			AddParameter("Donchian Channel Length", ParameterType.Int32, 30, 30, 30, 5);
			AddParameter("Bollinger Band Period", ParameterType.Int32, 15, 15, 20, 5); 
			AddParameter("Bollinger Band StDev", ParameterType.Double, 2, 2, 2, 0.5); 
			AddParameter("Min% TNX Change", ParameterType.Int32, 15, 15, 25, 5);
			AddParameter("Max correlation for buy signal", ParameterType.Double, 0.3, 0.2, 0.2, 0.1);
			AddParameter("Min yield (TNX/10)", ParameterType.Double, 2, 2, 2, 0.5);
			AddParameter("Stop Loss", ParameterType.Int32, 8, 8, 8, 1);
			AddParameter("ATR Stop", ParameterType.Double, 1.5, 1.5, 1.5, 0.5);
		}

        public override void Initialize (BarHistory bars)
        {
			spy = GetHistory (bars, _spy);
			tnx = GetHistory (bars, _2nd);

			stoch = StochD.Series(bars, stochPeriod, stochSmoothing);
			hhvStoch = Highest.Series(stoch, 3);
			atr = ATR.Series(bars, atrPeriod);

			/* TNX HH &LL */
			tbars = Parameters[0].AsInt;
			var llt = Lowest.Series(tnx.Close, tbars); 
			var hht = Highest.Series(tnx.Close, tbars); 
			tnxUp = (tnx.Close - llt) / (llt + .001) * 100;
			tnxDn = (tnx.Close - hht) / (hht  + .001) * 100;

			/* ETF HH & LL */
			cl = Parameters[1].AsInt;
			var ll = Lowest.Series(bars.Low, llbars);
			percUp = (bars.Close - ll) / (ll + .001) * 100;
			upper = Highest.Series(bars.Close, cl) >> -1; /* Donchian Upper Channel */

			/* Pearson’s Correlation */
			bbPeriod = Parameters[2].AsInt;
			sd = Parameters[3].AsDouble;
			corT = Corr.Series(bars, _2nd, PriceComponent.Close, 20);
			corS = Corr.Series(bars, _spy, PriceComponent.Close, 20);
			bbBot = SMA.Series(bars.Close, bbPeriod) - sd * StdDev.Series(bars.Close, bbPeriod);

			tnxPerc = Parameters[4].AsInt;
			corMax = Parameters[5].AsDouble;
			yld = tnx.Close / 10d;
			yldMin = Parameters[6].AsDouble;
			
			sma30 = SMA.Series(bars.Close, 30);
			maxLossPerc = Parameters[7].AsInt;
			hhv2 = Highest.Series(bars.Close, 2);
			hhv3 = Highest.Series(bars.Close, 3);
			spyMA = SMA.Series(spy.Close, 20);
			hhvBars = TimeSeries.BarsSince( tnx.High >= Highest.Series(tnx.High, cl));
			atrs = Parameters[8].AsDouble;
		}

        public override void Execute (BarHistory bars, int idx)
        {
			bool stop = bars.Close[idx] < sma30[idx] && bars.Close[idx] < ((1 - maxLossPerc / 100d)*hhv2[idx]) && 
				((spy.Close[idx] < ((1 - maxLossPerc / 100d) * spy.Close[idx - 1])) || corS[idx] < 0);
			var buyBB = (bars.Low[idx] < bbBot[idx] && bars.Close[idx] > bbBot[idx] + 0.2 * atr[idx]) &&
				((tnxDn[idx] < -tnxPerc && corT[idx] < corMax) || yld[idx] < yldMin) &&
				bars.Close[idx] > bars.AveragePriceHL[idx] && !stop;

			if (! HasOpenPosition (bars, PositionType.Long))
            {
				var buyTrend = bars.Close[idx] > upper[idx] && spy.Close[idx] > spyMA[idx] && hhvBars[idx] > 10 || corT[idx] > corMax || yld[idx] < yldMin;
				var buy = buyBB || buyTrend;

				if(buy)
					PlaceTrade(bars, TransactionType.Buy, OrderType.Market);
			}
            else
            {
				/* Chandelier Sell Stop */
				var Sell1 = (tnxUp[idx] > tnxPerc || (yld[idx] > 4 && tnxUp[idx] > 0) ) && bars.Close[idx] < (hhv3[idx]-atrs * atr[idx]) && !buyBB;

				/* Stop Loss */
				var Stop = bars.Close[idx] < sma30[idx] && 
					((bars.Close[idx] < ((1 - maxLossPerc / 100d) * bars.Close[idx - 1])) &&
					((spy.Close[idx] < ((1 - maxLossPerc / 100d) * spy.Close[idx - 1])) ||corS[idx] < 0));
				var SellOB = percUp[idx] > 50 && bars.Close[idx] < (hhv3[idx] - atrs * atr[idx]) && hhvStoch[idx] > 90;
				var Sell = Sell1 || SellOB || Stop;

				if (Sell)
					PlaceTrade(bars, TransactionType.Sell, OrderType.Market);
			}
        }

		/* declare private variables below */
		BarHistory tnx, spy;
		int stochPeriod = 0, stochSmoothing = 3, atrPeriod = 15, tbars, llbars = 100, cl, bbPeriod, tnxPerc, maxLossPerc;
		double sd, corMax, yldMin, atrs;
		string _2nd = "^TNX", _spy = "SPY";
		TimeSeries bbBot, corT, corS, atr, tnxUp, tnxDn, yld, sma30, hhv2, hhv3, upper, spyMA, hhvBars, percUp, stoch, hhvStoch;
	}
}

Since it uses Yahoo’s ^TNX as the symbol for the CBOE 10-Year Treasury Note Yield Index, to run it properly you should either check Yahoo Finance’s “Data Manager’s Historical Providers” list or choose the symbol name of your preferred data provider.

—Gene Geren (Eugene)
Wealth-Lab team
www.wealth-lab.com

BACK TO LIST

logo

TradingView: June 2024

The TradingView Pine Script code below implements the REIT ETF trading system described in Markos Katsanos’ article in this issue, “Is The Price REIT?” It functions as a strategy script, displaying filled order marks on the chart and providing performance metrics in the Strategy Tester tab beneath the TradingView chart.

//  TASC Issue: December 2024 - Vol. 42, Issue 6
//     Article: Is The Price REIT?
//              An Approach To Real Estate Investment Trusts
//  Article By: Markos Katsanos
//    Language: TradingView's Pine Script™ v5
// Provided By: PineCoders, for tradingview.com


//@version=5
string it  = 'TASC 2024.06 REIT ETF Trading System'
string st  = 'REIT TS'
strategy(it, st, true)


// --- Inputs ---
string it0 = 'Bollinger Bands Length'
string it1 = 'Bollinger Bands Multiplier'
string it2 = 'Lookback Period for TNX Index'
string it3 = 'Min TNX Change, %'
string it4 = 'Donchian Channel Length'
string it5 = 'Max Correlation for Buy Signal'
string it6 = 'Min Yield (TNX/10)'
string it7 = 'ATR Stop'
string it8 = 'Stop Loss, %'


int    iBBlen = input.int(15, it0)
float  iBBmul = input.float(2.0, it1)
int   iTNXlen = input.int(25, it2)
int   iTNXper = input.int(15, it3)
int    iDClen = input.int(30, it4)
float iCORmax = input.float(0.3, it5)
float iYLDmin = input.float(2.0, it6)
float iATRstp = input.float(1.5, it7)
int   iMAXlos = input.int(8, it8)


// --- Helper Functions ---
NotAtLoss (float src, float limit) =>
    src < ((1.0 - iMAXlos / 100.0) * limit)


// --- Calculations ---
if not timeframe.isweekly
    string er0 = 'The script should be applied on '+
                 'a WEEKLY chart of any REIT ETF.'
    runtime.error(er0)


// Reference indices (SPY and TNX)
float spy = request.security('SPY', timeframe.period, close, 
                   barmerge.gaps_on, barmerge.lookahead_off)
float tnx = request.security('TNX', timeframe.period, close, 
                   barmerge.gaps_on, barmerge.lookahead_off)


// Treasury Yield, Stochastic, ATR
float yld     = tnx / 10.0
float stoch   = ta.sma(ta.stoch(close, high, low, 10), 3)
float atr15   = ta.atr(15)


// HH & LL of TNX
float TNXll   = ta.lowest(tnx, iTNXlen)
float TNXhh   = ta.highest(tnx, iTNXlen)
float TNXup   = ((tnx - TNXll) / (TNXll + 0.001)) * 100.0
float TNXdn   = ((tnx - TNXhh) / (TNXhh + 0.001)) * 100.0


// HH & LL of ETF
int   LLbars  = bar_index >= 100 ? 100 : bar_index + 1
float ll      = ta.lowest(low, LLbars)
float PERCup  = (close - ll) / (ll + 0.001) * 100.0
float DCupper = ta.highest(close, iDClen)[1] 


// Correlations
float CORt    = ta.correlation(close, tnx, 20)
float CORs    = ta.correlation(close, spy, 20)
float BBlower = ta.sma(close, iBBlen) -
     iBBmul * ta.stdev(close, iBBlen)
bool  isStop  = close < ta.sma(close, 30) and 
     NotAtLoss(close, ta.highest(close, 2)) and 
     NotAtLoss(spy, spy[1]) or 
     CORs < 0


// Trade Signals
bool BuyBB    = (low < BBlower and 
     close > BBlower + 0.2 * atr15) and 
     ((TNXdn < -iTNXper and CORt < iCORmax) or 
     yld < iYLDmin) and close > hl2 and not isStop
bool BuyTrend = close > DCupper and
     spy > ta.sma(spy, 20) and 
     (ta.highest(tnx, iTNXlen) > 10.0 or 
     CORt > iCORmax or yld < iYLDmin)


// Stop Loss
bool Sell1  = (TNXup > iTNXper or 
     (yld > 4.0 and TNXup > 0.0)) and 
     close < ta.highest(close, 5) - iATRstp * atr15 and 
     not BuyBB  // Chandelier Exit
bool Stop0  = close < ta.sma(close, 30) and 
     NotAtLoss(close, close[1]) and 
     NotAtLoss(spy, spy[1]) or 
     CORs < 0 
bool SellOB = PERCup > 50.0 and 
     close < ta.highest(high, 3) - iATRstp * atr15 and 
     ta.highest(stoch, 3) > 90


// Execution
switch
    BuyBB =>
        strategy.entry("BUY BB", strategy.long)
    BuyTrend => 
        strategy.entry("BUY Trend", strategy.long)
    Sell1 =>
        strategy.close_all('STOP Trail')
    SellOB =>
        strategy.close_all('STOP OB')
    Stop0 =>
        strategy.close_all('STOP Stop')

The indicator is available on TradingView from the PineCodersTASC account at https://www.tradingview.com/u/PineCodersTASC/#published-scripts.

An example chart is shown in Figure 5.

Sample Chart

FIGURE 5: TRADINGVIEW. This TradingView chart demonstrates the REIT trading strategy applied on the SPDR Dow Jones REIT ETF (RWR).

—PineCoders, for TradingView
www.TradingView.com

BACK TO LIST

logo

AIQ: June 2024

The importable AIQ EDS file based on Markos Katsanos’ article in this issue, “Is The Price REIT?” can be obtained on request via rdencpa@gmail.com. The code is also shown below.

! Is The Price REIT?
! Author: Markos Katsanos, TASC June 2024
! Coded by: Richard Denning 4/17/2024

!INPUTS:
BBPERIOD is 15.
SD is 2.
TBARS is 25.
CL is 30.
TNXPERC is 15.
CORMAX is 0.3.
YLDMIN is 2.
ATRS is 1.5.
MAXLOSSPERC is 8.
!IMSEC2 is "SPY".
!IMSEC3 is "TNX".

C is [close].
C1 is valresult(C,2).
H is [high].
L is [low].

!FORMULAS:
SPYc is tickerudf("SPY",C).
TNXc is tickerudf("TNX",C).
YLD is TNXc/10.
STOCH is (C-lowresult(L,10))/(highresult(H,10)-lowresult(L,10)+0.0001)*100.
STOCHavg is simpleavg(STOCH,3).
TH is max(C1,H).
TL is min(C1,L).
TR is TH - TL.
ATR15 is expavg(TR,15*2-1).

LLT is lowresult(TNXc,TBARS).
HHT is highresult(TNXc,TBARS).
TNXUP is (TNXc-LLT)/(LLT+0.001)*100.
TNXDN is (TNXc-HHT)/(HHT+0.001)*100.

HDF is hasdatafor(110).
LLBARS is iff(HDF>100,100,HDF).
LL is lowresult(L, LLBARS).
PERCUP is (C-LL)/(LL+ 0.001)*100.
Upper is valresult(highresult(C,CL),1).
StDev is sqrt(variance(C,BBPERIOD)).
BBBOT is simpleavg(C,BBPERIOD)-SD*StDev.
STOP if C<simpleavg(C,30) AND C<(1-MAXLOSSPERC/100)*highresult(C,2)
AND (SPYc<(1-MAXLOSSPERC/100)*valresult(SPYc,1) OR CORS<0).
BuyBB if (L<BBBOT AND C>BBBOT+0.2*ATR15) AND
((TNXDN<-TNXPERC AND CORT<CORMAX) OR YLD<YLDMIN)
AND C>(H+L)/2 AND not STOP.
BUYTrend if C>UPPER AND SPYc>simpleavg(SPYc,20)
AND ( highresult(TNXc,CL)>10 OR CORT>CORMAX OR
YLD<YLDMIN).
Buy if BuyBB OR BuyTrend.

! Chandelier Sell Stop
SELL1 if (TNXUP>TNXPERC OR (YLD>4 AND TNXUP>0) )
AND C<highresult(C,5)-ATRS*ATR15 AND not BuyBB.

! Stop Loss
SELLOB if PERCUP>50 AND C<highresult(H,3)-ATRS*ATR15 AND
highresult(STOCH,3)>90. 
ExitLong if SELL1 OR SELLOB OR STOP.

!PEARSON CORRELATION TO SPY:
N is 20.
rC is (C / C1 - 1) * 100.
!SPYc is TickerUDF("SPY",C) .
rSPYc is (SPYc / valresult(SPYc,1) - 1) * 100.
stdDx is sqrt(variance(rC,N)).
Zx is (rC - simpleavg(rC,N)) / stdDx.
stdDy is sqrt(variance(rSPYc,N)).
Zy is (rSPYc - simpleavg(rSPYc,N)) / stdDy.
HD if hasdatafor(N*2) >= N.
Sr is iff(HD,simpleavg(Zx*Zy,N) * 1000,0).
SPYr is TickerUDF("SPY",Sr).
r is Sr / SPYr * 1000.
CORS is r.

!PEARSON CORRELATION TO TNX:
!TNXc is TickerUDF("TNX",C) .
rTNXc is (SPYc / valresult(TNXc,1) - 1) * 100.
stdDyT is sqrt(variance(rTNXc,N)).
ZyT is (rTNXc - simpleavg(rTNXc,N)) / stdDyT.
SrT is iff(HD,simpleavg(Zx*ZyT,N) * 1000,0).
TNXr is TickerUDF("TNX",SrT).
rT is SrT / TNXr * 1000 .
CORT is rT.

The code for the author’s system is set up in the AIQ EDS code file. To run a backtest of the system in AIQ EDS, first make a list of the ETFs that you want to test. Then set up the backtest as shown in Figure 6.

Sample Chart

FIGURE 6: AIQ. Demonstrated here are selected setup screens for the EDS backtest of the REIT ETF trading system.

—Richard Denning
rdencpa@gmail.com
for AIQ Systems

BACK TO LIST

logo

Neuroshell Trader: June 2024

The REIT trading system presented in Markos Katsanos’ article in this issue, “Is The Price REIT?”, can be easily implemented in NeuroShell Trader by combining some of NeuroShell Trader’s 800+ indicators. To implement the indicators, select “New indicator…” from the insert menu and use the indicator wizard to create the following indicators:

STOP  
And3( Price<Avg(Close,30),
            A<B(Close,Mul2(Sub(1,Divide(8,100)),Lag(Close,1))),
            Or2( A<B(SPY Close,Mul2(Sub(1,Divide(8,100)),Lag(SPY Close,1))),
                     A<B(LinXYReg r(Close,SPY Close,20),0)))

BuyBB 
And4( And2( A<B(Low,BB Low(Close,15,2)),
                        A>B(Close,Add2(BB Low(Close,15,2),Mul2(0.2,ATR(High,Low,Close,15))))),
            Or2( And2( A<B(Mul2(Sub(Divide(TNX Close,Max(TNX Close,25)),1),100),-15), 
                               A<B(LinXYReg r(Close,TNX Close,20),0.3)),
                     A<B(Divide(TNX Close,10),2)),
            A>B(Close,Avg2(High,Low)),
            Not(STOP))

BUYTrend
And3( A>B(Close,Lag(Max(Close,30),1)),
            Price>Avg(SPY Close,20),
            Or3( A>B(Max(TNX Close,30),
                     Max(TNX Close,10)),
                     A>B(LinXYReg r(Close,TNX Close,20),0.3),A<B(Divide(TNX Close,10),2)))

Sell1 
And3( Or2( A>B(Mul2(Sub(Divide(TNX Close,Min(TNX Close,25)),1),100),15),
                     And2( A>B(Divide(TNX Close,10),4),
                                 A>B(Mul2(Sub(Divide(TNX Close,Min(TNX Close,25)),1),100),0))),
            A<B(Close,Sub(Max(Close,5),Mul2(1.5,ATR(High,Low,Close,15)))),
            Not(BuyBB))

SELLOB 
And3( A>B(Mul2(Sub(Divide(Close,Min(Low,100)),1),100),50),
            A<B(Close,Sub(Max(High,3),Mul2(1.5,ATR(High,Low,Close,15)))),
            A>B(Max(Stoch%D(High,Low,Close,10,3),3),90))

To implement the trading system, select “New strategy…” from the insert menu and use the trading strategy wizard to create the following strategy:

BUY LONG CONDITIONS: [1 of which must be true]
     BuyBB
     BUYTrend

SELL LONG CONDITIONS: [1 of which must be true]
     Sell1
     SELLOB
     STOP
Sample Chart

FIGURE 7: NEUROSHELL TRADER. This NeuroShell Trader chart demonstrates the REIT trading system applied to eight different REIT ETFs.

—Ward Systems Group, Inc.
sales@wardsystems.com
www.neuroshell.com

BACK TO LIST

Originally published in the June 2024 issue of
Technical Analysis of STOCKS & COMMODITIES magazine.
All rights reserved. © Copyright 2024, Technical Analysis, Inc.