Skip to content
Merged
  •  
  •  
  •  
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,7 @@ export(kicking_baby_length)
export(ladder_bottom)
export(long_legged_doji)
export(long_line)
export(lookback)
export(marubozu)
export(mat_hold)
export(matching_low)
Expand Down
19 changes: 19 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# version 0.9-3

## improvements

* A new function for pre-calculating the lookback-period has been implemented. It can be used as follows:

```R
talib::lookback(
FUN = talib::SMA,
n = 10,
x = talib::BTC
)
```

The function returns the minimum required lookback for calculating the indicator.
Its use-case is customized control-flows for downstream wrappers and/or packages that declares dependency on {talib}.

## bug-fixes

# version 0.9-2

## improvements
Expand Down
126 changes: 126 additions & 0 deletions R/lookback.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#' @export
#' @family Utility
#'
#' Calculate lookback period
#'
#' @description
#' The function calculates the lookback period for a given
#' indicator.
#' Its primarily meant as a helper function for downstream packages
#' that wants to use a customized control-flow.
#'
#' @examples
#' ## calculate the lookback
#' ## for the bollinger bands
#' talib::lookback(
#' talib::bollinger_bands,
#' n = 20,
#' x = talib::BTC
#' )
#'
#' @param FUN A [call] or [function].
#' @param ... Additional parameters passed into the indicator function. See examples for more details.
#'
#' @concept finance
#' @concept technical analysis
#' @concept trading
#' @concept algorithmic trading
#'
#'
#' @author Serkan Korkmaz
#'
#' @returns
#' The minimum lookback required to calculate the indicator.
#' If the indicator specification and input data are invalid the function returns [NA], otherwise it returns an [integer] of [length] 1.
lookback <- function(
FUN,
...
) {
## store {talib} as a namespace
## so the function can be found
## (*_lookback is not exported)
ns <- getNamespace(
"talib"
)

## extract the function call
## as-is
FUN <- substitute(
FUN
)

## important distinction with substitute:
## pkg::foo() -> call
## foo -> function
if (is.call(FUN)) {
FUN <- FUN[[length(FUN)]]
}

## all exported indicators has
## a _lookback post-fix which handles
## the lookback calculation
FUN <- paste0(
as.character(FUN),
"_lookback"
)

if (!exists(FUN, envir = ns, mode = "function", inherits = FALSE)) {
## strip FUN to get
## the basename of the passed
## function
FUN <- gsub(
pattern = "_lookback",
replacement = "",
x = FUN
)

## stop the function with
## a hard error.
## TODO: Consider the case for
## custom indicators, wrapper functions
## or exported functions that does not have
## a lookback-calculation.
stop(
"No indicator named `",
FUN,
"` was found.",
call. = FALSE
)
}

FUN <- get(
FUN,
envir = ns,
mode = "function",
inherits = FALSE
)

## upstream returns -1
## for invalid input data
## relative to the indicator;
## SMA, for example, requires at
## minimum two data points to calculate
## given n = 2 - and three, if n = 3.
##
## if the indicator and input are not
## satisfying this constraint upstream
## returns -1, ie. not applicable.
minimum_lookback <- do.call(
FUN,
args = list(...)
)

if (minimum_lookback == -1) {
return(NA)
}

## volume, for example, returns
## a lookback of 0 if calculated without
## moving averages - wrap the lookback
## in max() as a safety precaution
max(
minimum_lookback,
1,
na.rm = TRUE
)
}
32 changes: 32 additions & 0 deletions R/ta_ACCBANDS.R
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,38 @@ acceleration_bands.matrix <- function(
)
}

