Welcome Features News Download Registration Support FAQ Wish list Links
Advanced stock charting and analysis program

AFL Library

This is read-only version of AFL library entry. Ability to add user formulas and comment is only available from members-only area.

Details:

Formula name: Ed Seykota's TSP: Support and Resistance
Author/Uploader: Mark H. - mdhuang1gmailcom
Date/Time added: 2006-10-08 01:48:31
Origin:
Keywords:
Level: semi-advanced
Flags: system,exploration,indicator

DISCLAIMER: Most formulas present in AFL on-line library are submitted by the users and are provided here on an "as is" and "as available" basis. AmiBroker.com makes no representations or warranties of any kind to the contents or the operation of material presented here. We do not maintain nor provide technical support for 3rd party formulas.
Description:

This is an implementation of Seykota's TSP S-R system.
See http://www.seykota.com/tribe/TSP/SR/index.htm for details.
I have tested it and got identical results (well there is 2-cent difference due to rounding).

Formula:

/*==============================================================================
	Global Settings
==============================================================================*/
SetOption("InitialEquity", 1000000);
SetOption("NoDefaultColumns", True );
SetOption("CommissionMode", 2); //$$ per trade
SetOption("CommissionAmount", 0);
SetOption("MarginRequirement", 10);
SetOption("UsePrevBarEquityForPosSizing", True);
SetOption("UseCustomBacktestProc", True );

SetTradeDelays( 0, 0, 0, 0 );

/*==============================================================================
	User-defined Functions
==============================================================================*/
function Support(p)
{
	sup = LLV(low, p);
	sup[0] = low[0];
	for (i = 1; i < p; i++)
	{
		if(low[i] < sup[i-1]) sup[i] = low[i];
		else sup[i] = sup[i-1];
	}	
	return sup;
}

function Resistance(p)
{
	res = HHV(high, p);
	res[0] = high[0];
	for (i = 1; i < p; i++)
	{
		if(high[i] > res[i-1]) res[i] = high[i];
	  	else res[i] = res[i-1];
	}
	return res;
}	
	
function OptimizeNot(a1, a2, a3, a4, a5)
{
	return a2;
}

/*==============================================================================
	Entry and Exit Rules
==============================================================================*/
fast = Optimize("Fast", 20, 5, 105, 5);
slow = Optimize("Slow", 140, 20, 420, 20);
FastRes = Resistance(fast);
FastSup = Support(fast);
SlowRes = Resistance(slow);
SlowSup = Support(slow);
heat = 0.05;

// determine longer term trend
// Note: could have problem if current bar is outside of all previous bars
trend[0] = 0;
for(bar= 1; bar < BarCount; bar++)
{
  if(high[bar] > SlowRes[bar-1]) trend[bar] = 1;
  else if(low[bar] < SlowSup[bar-1]) trend[bar] = -1;
  else trend[bar] = trend[bar-1];
}

LastPosition = 0; // 1 - long; -1 - short
PositionRiskStop = 0;

