TRADERS’ TIPS
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.
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.
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.
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
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.
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.
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.
FIGURE 4: REALTEST. The sample results for the REIT strategy are shown here from RealTest software.
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.
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.
FIGURE 5: TRADINGVIEW. This TradingView chart demonstrates the REIT trading strategy applied on the SPDR Dow Jones REIT ETF (RWR).
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.
FIGURE 6: AIQ. Demonstrated here are selected setup screens for the EDS backtest of the REIT ETF trading system.
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
FIGURE 7: NEUROSHELL TRADER. This NeuroShell Trader chart demonstrates the REIT trading system applied to eight different REIT ETFs.