#' @usage NULL
ACCBANDS_lookback <- acceleration_bands_lookback <- function(
x,
cols,
n = 20,
...
) {
## validate 'cols'-argument
## if explicitly passed
if (!missing(cols)) {
assert_formula(cols)
}

## construct series
## from input
constructed_series <- series(
x = cols,
default_formula = ~ high + low + close,
data = x,
...
)

.Call(
C_impl_ta_ACCBANDS_lookback,
## splice:lookback:start
constructed_series[[1]],
constructed_series[[2]],
constructed_series[[3]],
as.integer(n)
## splice:lookback:end
)
}

#' @usage NULL
#' @aliases acceleration_bands
Expand Down
31 changes: 31 additions & 0 deletions R/ta_AD.R
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,37 @@ chaikin_accumulation_distribution_line.matrix <- function(
)
}

#' @usage NULL
AD_lookback <- chaikin_accumulation_distribution_line_lookback <- function(
x,
cols,
...
) {
## validate 'cols'-argument
## if explicitly passed
if (!missing(cols)) {
assert_formula(cols)
}

## construct series
## from input
constructed_series <- series(
x = cols,
default_formula = ~ high + low + close + volume,
data = x,
...
)

.Call(
C_impl_ta_AD_lookback,
## splice:lookback:start
constructed_series[[1]],
constructed_series[[2]],
constructed_series[[3]],
constructed_series[[4]]
## splice:lookback:end
)
}

#' @usage NULL
#' @aliases chaikin_accumulation_distribution_line
Expand Down
35 changes: 35 additions & 0 deletions R/ta_ADOSC.R
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,41 @@ chaikin_accumulation_distribution_oscillator.matrix <- function(
)
}

#' @usage NULL
ADOSC_lookback <- chaikin_accumulation_distribution_oscillator_lookback <- function(
x,
cols,
fast = 3,
slow = 10,
...
) {
## validate 'cols'-argument
## if explicitly passed
if (!missing(cols)) {
assert_formula(cols)
}

## construct series
## from input
constructed_series <- series(
x = cols,
default_formula = ~ high + low + close + volume,
data = x,
...
)

.Call(
C_impl_ta_ADOSC_lookback,
## splice:lookback:start
constructed_series[[1]],
constructed_series[[2]],
constructed_series[[3]],
constructed_series[[4]],
as.integer(fast),
as.integer(slow)
## splice:lookback:end
)
}

#' @usage NULL
#' @aliases chaikin_accumulation_distribution_oscillator
Expand Down
32 changes: 32 additions & 0 deletions R/ta_ADX.R
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,38 @@ average_directional_movement_index.matrix <- function(
)
}

#' @usage NULL
ADX_lookback <- average_directional_movement_index_lookback <- function(
x,
cols,
n = 14,
...
) {
## validate 'cols'-argument
## if explicitly passed
if (!missing(cols)) {
assert_formula(cols)
}

## construct series
## from input
constructed_series <- series(
x = cols,
default_formula = ~ high + low + close,
data = x,
...
)

.Call(
C_impl_ta_ADX_lookback,
## splice:lookback:start
constructed_series[[1]],
constructed_series[[2]],
constructed_series[[3]],
as.integer(n)
## splice:lookback:end
)
}

#' @usage NULL
#' @aliases average_directional_movement_index
Expand Down
32 changes: 32 additions & 0 deletions R/ta_ADXR.R
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,38 @@ average_directional_movement_index_rating.matrix <- function(
)
}

#' @usage NULL
ADXR_lookback <- average_directional_movement_index_rating_lookback <- function(
x,
cols,
n = 14,
...
) {
## validate 'cols'-argument
## if explicitly passed
if (!missing(cols)) {
assert_formula(cols)
}

## construct series
## from input
constructed_series <- series(
x = cols,
default_formula = ~ high + low + close,
data = x,
...
)

.Call(
C_impl_ta_ADXR_lookback,
## splice:lookback:start
constructed_series[[1]],
constructed_series[[2]],
constructed_series[[3]],
as.integer(n)
## splice:lookback:end
)
}

#' @usage NULL
#' @aliases average_directional_movement_index_rating
Expand Down
Loading
Loading