Buy = Sell = Short = Cover = 0;
for(bar = 5; bar < BarCount-1; bar++)
{
  	// Exit position  by protection stop
    if(LastPosition == 1)
    {
		// Sell at stop
		if(PositionRiskStop > low[bar] )   // skip if the signal price only touch (=)
the low
		{
		// We just calculate the exact price to simulate Ed's skid     
			stopPrice = PositionRiskStop;
			ff = min(open[bar], stopPrice) - low[bar];
			stopPrice = min(open[bar], stopPrice) - 0.5*ff;
	  		Sell[bar] = 1;
	  		SellPrice[bar] = stopPrice;
			TradePrice[bar] = stopPrice;
			LastPosition = 0;
		}
    }
    else if(LastPosition == -1)
    {
		// Cover at stop
		if(PositionRiskStop < high[bar])  // skip if the signal price only touch (=)
the high
		{
			stopPrice = PositionRiskStop;
			ff = high[bar] - max(open[bar], stopPrice);
			stopPrice = max(open[bar], stopPrice) + 0.5*ff;
	  		Cover[bar] = 1;
	  		CoverPrice[bar] = stopPrice;
			TradePrice[bar] = stopPrice;
			LastPosition = 0;
		}
    }

  // move the protection stop
  if(LastPosition == 1)
  {
      PositionRiskStop = FastSup[bar];
  }
  else if(LastPosition == -1)
  {
     PositionRiskStop = FastRes[bar];
  }
  else { // Enter position only when last position has been closed	  
	  if(trend[bar] == 1)
	  {
		// buy at stop	    
	    if( fastRes[bar] < high[bar+1]) 
	    {
		    ff = high[bar+1] - max(open[bar+1], fastRes[bar]);
		    stopPrice = max(open[bar+1], FastRes[bar]) + 0.5*ff;
		    f = heat/(FastRes[bar] - FastSup[bar]);
			Buy[bar+1] = 1;
			BuyPrice[bar+1] = stopPrice;
			PositionSize[bar+1] = f; //this value is passed to CBT for position sizing
			LastPosition  = 1;
			PositionRiskStop = FastSup[bar+1];
			TradePrice[bar+1] = stopPrice;
			bar ++; // skip one bar since next bar has been handled
	    }
	  }
	  else if(trend[bar] == -1)
	  {	  
	  	// short at stop
	    if( fastSup[bar] > low[bar+1]) 
	    {
			ff = min(open[bar+1], FastSup[bar]) - low[bar+1];
			stopPrice = min(open[bar+1], FastSup[bar]) - 0.5*ff;
			f = heat/(FastRes[bar] - FastSup[bar]);
	    	Short[bar+1] = 1;
			ShortPrice[bar+1] = stopPrice;
			PositionSize[bar+1] = f; //this value is passed to CBT for position sizing
			LastPosition = -1;
	    	PositionRiskStop = FastRes[bar+1];
			TradePrice[bar+1] = stopPrice;
			bar ++; // skip one bar since next bar has been handled
	    }
	  }
  }
}

// close final day for accounting purpose
bar = Barcount-1;
if(LastPosition == 1) { Sell[bar] = 1; SellPrice[bar] =
(low[bar]+close[bar])/2; }
else if(LastPosition == -1) { Cover[bar] = 1; CoverPrice[bar] =
(high[bar]+close[bar])/2; }

/*==============================================================================
	Automatic Analysis Action Options
==============================================================================*/
AAAction = Status("action");
if(AAAction == actionIndicator)
{
	Plot(FastRes, "FastRes", colorRed);
	Plot(SlowRes, "SlowRes", colorPink);
	Plot(FastSup, "FastSup", colorGreen);
	Plot(SlowSup, "SlowSup", colorBlue);
}
else if(AAAction == actionExplore)
{
	Filter = 1;	
	AddColumn( DateTime(), "Date", formatDateTime ); 
	AddColumn(O, "Open");
	AddColumn(H, "High");
	AddColumn(L, "Low");
	AddColumn(C, "Close");
	AddColumn(FastRes, "FastRes");
	AddColumn(SlowRes, "SlowRes");
	AddColumn(FastSup, "FastSup");
	AddColumn(SlowSup, "SlowSup");
	AddColumn(Trend, "Trend");
	AddColumn(IIf(Buy, Asc("B"), IIf(Sell, Asc("S"), IIf(Short, Asc("H"),
IIf(Cover, Asc("C"), 0)))) , "Signal", formatChar);
	AddColumn(TradePrice, "TradePrice");
}
else if(AAAction == actionPortfolio)
{
	bo = GetBacktesterObject();
	bo.PreProcess(); // Initialize backtester
	for( bar=0; bar < BarCount; bar++)
	{
		eq =  bo.Equity;
		for ( sig=bo.GetFirstSignal(bar); sig; sig=bo.GetNextSignal(bar) )
		{
			if (sig.isExit())
			{
            	if(bo.ExitTrade(bar,sig.symbol,sig.Price))
				{ 
					_TRACE("EXIT: " + sig.symbol + "@" + sig.Price);
				}
			}
		}

        // update stats after closing trades
     	bo.UpdateStats(bar, 1 );
       
     	for ( sig=bo.GetFirstSignal(bar); sig; sig=bo.GetNextSignal(bar)) 
     	{ 
			if (sig.isEntry()) 
			{ 
				// sig.PosSize is passed from Phase I.
				shares = round((eq*sig.PosSize)/100)*100;
				ps = shares * sig.Price;

				if(bo.EnterTrade(bar, sig.symbol, sig.IsLong, sig.Price, ps,
sig.PosScore,sig.RoundLotSize)) 
				{
					_TRACE("ENTRY: " + sig.symbol + " @" + sig.Price + " PosScore=" +
sig.PosScore + " PosSize=" + ps);
            	}
			}
		}

		bo.UpdateStats(bar,1); // MAE/MFE is updated when timeinbar is set to 1.
		bo.UpdateStats(bar,2);
   	}
	bo.PostProcess(); // Finalize backtester
}
/*==============================================================================
	End of Formula
==============================================================================*/

