Buy Low Sell High - r

I've a data like this:
library("xts")
close <- c(0, -0.5, -0.75, -1, -0.75, -1.5, -2, -2.5, -3, -3.5, -3, -2.5, -2, -1, 0, 1, 1.5, 2, 2.5, 3, 2.5, 2, 0)
data <- xts(close, Sys.Date()-23:1)
colnames(data) <- "close"
I'd like to generate another column which will give me a trade signal based on the logic below:
Buy when the close is # or below -1, -2 and -3.
Sell all the 3 when close is # or above 0.
Short Sell when the close is # or above 1, 2 and 3
Buy all the 3 when close is # or below 0.
For this i've tried
data$trade <- 0
data$trade[data$close <= -1] <- 1
data$trade[data$close <= -2] <- 2
data$trade[data$close <= -3] <- 3
data$trade[data$close >= 1] <- -1
data$trade[data$close >= 2] <- -2
data$trade[data$close >= 3] <- -3
data trade column is giving me (0,0,0,1,0,1,2,2,,3,3,3,2,2,1,0,-1,-1,-2,-2,-3,-2,-2,0)
but i want that it should give me ((0,0,0,1,1,1,2,2,3,3,3,3,3,3,0,-1,-1,-2,-2,-3,-3,-3,0)
i want that when i buy # say -1 or -2 the trade signal should be on till we reach 0 or above and similarly when we short sell it # say -1, -2 etc the trade signal should be on till we reach 0 or below. Kindly help i've tried lots of combinations, but not getting the required result.

If I've understood correctly, this is hard to do efficiently because the choice depends upon the past. It's not elegant but this code gives the output you require,
library("xts")
close <- c(0, -0.5, -0.75, -1, -0.75, -1.5, -2, -2.5, -3, -3.5, -3, -2.5, -2, -1, 0, 1, 1.5, 2, 2.5, 3, 2.5, 2, 0)
data <- xts(close, Sys.Date()-23:1)
colnames(data) <- "close"
sig.buy <- c(F,F,F)
sig.short <- c(F,F,F)
for(i in 1:length(data))
{
if(data$close[i] <= -1) sig.buy[1] <- T
if(data$close[i] <= -2) sig.buy[2] <- T
if(data$close[i] <= -3) sig.buy[3] <- T
if(sig.buy[1] && data$close[i] >= 0) sig.buy[1] <- F
if(sig.buy[2] && data$close[i] >= 0) sig.buy[2] <- F
if(sig.buy[3] && data$close[i] >= 0) sig.buy[3] <- F
if(data$close[i] >= 1) sig.short[1] <- T
if(data$close[i] >= 2) sig.short[2] <- T
if(data$close[i] >= 3) sig.short[3] <- T
if(sig.short[1] && data$close[i] <= 0) sig.short[1] <- F
if(sig.short[2] && data$close[i] <= 0) sig.short[2] <- F
if(sig.short[3] && data$close[i] <= 0) sig.short[3] <- F
data$trade[i] <- sum(sig.buy) - sum(sig.short)
}

Related

How to convert binary output to values in relation to a column in r

The sample data is as follows
ID <- c(1, 2, 3)
O1D1 <- c(0, 0, 0)
O1D2 <- c(0, 0, 0)
O1D3 <- c(0, 10, 0)
O2D1 <- c(0, 0, 0)
O2D2 <- c(0, 0, 0)
O2D3 <- c(18, 0, 17)
O3D1 <- c(0, 9, 0)
O3D2 <- c(20, 1, 22)
O3D3 <- c(0, 0, 0)
x <- data.frame(ID, O1D1, O1D2, O1D3, O2D1, O2D2, O2D3, O3D1, O3D2, O3D3)
I created a new column with some conditional logic.
Say, the new column is n
x$n <- (x$O1D3 > 0 & x$O2D3 == 0)
> x$n
[1] FALSE TRUE FALSE
What I am looking to get instead is a column with values such as
> x$n
[1] 0 10 0
Or, in other words, the values of O1D3 should replace TRUE values in the n column and the FALSE values can be replaced with 0.
Thanks for your time and help.

judge the values crossing zero

I would like to determine whether or not the ranges of min and max values cross zero (0 = crossing zero, 1 = not crossing zero).
min <- c(0, -1, -1, 1, 1)
max <- c(1, 1, -0.1, 3, 1.5)
answer <- c(0, 0, 1, 1, 1)
data <- cbind(min,max, answer)
You can use the between function from dplyr:
library(dplyr)
min <- c(0, -1, -1, 1, 1)
max <- c(1, 1, -0.1, 3, 1.5)
df1 = data.frame(min,max) %>%
rowwise() %>%
mutate(answer = as.numeric(!between(0,min,max)))
Or using base R:
df1 = data.frame(min,max)
df1$answer = apply(df1, 1, function(x) as.numeric(!(x[1]<= 0 & x[2] >=0)))
Base R vectorised answer -
transform(data, answer = as.integer(!(min <= 0 & max > 0)))
# min max answer
#1 0 1.0 0
#2 -1 1.0 0
#3 -1 -0.1 1
#4 1 3.0 1
#5 1 1.5 1
If you prefer dplyr the same can be written as -
library(dplyr)
data %>% mutate(answer = as.integer(!(min <= 0 & max > 0)))
data
min <- c(0, -1, -1, 1, 1)
max <- c(1, 1, -0.1, 3, 1.5)
data <- data.frame(min,max)
You can simply multiply them, as to cross you either need a negative product or one being zero.
answer <- ifelse(min * max <= 0, 0, 1)
or
answer <- as.integer(min * max > 0)
# [1] 0 0 1 1 1
If your 0 and 1 are not a requirement, even shorter to get a TRUE or FALSE
answer <- min * max <= 0
# [1] TRUE TRUE FALSE FALSE FALSE

Piecewise Function Help in R

For a class I must create a piecewise function defined in the following way:
2x-2 , x < -1
0 , -1 <= X <= 1
x^(2)-1, x > 1
I have tried an ifelse sequence but I cant seem to make it work. I've also tried an if, elseif, else sequence, but that only seems to use the first function to calculate answers.
The end goal is to have this:
pwfun(c(-2, 0.5, 3))
2 0 8
A piece-wise function like below?
pwfun <- function(x) ifelse(x < -1, 2 * x - 2, ifelse(x <= 1, 0, x**2 - 1))
such that
> pwfun(c(-2, 0.5, 3))
[1] -6 0 8
pwfun <- function(x) ifelse(x < -1, (x * x) -2, ifelse(x <= 1, 0, x**2 - 1))
> pwfun(c(-2, 0.5, 3))
[1] -2 0 8
The above edit to ThomasIsCoding's answer gives you what you want, but I would use this approach because it communicates it's intent better:
library(dplyr)
df <- data.frame(x = c(-2, 0.5, 3))
pwfunc <- function(data){
data %>%
mutate(y =
case_when(x < -1 ~ -2,
x > 0 & x <= 1 ~ 0,
TRUE ~ x**2 - 1)) ## TRUE in a case_when basically
## means "everything that isnt caught by my specified conditions
## becomes..." so it works like the "else" clause
}
Then just call the function on your data:
df <- data.frame(x = c(-2, 0.5, 3))
pwfunc(data)
And get:

Combined subsetting in R?

I trying to subset 3 ys for when xs are -1, 0, and 1 in my code below. But I was hoping to do this all at once using y[c(x == -1, x == 0, x == 1)] which apparently does not work (see below).
Any better way to do this subsetting all at once?
x = seq(-1, 1, l = 1e4)
y = dcauchy(x, 0, sqrt(2)/2)
y[c(x == -1, x == 0, x == 1)] ## This subsetting format doesn't work
We can do this.
y[x == -1| x == 0| x == 1]
Or this
y[x %in% c(-1, 0, 1)]

how to find the longest same number in R

for example I have data like this
x<-c(0,0,1,1,1,1,0,0,1,1,0,1,1,1)
I want find the longest sequence of "1" by considering the start and end position, in this case should be (3,6)
How to do this in R
thanks all
Here's an approach that uses seqle from the "cgwtools" package:
library(cgwtools)
y <- seqle(which(x == 1))
z <- which.max(y$lengths)
y$values[z] + (sequence(y$lengths[z]) - 1)
# [1] 3 4 5 6
You can use range if you just wanted the "3" and "6".
seqle "extends rle to find and encode linear sequences".
Here's the answer as a function:
longSeq <- function(invec, range = TRUE) {
require(cgwtools)
y <- seqle(which(invec == 1))
z <- which.max(y$lengths)
out <- y$values[z] + (sequence(y$lengths[z]) - 1)
if (isTRUE(range)) range(out) else out
}
Usage would be:
x <- c(0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1)
longSeq(x)
# [1] 3 6
longSeq(x, range = FALSE)
# [1] 3 4 5 6
And, with KFB's example input:
y <- c(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1)
longSeq(y)
# [1] 9 11
You can do this easily with base R too using rle and inverse.rle combination
Creating the funciton
longSeq2 <- function(x, range = TRUE){
temp <- rle(x == 1)
temp$values <- temp$lengths == max(temp$lengths[temp$values == TRUE])
temp <- which(inverse.rle(temp))
if (isTRUE(range)) range(temp) else temp
}
Testing
x <- c(0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,0,1,1,1)
longSeq2(x)
## [1] 3 6
longSeq2(x, range = FALSE)
## [1] 3 4 5 6
y <- c(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1)
longSeq2(y)
## [1] 9 11
longSeq2(y, range = FALSE)
## [1] 9 10 11

Resources