Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 9 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ R package (`talib`) providing an interface to the TA-Lib C library for technical
## Build Commands

```bash
make build # Full build: gen-code → document → install
make build # Full build: cleanfmt → document → install (does NOT run gen-code)
make check # R CMD check --as-cran
make check-full # R CMD check with valgrind
make test # Run testthat suite
Expand All @@ -25,21 +25,19 @@ Single test file: `Rscript -e "testthat::test_file('tests/testthat/test-ta_APO.R

### Code Generation (Most Source Files Are Generated)

Most R wrappers (`R/ta_*.R`), C wrappers (`src/ta_*.c`), and tests (`tests/testthat/test-ta_*.R`) are **auto-generated**. Do not edit these directly — modify the generation infrastructure in `codegen/` instead:
Most R wrappers (`R/ta_*.R`), the C X-macro header (`src/TA-Lib.h`), and tests (`tests/testthat/test-ta_*.R`) are **auto-generated** by the zero-dependency Rust crate in `codegen/` — see `codegen/README.md` for the full architecture. Do not edit generated files directly — modify the generation infrastructure instead:

- `codegen/gen_code/indicators.R` — Unified metadata for all 128 indicators
- `codegen/gen_code/generate.R` — Single driver script that generates R, C, and test files
- `codegen/gen_code/utils.R` — `impl_generate_indicator()` and `impl_generate_test()` helpers
- `codegen/generate_indicator.sh`, `generate_API.sh`, `generate_FFI.sh` — Shell scripts for template-driven generation
- `src/api.h` and `src/init.c` — Auto-generated (function prototypes and R registration)
- `codegen/src/` — `main.rs` (driver), `c_header.rs` (C X-macro lines from ta_func.h), `metadata.rs` (XML mining), `render.rs` (template rendering + splice preservation), `testthat.rs` (test files), `tables.rs` (the hand-maintained per-indicator lookup tables: names, chart types, classifications, exclusions)
- `codegen/templates/` — plain R files with `${...}` placeholders; the `chart_*` templates are dual-backend (one file renders both the `.plotly` and `.ggplot` method)
- Hand-edited content between `## splice:<name>:start` / `## splice:<name>:end` markers in generated files survives regeneration

Run `make gen-code` after changing any generation logic.
Run `make gen-code` after changing any generation logic (`cargo test` inside `codegen/` tests the generator itself).

### R ↔ C Binding