Comments:

Edwin Wigmore
ted3001 [at] xtra.co.nz
2006-10-08 03:31:09
Hi,
This looks very interesting, but I seem to be getting several errors whenever I try to use it including "possible missing ;" and others. I just cut and paste it from the web page. Did I do something wrong?
Cheers
avi

2006-10-08 09:39:19
very nice work!
Mark H.
mdhuang1gmailcom
2006-10-08 10:36:31
This is an updated vesion. I have removed all references to "bar+1", which had made it look like it was referencing to the future (although it was not). The the code is also a bit cleaner.
The backtest results are the same as previous version.

/*==============================================================================
Global Settings
==============================================================================*/
SetFormulaName("TT Support Resistance 1.2");
SetOption("InitialEquity", 1000000);
SetOption("NoDefaultColumns", True );
SetOption("CommissionMode", 2); //$$ per trade
SetOption("CommissionAmount", 0);
SetOption("MarginRequirement", 10);
SetOption("UsePrevBarEquityForPosSizing", True);
SetOption("UseCustomBacktestProc", True );

SetTradeDelays( 0, 0, 0, 0 );

/*==============================================================================
User-defined Functions
==============================================================================*/
function Support(p)
{
sup = LLV(low, p);
sup[0] = low[0];
for (i = 1; i < p; i++)
{
if(low[i] < sup[i-1]) sup[i] = low[i];
else sup[i] = sup[i-1];
}
return sup;
}

function Resistance(p)
{
res = HHV(high, p);
res[0] = high[0];
for (i = 1; i < p; i++)
{
if(high[i] > res[i-1]) res[i] = high[i];
else res[i] = res[i-1];
}
return res;
}

function OptimizeNot(a1, a2, a3, a4, a5)
{
return a2;
}

/*==============================================================================
Entry and Exit Rules
==============================================================================*/
fast = Optimize("Fast", 20, 5, 105, 5);
slow = Optimize("Slow", 140, 20, 420, 20);
FastRes = Resistance(fast);
FastSup = Support(fast);
SlowRes = Resistance(slow);
SlowSup = Support(slow);
heat = 0.05;

// determine longer term trend
// Note: could have problem if current bar is outside of all previous bars
// the trend can also be calculated within main loop, but put here for clarity
trend[0] = 0;
for(bar= 1; bar < BarCount; bar++) // bar must start from 1, otherwise trend calculation is wrong
{
if(high[bar] > SlowRes[bar-1]) trend[bar] = 1;
else if(low[bar] < SlowSup[bar-1]) trend[bar] = -1;
else trend[bar] = trend[bar-1];
}

LastPosition = 0; // 1 - long; -1 - short
PositionRiskStop = 0;

