Swing high and low from Pine to R

728 Views Asked by At

I am trying to translate a Swing High and Low function from Pine to R, and I cannot really get the logic behind the Pine code.

Basically, this function loops over a time series database of high and low prices, and yields:

A swing high: as the position of the highest price after the price moves below the prior swing high OR as the position of a new price that reaches a new high in the given prior time period.

Then moves to find the

Swing low: as the lowest value after the price moves above the prior swing low OR as the position of a new price that reaches a new low in the given prior time period.

Is any one familiar of a similar function in R?

Here is the function in Pine:

//@version=3
study("Swings", overlay=true)


barsback = input(7, title='Bars back to check for a swing')

swing_detection(index)=>
swing_high = false
swing_low = false
start = (index*2) - 1 // -1 so we have an even number of
swing_point_high = high[index]
swing_point_low = low[index]

//Swing Highs
for i = 0 to start
    swing_high := true
    if i < index 
        if high[i] > swing_point_high 
            swing_high := false
            break
    // Have to do checks before pivot and after separately because we can get
    // two highs of the same value in a row. Notice the > and >= difference
    if i > index
        if high[i] >= swing_point_high 
            swing_high := false
            break
    
//Swing lows
for i = 0 to start
    swing_low := true
    if i < index
        if low[i] < swing_point_low 
            swing_low := false
            break  
    // Have to do checks before pivot and after seperately because we can get
    // two lows of the same value in a row. Notice the > and >= difference
    if i > index
        if low[i] <= swing_point_low 
            swing_low := false
            break 
    
[swing_high, swing_low]

// Check for a swing
[swing_high, swing_low] = swing_detection(barsback)

// Plotting
plotshape(swing_high, style=shape.arrowdown, location=location.abovebar, color=red, text='SH', offset=-barsback)
plotshape(swing_low, style=shape.arrowup, location=location.belowbar, color=green, text='SL', offset=-barsback)

Here is a sample data:

library(quantmod)
DT <- getSymbols('rdwr', auto.assign=FALSE)
DT=data.frame(DT$RDWR.Low, DT$RDWR.High)
colnames(DT)=c("Low","High")
2

There are 2 best solutions below

4
On

I created a function that works with chartSeries from the quantmod package. You can adjust the timeperiod the lows are looking at in case you want to use hourly or minute data. The function is not really optimised or checks on wrong inputs but it works.

library(quantmod)

ADM <- getSymbols("ADM", 
                  from = "2018-01-01", 
                  to = "2018-07-01", 
                  auto.assign = FALSE)

# create function for calculating the swings defaulting to checking lows for 7 time periods. 
add_swing_high_low <- function(x, n = 7){
  
  # find rolling low
  x_low <- rollapply(Lo(x), n, min)
  y_low <- ifelse(x_low == Lo(x), 1, 0)
  
  # calculate lows while checking that the next 2 higher lows are indeed higher
  z_low <- ifelse(x_low < lag(Lo(x),-1) &
                    x_low < lag(Lo(x),-2) &
                    lag(Lo(x),-1) < lag(Lo(x),-2) &
                    y_low == 1,
                  1,
                  0)
  
  swing_low <- ifelse(z_low == 1, Lo(x), NA)
  
  # find rolling high
  x_high <- rollapply(Hi(x), n, max)
  y_high <- ifelse(x_high == Hi(x), 1, 0)
  
  z_high <- ifelse(x_high > lag(Hi(x),-1) &
                     x_high > lag(Hi(x),-2) &
                     lag(Hi(x),-1) > lag(Hi(x),-2) &
                     y_high == 1,
                   1,
                   0)
  
  swing_high <- ifelse(z_high == 1, Hi(ADM), NA)
  
  # set colours
  swings <- ifelse(!is.na(swing_low), swing_low, ifelse(!is.na(swing_high), swing_high, NA))
  swing_cols <- ifelse(swings == quantmod::Lo(ADM), "green", NA)
  swing_cols <- ifelse(swings == quantmod::Hi(ADM), "red", swing_cols)

  # set pch values to triangle and inverted triangle. 
  swing_pch <- ifelse(swing_cols == "green", 24, 
                      ifelse(swing_cols == "red", 25, NA))
  
  # add points to chart
  addPoints(1:nrow(swings), swings, col = swing_cols, pch = swing_pch, cex = 0.75, on = 1)
  
}

chartSeries(ADM) 
add_swing_high_low(ADM, n = 7)

enter image description here

0
On

I tried to replicate the same logic as the Swings High and Low function in Pine (as described here), And I came out with this below function. I think it could be clean up a bit, but it seems to replicate the results I obtained with the Pine function.

SwingsHL <-function (Low, High, barsback){

#Create container for results
swing_high = c()
swing_low = c()

#Loops through all candles, leaving room for the search window at the start and end of the series
for (Index in (barsback+1): (length(Low)-barsback)){

# Select high and low values at position Index
HighVal = High[Index]
LowVal = Low[Index]

#Define the size of the window to check for swings
LeftWindow= c((Index-barsback):(Index-1))
RightWindow= c((Index+1):(Index+barsback))

#find extreme values to left and right
MaxHighValToLeft=max(High[LeftWindow])[1]
MaxHighValToRight=max(High[RightWindow])[1]

MinLowValToLeft=min(Low[LeftWindow])[1]
MinLowValToRight=min(Low[RightWindow])[1]

#check if value at position index is larger than values to left or right
###----Swing Highs
if(HighVal>MaxHighValToLeft & HighVal>=MaxHighValToRight){swing_high[Index] = TRUE; } else{swing_high[Index] = FALSE; }


###----Swing Lows
if(LowVal<MinLowValToLeft & LowVal<=MinLowValToRight){swing_low[Index] = TRUE; } else {swing_low[Index] = FALSE; }

}

Results=data.frame(swing_high,swing_low)
Results[(Index+1):(Index+barsback),]=NA
colnames(Results)=c("SHigh", "SLows")
return (Results)
}