This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
rwRtools is an R package giving RW Pro members access to Robot Wealth's Lab datasets in Google Cloud Storage (GCS). It is the data access layer for 5 Research Pods: EquityFactors, FX, Crypto, Macro, and TLAQ. Each pod has its own GCS bucket and a family of pod_get_*() loader functions.
Members install straight from GitHub master (pacman::p_load_current_gh("RWLab/rwRtools")), so master is production. Bump Version in DESCRIPTION when shipping a change.
devtools::load_all() # Load package locally
devtools::document() # Regenerate man/ and NAMESPACE from roxygen2 comments (required after any @export change)
devtools::check() # Full R CMD check
devtools::test() # Runs nothing: tests/testthat.R has test_check() commented out and there is no tests/testthat/ dirR is not on PATH in the shell. Run scripts with the full path:
"/c/Program Files/R/R-4.5.2/bin/Rscript.exe" -e 'devtools::document()'Real verification requires GCS auth (rwlab_data_auth() opens a browser), so most roxygen examples are \dontrun{} and there is no automated test coverage. Test loaders interactively.
- GCS core (
R/rwlab_gcs.R) —get_pod_meta()holds the hardcoded pod → bucket mapping.transfer_lab_object()(internal) downloads one object;load_lab_object()(exported) downloads and reads it as feather.transfer_pod_data()/quicksetup()bulk-load a pod'sessentialsand assign apricesdata.frame into.GlobalEnv. - Pod loaders (
R/crypto_data_utils.R,R/fx_data_utils.R,R/macro_pod_utils.R,R/equity_factors_utils.R) — thin wrappers that calltransfer_lab_object()for a specific object, read it, fix column types, and return a tibble. Every loader follows the same shape:
pod_get_thing <- function(path = "<pod-dir>", force_update = TRUE) {
if(!file.exists(file.path(path, "thing.feather")) || force_update == TRUE) {
transfer_lab_object(pod = "Pod", object = "gcs/prefix/thing.feather", path = path)
}
rw_read_feather(file.path(path, "thing.feather")) %>% dplyr::mutate(date = lubridate::as_date(date))
}Adding a dataset = add a loader in the right pod file following this shape, @export it, run devtools::document(). Adding a pod = add an entry to get_pod_meta() plus a new *_utils.R file.
R/feather_io.R defines the only feather reader. It wraps arrow::read_feather() with arrow.use_altrep = FALSE set locally (restored on exit). ALTREP-backed columns from arrow have crashed downstream dplyr::filter() calls with vec_slice_altrep(): negative length vectors are not allowed on large frames. The feather package is deprecated and is no longer a dependency. Never call arrow::read_feather() or feather::read_feather() directly in package code.
Two flags with different meanings:
force_update(pod loaders, defaultTRUE): whether to calltransfer_lab_object()at all.FALSEuses the local file with no network call.force(transfer_lab_object()/load_lab_object(), defaultFALSE): whether to skip the cache check. WhenFALSEand a local file exists, it fetches GCS object metadata and reuses the local file only if size matches and local mtime >= remoteupdated. Otherwise it re-downloads with overwrite.
Pod loaders do not pass force through, so force_update = TRUE means "verify against GCS and download if changed", not "always re-download". transfer_pod_data() (and therefore quicksetup()) bypasses the cache and always downloads.
GCS objects may have directory prefixes (statarb/spreads.feather, feather/Daily/EURUSD.feather). Locally only the basename is kept, inside a per-pod default directory relative to the working directory:
| Pod | Default path |
|---|---|
| Macro | macropod |
| EquityFactors | equityfactors |
| Crypto | binance, ftx, coinmetrics, coincodex (by source) |
| FX | Daily, Hourly, Zorro-Assets-Lists, Policy-Rates |
core rwlab_gcs.R functions |
. |
Because prefixes are dropped, equity_get_statarb_prices() (statarb/prices.feather) and equity_get_liquid_universe() (equity_factors/prices.feather) both write equityfactors/prices.feather and will clobber each other. Pass distinct path values when using both.
The datasets vector in get_pod_meta() is stale and incomplete. Only essentials and prices are used (by transfer_pod_data() / quicksetup()). Many loaders fetch objects not listed there. FX has NA essentials and cannot be bulk-loaded.
quicksetup() reads the prices file via feather, or via hardcoded branches for two CSV names (coinmetrics.csv, main_asset_classes_daily_ohlc.csv). A new pod with a CSV prices file needs a new branch there.
rwlab_data_auth() takes no arguments (the oauth_email argument shown in README.md and older docs no longer exists). It uses gargle's built-in web OAuth client via unexported internals (gargle:::goc_web(), gargle:::is_google_colab()), forces OOB auth, and hands the token to googleCloudStorageR::gcs_auth(). This is known to be fragile across gargle versions. R/app.R (get_lab_app() calling an undefined gla()) and R/sysdata.rda (an OAuth client json_string) are remnants of a previous auth approach and are unused.
- Naming:
pod_get_noun_timeframe(), e.g.crypto_get_binance_spot_1d(),macro_get_expiring_vx_futures(),fx_get_daily_OHLC(). - Namespace:
NAMESPACEimports only%>%. Everything else must be fully qualified (glue::glue(),readr::read_csv(),lubridate::as_date()). Existing loaders callmutate,filter,select,arrange,renameunqualified and only work because members have dplyr attached. Usedplyr::in new code; R CMD check flags the unqualified ones. - Paths: build with
file.path(path, ...)orglue::glue("{path}/..."); both are used. - Output: transfer functions report progress with
cat(), notmessage(). Loaders return a tibble, usually arranged by date then ticker. - Roxygen: every exported function has roxygen2 docs with a
\dontrun{}example.man/andNAMESPACEare generated; never hand-edit.
- Hyperliquid timestamps are at bar close; Binance timestamps are at bar open — lag HL by one bar to align.
- FTX datasets are historical only (exchange defunct).
- Date columns should be type
Datevialubridate::as_date(); datetime columns vialubridate::as_datetime(). - FX loaders strip
/from tickers (EUR/USD→EURUSD) because Zorro asset lists use slashes but GCS filenames do not.
examples/colab/load_libraries.R is sourced from the raw GitHub URL inside Colab. It writes and runs a bspm/r2u apt setup script, installs binaries via pacman, then installs rwRtools from GitHub with dependencies = FALSE. Any new package dependency must also be added to its core_packages vector or Colab installs will break. GitHub caches raw content for ~5 minutes after a push.
source('https://raw.githubusercontent.com/RWLab/rwRtools/master/examples/colab/load_libraries.R')
load_libraries(load_rsims = FALSE, extra_libraries = c('patchwork'))feature-requests/ is gitignored and holds informal specs for new loader functions. .claude/settings.local.json is also local.