Buy = Sell = Short = Cover = 0; // this has to be set otherwise they are undefined!!! weird
// main loop
for(bar = 5; bar < BarCount-1; bar++) // give some bars for the system to stablize
{
// Exit position by protection stop
if(LastPosition == 1)
{
// Sell at stop
if(PositionRiskStop > low[bar] ) // skip if the signal price only touch (=) the low
{
// We just calculate the exact price to simulate Ed's skid
stopPrice = PositionRiskStop;
ff = min(open[bar], stopPrice) - low[bar];
stopPrice = min(open[bar], stopPrice) - 0.5*ff;
Sell[bar] = 1;
SellPrice[bar] = stopPrice;
TradePrice[bar] = stopPrice;
LastPosition = 0;
}
else // move the protection stop
{
PositionRiskStop = FastSup[bar];
}
}
else if(LastPosition == -1)
{
// Cover at stop
if(PositionRiskStop < high[bar]) // skip if the signal price only touch (=) the high
{
stopPrice = PositionRiskStop;
ff = high[bar] - max(open[bar], stopPrice);
stopPrice = max(open[bar], stopPrice) + 0.5*ff;
Cover[bar] = 1;
CoverPrice[bar] = stopPrice;
TradePrice[bar] = stopPrice;
LastPosition = 0;
}
else // move the protection stop
{
PositionRiskStop = FastRes[bar];
}
}
// Enter position only when last position has been closed
else {
if(trend[bar-1] == 1)
{
// buy at stop
if( fastRes[bar-1] < high[bar])
{
ff = high[bar] - max(open[bar], FastRes[bar-1]);
stopPrice = max(open[bar], FastRes[bar-1]) + 0.5*ff;
f = heat/(FastRes[bar-1] - FastSup[bar-1]);
Buy[bar] = 1;
BuyPrice[bar] = stopPrice;
PositionSize[bar] = f; //this value is passed to CBT for position sizing
LastPosition = 1;
PositionRiskStop = FastSup[bar];
TradePrice[bar] = stopPrice;
}
}
else if(trend[bar-1] == -1)
{
// short at stop
if( FastSup[bar-1] > low[bar])
{
ff = min(open[bar], FastSup[bar-1]) - low[bar];
stopPrice = min(open[bar], FastSup[bar-1]) - 0.5*ff;
f = heat/(FastRes[bar-1] - FastSup[bar-1]);
Short[bar] = 1;
ShortPrice[bar] = stopPrice;
PositionSize[bar] = f; //this value is passed to CBT for position sizing
LastPosition = -1;
PositionRiskStop = FastRes[bar];
TradePrice[bar] = stopPrice;
}
}
}
}

// close final day for accounting purpose
bar = Barcount-1;
if(LastPosition == 1) { Sell[bar] = 1; SellPrice[bar] = (low[bar]+close[bar])/2; }
else if(LastPosition == -1) { Cover[bar] = 1; CoverPrice[bar] = (high[bar]+close[bar])/2; }