Uses `.Call()` (R's native C interface), not Rcpp. Each indicator has:

1. **C wrapper** (`src/ta_*.c`): Converts R SEXP → C arrays, calls TA-Lib, returns SEXP matrix
1. **C wrapper**: one X-macro line in the generated `src/TA-Lib.h`, expanded by the hand-written `src/wrapper.h`/`src/init.c` macros into a function that converts R SEXP → C arrays, calls TA-Lib, and returns a SEXP matrix (there are no per-indicator `.c` files)
2. **R wrapper** (`R/ta_*.R`): S3 generic with methods for `default`, `data.frame`, and `plotly`

C memory management uses manual `PROTECT`/`UNPROTECT` with protection counters.
Expand Down Expand Up @@ -87,8 +85,8 @@ isolated without depending on those packages. `chart()` and its
- `R/helper.R` — Operators (`%nn%`, `%or%`), chart helpers (`plotly_init`, `plotly_line`, `ggplot_init`, `ggplot_line`, `modify_traces`, `add_idx`, `rebuild_formula`)
- `R/BTC.R`, `R/NVDA.R`, `R/SPY.R`, `R/ATOM.R` — Built-in OHLCV datasets (docs only; `.rda` files in `data/`)
- `R/talib-package.R` — `generate_returns_section()` used at roxygen-render time by `man-roxygen/returns.R`
- `src/dataframe.c` — Matrix↔data.frame conversion (`map_dfr`)
- `src/container.h`, `src/shift.h`, `src/names.h` — Shared C utilities
- `src/data-frame.c` — Matrix↔data.frame conversion (`map_dfr`)
- `src/shift.h`, `src/names.h` — Shared C utilities

### TA-Lib Submodule

Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ document: ## Build R documentation
@Rscript --verbose -e "devtools::document()"

build: clean fmt ## Build the R package
@codegen/generate_API.sh src/ src/api.h && codegen/generate_FFI.sh src/api.h src/init.c && $(MAKE) fmt
@$(MAKE) document
@R CMD build . --no-build-vignettes && R CMD INSTALL $(tarball_location)
@rm -rf README.md
Expand Down Expand Up @@ -69,6 +68,7 @@ fmt: ## Format code
@air format R
@air format tests/testthat
@rm -rf ./.clang-format
@cargo fmt --manifest-path codegen/Cargo.toml

pkgdown-build: ## Build {pkgdown} documentation
@$(MAKE) document
Expand Down Expand Up @@ -133,5 +133,6 @@ parity-clean: ## Remove parity build artifacts and the generated test file
@rm -rf tests/parity/snapshot

gen-code: ## Generate R wrappers and unit-tests
@cargo run --manifest-path codegen/Cargo.toml
@Rscript --verbose ./codegen/gen_code/generate.R
$(MAKE) fmt
62 changes: 20 additions & 42 deletions R/ta_ACCBANDS.R
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#' @export
#' @family Overlap Study
#' @family Overlap Studies
#'
#' @title Acceleration Bands
#' @templateVar .title Acceleration Bands
#' @templateVar .author Serkan Korkmaz
#' @templateVar .fun acceleration_bands
#' @templateVar .family Overlap Study
#' @templateVar .formula ~ high + low + close
#' @templateVar .family Overlap Studies
#' @templateVar .formula ~high + low + close
#'
## splice:documentation:start
## splice:documentation:end
Expand All @@ -16,7 +16,7 @@
acceleration_bands <- function(
x,
cols,
n = 20,
timePeriod = 20,
na.bridge = FALSE,
...
) {
Expand All @@ -37,7 +37,7 @@ ACCBANDS <- acceleration_bands
acceleration_bands.default <- function(
x,
cols,
n = 20,
timePeriod = 20,
na.bridge = FALSE,
...
) {
Expand All @@ -64,12 +64,10 @@ acceleration_bands.default <- function(
## return as data.frame
x <- .Call(
C_impl_ta_ACCBANDS,
## splice:call:start
constructed_series[[1]],
constructed_series[[2]],
constructed_series[[3]],
as.integer(n),
## splice:call:end
as.integer(timePeriod),
as.logical(na.bridge)
)

Expand All @@ -87,15 +85,15 @@ acceleration_bands.default <- function(
acceleration_bands.data.frame <- function(
x,
cols,
n = 20,
timePeriod = 20,
na.bridge = FALSE,
...
) {
map_dfr(
acceleration_bands.default(
x = x,
cols = cols,
n = n,
timePeriod = timePeriod,
na.bridge = na.bridge,
...
)
Expand All @@ -109,60 +107,40 @@ acceleration_bands.data.frame <- function(
acceleration_bands.matrix <- function(
x,
cols,
n = 20,
timePeriod = 20,
na.bridge = FALSE,
...
) {
acceleration_bands.default(
x = x,
cols = cols,
n = n,
timePeriod = timePeriod,
na.bridge = na.bridge,
...
)
}

#' @usage NULL
ACCBANDS_lookback <- acceleration_bands_lookback <- function(
acceleration_bands_lookback <- function(
x,
cols,
n = 20,
timePeriod = 20,
na.bridge = FALSE,
...
) {
## 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
as.integer(timePeriod)
)
}

#' @usage NULL
#' @aliases acceleration_bands
#'
#' @export
acceleration_bands.plotly <- function(
x,
cols,
n = 20,
timePeriod = 20,
na.bridge = FALSE,
## splice:optional-plotly:start
color = "steelblue",
Expand Down Expand Up @@ -196,7 +174,7 @@ acceleration_bands.plotly <- function(
cols = rebuild_formula(
names(constructed_series)
),
n = n,
timePeriod = timePeriod,
na.bridge = TRUE
)

Expand All @@ -209,7 +187,7 @@ acceleration_bands.plotly <- function(
## splice:plotly-assembly:start
name <- label(
"Acceleration Bands",
n
timePeriod
)

traces <- list(
Expand Down Expand Up @@ -267,7 +245,7 @@ acceleration_bands.plotly <- function(
acceleration_bands.ggplot <- function(
x,
cols,
n = 20,
timePeriod = 20,
na.bridge = FALSE,
## splice:optional-ggplot:start
## splice:optional-ggplot:end
Expand Down Expand Up @@ -298,7 +276,7 @@ acceleration_bands.ggplot <- function(
cols = rebuild_formula(
names(constructed_series)
),
n = n,
timePeriod = timePeriod,
na.bridge = TRUE
)

Expand All @@ -320,7 +298,7 @@ acceleration_bands.ggplot <- function(
y_lower = "LowerBand"
)
)
name <- label("ACCBANDS", n)
name <- label("ACCBANDS", timePeriod)
## splice:ggplot-assembly:end

state <- .chart_state()
Expand Down
37 changes: 7 additions & 30 deletions R/ta_AD.R
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#' @export
#' @family Volume Indicator
#' @family Volume Indicators
#'
#' @title Chaikin A/D Line
#' @templateVar .title Chaikin A/D Line
#' @templateVar .author Serkan Korkmaz
#' @templateVar .fun chaikin_accumulation_distribution_line
#' @templateVar .family Volume Indicator
#' @templateVar .formula ~high+low+close+volume
#' @templateVar .family Volume Indicators
#' @templateVar .formula ~high + low + close + volume
#'
## splice:documentation:start
## splice:documentation:end
Expand Down Expand Up @@ -62,12 +62,10 @@ chaikin_accumulation_distribution_line.default <- function(
## return as data.frame
x <- .Call(
C_impl_ta_AD,
## splice:call:start
constructed_series[[1]],
constructed_series[[2]],
constructed_series[[3]],
constructed_series[[4]],
## splice:call:end
as.logical(na.bridge)
)

Expand Down Expand Up @@ -117,37 +115,16 @@ chaikin_accumulation_distribution_line.matrix <- function(
}

#' @usage NULL
AD_lookback <- chaikin_accumulation_distribution_line_lookback <- function(
chaikin_accumulation_distribution_line_lookback <- function(
x,
cols,
na.bridge = FALSE,
...
) {
## 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
C_impl_ta_AD_lookback
)
}

#' @usage NULL
#' @aliases chaikin_accumulation_distribution_line
#'
Expand Down Expand Up @@ -247,9 +224,9 @@ chaikin_accumulation_distribution_line.ggplot <- function(
x,
cols,
na.bridge = FALSE,
title,
## splice:optional-ggplot:start
## splice:optional-ggplot:end
title,
...
) {
## check ggplot2 availability
Expand Down
Loading
Loading