Implementing Bill Williams Fractals as Quantstrat Indicators
Summary
This discussion shows how to implement upward and downward Bill Williams fractal indicators for use in R's quantstrat framework. The example identifies a local high or low by comparing a candidate bar with neighboring bars, then marks the detected pattern in an indicator series. A follow-up describes adjustments needed in one environment, including returning the indicator values and accessing data columns appropriately.
The examples also show how the indicators can be attached to a strategy and used to form entry and exit signals, with a simple SPY illustration. The author explicitly presents that trading logic as a demonstration rather than a strategy for actual use. The initial implementation may contain errors, and the discussion advises checking its logic; the material supplies no performance evaluation or evidence that fractal signals are profitable. It is best treated as a coding example whose detection timing and implementation details should be independently validated before backtesting.
Key ideas
- The example defines separate indicators for upward and downward fractal patterns using local highs and lows.
- A fractal condition compares the candidate bar with several neighboring bars.
- Quantstrat can attach custom indicator functions and use their outputs to generate signals.
- The sample entry and exit rules illustrate framework usage and are not presented as a tradable strategy.
- The indicator logic and timing should be validated because the original code may need correction.
Tags
Full text
# Fractals indicator (Bill Williams) R Quantstrat
# Fractals indicator (Bill Williams) R Quantstrat
Hi has anyone seen or know how to create an indicator for fractals in quantstrat?
fractals explained http://forex-indicators.net/bill-williams/fractals
example code (only interested in type 1 fractal) http://forexsb.com/forum/topic/68/fractals/
## Answer by Kumar (score 2, accepted)
https://quant.stackexchange.com/a/18645
Most technical indicators must be available in the TTR package. However, if they are not then you can write a custom indicator for use in quantstrat as follows.
```
fractalindicator.up <- function(x) {
High <- Hi(x); Bars <- nrow(x)
afFrUp <- rep(NA, Bars)
for(iBar in seq(8,Bars-2))
{
if(High[iBar-1]<High[iBar-2] && High[iBar]<High[iBar-2])
{
#Fractal type 1
if( High[iBar-4]<High[iBar-2] &&
High[iBar-3]<High[iBar-2] )
afFrUp[iBar+1]=High[iBar-2];
}
}
names(afFrDn) <- "F.Up"
}
fractalindicator.dn <- function(x) {
Low <- Lo(x); Bars <- nrow(x)
afFrDn <- rep(NA, Bars)
for(iBar in seq(8,Bars-2))
{
if(Low[iBar-1]>Low[iBar-2] && Low[iBar]>Low[iBar-2])
{
#Fractal type 1
if( Low[iBar-4]>Low[iBar-2] &&
Low[iBar-3]>Low[iBar-2] )
afFrDn[iBar+1]=Low[iBar-2];
}
}
names(afFrDn) <- "F.Down"
}
#Add indicators
add.indicator(strategy = "fractal", name = "fractalindicator.up",
arguments = list(x = quote(mktdata)), label="fractalup")
#Add indicators
add.indicator(strategy = "fractal", name = "fractalindicator.dn",
arguments = list(x = quote(mktdata)), label="fractaldn")
```
I have defined two here, fractalindicator.up and fractalindicator.dn. You can work with these just like you do in a regular quantstrat strategy. I may be wrong in constructing the indicator so check the logic. It is also possible to combine the two functions into one with an additional parameter.
Also, quantstrat related questions are best asked on r-sig-finance mailing list. The authors of quantstrat and many more R enthusiasts are very active on that mailing list.
## Answer by GeV 126 (score 0)
https://quant.stackexchange.com/a/18672
so i had to do a couple changes to get it fully working for me, but Rohit you pretty much got it close. Again this is what worked in my env
```
fractalindicator.up <- function(x) {
x$FUp <- 0
High <- Hi(x); Bars <- nrow(x)
for(iBar in seq(8,Bars-2))
{
if(High[[iBar-1]]<High[[iBar-2]] && High[[iBar]]<High[[iBar-2]])
{
#Fractal type 1
if( High[[iBar-4]]<High[[iBar-2]] &&
High[[iBar-3]]<High[[iBar-2]] )
#afFrUp[iBar+1]=High[iBar-2];
x$FUp[iBar]= 1;
}
}
return(x$FUp)
}
fractalindicator.dn <- function(x) {
x$FDown <- 0
Low <- Lo(x); Bars <- nrow(x)
for(iBar in seq(8,Bars-2))
{
if(Low[[iBar-1]]>Low[[iBar-2]] && Low[[iBar]]>Low[[iBar-2]])
{
#Fractal type 1
if( Low[[iBar-4]]>Low[[iBar-2]] &&
Low[[iBar-3]]>Low[[iBar-2]] )
#afFrDn[iBar+1]=Low[iBar-2];
x$FDown[iBar]=1;
}
}
return(x$FDown)
}
```
I needed to return an xts object and include [[]] to access values in the dataframe
Pasted below is the full code (without analytics), I used the boilerplate code from Ilya Kipnis so full credit goes to him (please source the code from the link and not copy and paste from this) https://github.com/IlyaKipnis/DSTrading/blob/master/demo/TVI2.R
The strategy just buys as soon as it gets and up fractal and exits on a down fractal, obviously this is not a strategy anyone would trade, This is just an example of using fractals.
```
require(quantstrat)
require(IKTrading)
require(devtools)
require(DSTrading)
require(PerformanceAnalytics)
options("getSymbols.warning4.0"=FALSE)
rm(list=ls(.blotter), envir=.blotter)
currency('USD')
Sys.setenv(TZ="UTC")
symbols <- "SPY"
suppressMessages(getSymbols(symbols, from="1998-01-01", to="2015-05-15"))
stock(symbols, currency="USD", multiplier=1)
initDate="1990-01-01"
tradeSize <- 10000
initEq <- tradeSize*length(symbols)
account.st <- 0
strategy.st <- portfolio.st <- account.st <- "fractal"
rm.strat(portfolio.st)
rm.strat(strategy.st)
initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD')
initAcct(account.st, portfolios=portfolio.st, initDate=initDate, currency='USD',initEq=initEq)
initOrders(portfolio.st, initDate=initDate)
strategy(strategy.st, store=TRUE)
#new
fractalindicator.up <- function(x) {
x$FUp <- 0
High <- Hi(x); Bars <- nrow(x)
for(iBar in seq(8,Bars-2))
{
if(High[[iBar-1]]<High[[iBar-2]] && High[[iBar]]<High[[iBar-2]])
{
#Fractal type 1
if( High[[iBar-4]]<High[[iBar-2]] &&
High[[iBar-3]]<High[[iBar-2]] )
#afFrUp[iBar+1]=High[iBar-2];
x$FUp[iBar]= 1;
}
}
return(x$FUp)
}
fractalindicator.dn <- function(x) {
x$FDown <- 0
Low <- Lo(x); Bars <- nrow(x)
for(iBar in seq(8,Bars-2))
{
if(Low[[iBar-1]]>Low[[iBar-2]] && Low[[iBar]]>Low[[iBar-2]])
{
#Fractal type 1
if( Low[[iBar-4]]>Low[[iBar-2]] &&
Low[[iBar-3]]>Low[[iBar-2]] )
#afFrDn[iBar+1]=Low[iBar-2];
x$FDown[iBar]=1;
}
}
return(x$FDown)
}
#Add indicators
add.indicator(strategy = "fractal", name = "fractalindicator.up",
arguments = list(x = quote(mktdata)), label="fractalup")
#Add indicators
add.indicator(strategy = "fractal", name = "fractalindicator.dn",
arguments = list(x = quote(mktdata)), label="fractaldn")
applyIndicators(strategy=strategy.st, mktdata)
#
# mktdata$FDown.FDownCompare <- 1
# mktdata$FUp.FUpCompare <- 1
add.signal(strategy.st, name = "sigComparison", arguments = list(columns=c("fractalup", "fractaldn"),
relationship="gt"), label="upFractal")
add.signal(strategy.st, name = "sigComparison", arguments = list(columns=c("fractaldn", "fractalup"),
relationship="gt"), label="downFractal")
applySignals(strategy=strategy.st,mktdata)
#enter rule
add.rule(strategy.st, name = "ruleSignal", arguments = list(sigcol="upFractal",
sigval=TRUE,
ordertype="market",
orderside=NULL,
replace=FALSE,
prefer="close",
orderqty=1),
type="enter",path.dep=TRUE,label="ruleUp")
#exit rule
add.rule(strategy.st, name = "ruleSignal", arguments = list(sigcol="downFractal",
sigval=TRUE,
orderqty="all",
orderqty=-1,
ordertype="market",
orderside=NULL,
replace=FALSE,
prefer="open"),
type="enter",path.dep=TRUE,label="ruleDown")
#apply strategy
t1 <- Sys.time()
out <- applyStrategy(strategy=strategy.st,portfolios=portfolio.st,debug=TRUE )
t2 <- Sys.time()
print(t2-t1)
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.