/*==============================================================================
Automatic Analysis Action Options
==============================================================================*/
AAAction = Status("action");
if(AAAction == actionIndicator)
{
Plot(FastRes, "FastRes", colorRed);
Plot(SlowRes, "SlowRes", colorPink);
Plot(FastSup, "FastSup", colorGreen);
Plot(SlowSup, "SlowSup", colorBlue);
}
else if(AAAction == actionExplore)
{
Filter = 1;
AddColumn( DateTime(), "Date", formatDateTime );
AddColumn(O, "Open");
AddColumn(H, "High");
AddColumn(L, "Low");
AddColumn(C, "Close");
AddColumn(FastRes, "FastRes");
AddColumn(SlowRes, "SlowRes");
AddColumn(FastSup, "FastSup");
AddColumn(SlowSup, "SlowSup");
AddColumn(Trend, "Trend");
AddColumn(IIf(Buy, Asc("B"), IIf(Sell, Asc("S"), IIf(Short, Asc("H"), IIf(Cover, Asc("C"), 0)))) , "Signal", formatChar);
AddColumn(TradePrice, "TradePrice");
}
else if(AAAction == actionPortfolio)
{
bo = GetBacktesterObject();
bo.PreProcess(); // Initialize backtester
for( bar=0; bar < BarCount; bar++)
{
eq = bo.Equity;
for ( sig=bo.GetFirstSignal(bar); sig; sig=bo.GetNextSignal(bar) )
{
if (sig.isExit())
{
if(bo.ExitTrade(bar,sig.symbol,sig.Price))
{
_TRACE("EXIT: " + sig.symbol + "@" + sig.Price);
}
}
}

// update stats after closing trades
bo.UpdateStats(bar, 1 );

for ( sig=bo.GetFirstSignal(bar); sig; sig=bo.GetNextSignal(bar))
{
if (sig.isEntry())
{
// sig.PosSize is passed from Phase I.
shares = round((eq*sig.PosSize)/100)*100;
ps = shares * sig.Price;

if(bo.EnterTrade(bar, sig.symbol, sig.IsLong, sig.Price, ps, sig.PosScore,sig.RoundLotSize))
{
_TRACE("ENTRY: " + sig.symbol + " @" + sig.Price + " PosScore=" + sig.PosScore + " PosSize=" + ps);
}
}
}

bo.UpdateStats(bar,1); // MAE/MFE is updated when timeinbar is set to 1.
bo.UpdateStats(bar,2);
}
bo.PostProcess(); // Finalize backtester
}
/*==============================================================================
End of Formula
==============================================================================*/
Mark H.
mdhuang1gmailcom
2006-10-08 11:32:36
Add the following line in Support() and Resistance() function to avoid display error if you current symbol doesn't have enough bars:

p = min(p,BarCount); // avoid display error
(before for (i = 1; i < p; i++))
Mark H.
mdhuang1gmailcom
2006-10-08 11:36:18
Edwin: Make sure the lines are not wrapped when you paste the code to AmiBroker.
Jack

2006-10-09 04:52:11
There is a syntax error in this line:"AddColumn(IIf(Buy, Asc("B"), IIf(Sell, Asc("S"), IIf(Short, Asc("H"), IIf(Cover, Asc("C"), 0)))) , "Signal", formatChar);"
Wouldn't you like to plot the price bars on top of the support and resistance lines?
Mark H.
mdhuang1gmailcom
2006-10-09 09:20:22
Jack: make sure you use the latest version of Amibroker and no line wrap. You can apply the formula as an indicator to an existing price chart, so you don't need to plot the price here.
Jack

2006-10-10 04:27:12
Thanks Mark. My AB version was the problem. I can see that sometimes the long and short time support or resistance lines overlap themselfs. Is it a problem or just coincidence?
Mark H.

2006-10-10 11:43:25
Jack: fast and slow values overlapping is normal when the trends are establishing.
Jack

2006-10-11 03:24:45
Thanks for your help and great effort Mark. I am admire people like you who share their ideas with others.
martin
artofjoy11 [at] yahoo.com.sg
2006-10-15 11:46:32
hi, this is really great. Save time lot of time to plot SAR.
But when i toggle it fr daily to wkly chart, there r several error as follow, kindly advise

Price:
For (i=1;i<p;i++)
{
if(High[i]>res[i-1]res[i] res[i[=High[i];
else res[i]

Error 10
Subscript out of range.
You must not access arry elements outside 0..(BarCount-1) range.


rob
chapman49682 [at] yahoo.com
2007-03-20 09:06:42
I get the same error as Martin and in the same place. Can anyone help? thanks.
franco
franco_tsang [at] yahoo.com.sg
2007-03-22 00:19:01
Good work Mark!! it is nice & neat!
Gary
gary [at] garynielson.com
2007-03-23 13:06:48
I just downloaded your AFL file -- the updated version where you have removed all references to "bar+1" -- and I am getting an Error 10 when I run a backtest. "Subscript out of range. You must not access array elements outside 0 ... (BarCount-1) range. I am getting it twice on a symbol and then an Error 29: "Variable 'tradeprice' used without having been initialized. I am running 4.90. Any help appreciated.
Mark H.

2007-03-24 20:51:43
Add this line to the Support() and Resistance() functions just before the loop to avoid the error.
p = min(p,BarCount); //avoid out of range error
for(i=1;i<p;i++)...
Mark H.

2007-03-25 01:58:45
To fix: Error 29: "Variable 'tradeprice' used without having been initialized.

Just add
TradePrice = 0;
before the main loop.
Ilhan Ketrez
ilhanketrez [at] gmail.com
2010-01-24 12:56:21
Mark, thank you for publishing your clear solution.
Please find below my shorter version for everyone\\\'s benefit.


SetOption(\\\"InitialEquity\\\", 1000000);
SetOption(\\\"MarginRequirement\\\", 10);
SetOption(\\\"UsePrevBarEquityForPosSizing\\\", True);
SetOption(\\\"UseCustomBacktestProc\\\", True );

fast = Optimize(\\\"Fast\\\", 20, 5, 105, 5);
slow = Optimize(\\\"Slow\\\", 140, 20, 420, 20);
FastRes = HHV(H,fast); FastSup = LLV(L,fast);
SlowRes = HHV(H,slow); SlowSup = LLV(L,slow);

uptrend = Flip(H > Ref(SlowRes,-1),Ref(SlowSup,-1) > L);
trend = IIf(uptrend,1,-1);
for(bar = 1; bar < 10 ;bar++){trend[bar] = 0;}//skipping a few bars at the beginning

Buy = Ref(trend,-1) == 1 AND H > Ref(FastRes,-1);
Sell = Cross(Ref(FastSup,-1),L);
Short = Ref(trend,-1) == -1 AND Ref(FastSup,-1) > L;
Cover = Cross(H,Ref(FastRes,-1));

heat = 0.05;
PositionSize = heat / Ref((FastRes - FastSup),-1);
BuyPrice = (H + Max(O,Ref(FastRes,-1)))/2;
SellPrice = (L + Min(O,Ref(FastSup,-1)))/2;
ShortPrice = (L + Min(O,Ref(FastSup,-1)))/2;
CoverPrice = (H + Max(O,Ref(FastRes,-1)))/2;

// final day detail:
bar = BarCount-1;
if(trend[bar] == 1) { Sell[bar] = 1; SellPrice[bar] = (Low[bar]+Close[bar])/2; }
else if(trend[bar] == -1) { Cover[bar] = 1; CoverPrice[bar] = (High[bar]+Close[bar])/2; }

if( Status(\\\"action\\\") == actionPortfolio )
{
bo = GetBacktesterObject();
bo.PreProcess();
for( bar=0; bar < BarCount; bar++)
{
eq = bo.Equity;
for ( sig=bo.GetFirstSignal(bar); sig; sig=bo.GetNextSignal(bar))
{
if (sig.isExit())
{
bo.ExitTrade(bar,sig.symbol,sig.Price);//close position
}
if (sig.isEntry())
{
shares = round((eq*sig.PosSize)/100)*100;
ps = shares * sig.Price;
bo.EnterTrade(bar, sig.symbol, sig.IsLong, sig.Price, ps, sig.PosScore,sig.RoundLotSize); //open position
}
}
bo.UpdateStats(bar,1);
bo.UpdateStats(bar,2);
}
bo.PostProcess();
}
Ilhan Ketrez
ilhanketrez [at] gmail.com
2010-01-24 13:01:49
\\\"\\\\\\\\\\\\\\\" characters appear above do not exist in the real code. They are most probably gifts from comment addition procedure of this page. Please remove them while executing the code.


About | Privacy | Terms of Use | Contact information
Copyright © 2001 AMIBROKER.COM