strategyr

strategyr is an execution-oriented R package for modular strategy workflows. It is designed to transform already-available market features, portfolio state, and dynamic quantitative analysis into actionable signals, target positions, portfolio adjustments, and order intents.

The package emphasizes path-dependent backtesting so strategy logic is evaluated under evolving account state, execution assumptions, and market conditions rather than through purely static signal research.

Compared with investlabr, which is oriented toward exploratory research and communication, strategyr is intended for disciplined strategy logic and timely investment decision support.

Installation

devtools::install_github("OliverLDS/strategyr")

Usage Cases

1. Single-asset strategy backtest

library(data.table)
library(strategyr)

DT <- data.table(
  datetime = as.POSIXct("2020-01-01", tz = "UTC") + 86400 * 0:249
)
DT[, close := 100 + cumsum(sin(seq_len(.N) / 8) + 0.15)]
DT[, open := shift(close, fill = close[1])]
DT[, high := pmax(open, close) + 1]
DT[, low := pmin(open, close) - 1]

tgt_pos <- strat_donchian_turtle_tgt_pos(
  DT,
  entry_n = 30L,
  exit_n = 10L,
  target_size = 0.95
)

eq <- backtest_rcpp(
  timestamp = as.numeric(DT$datetime),
  open = DT$open,
  high = DT$high,
  low = DT$low,
  close = DT$close,
  tgt_pos = tgt_pos,
  pos_strat = rep(307L, nrow(DT)),
  tol_pos = rep(0.05, nrow(DT)),
  strat = 307L,
  asset = 8001L,
  ctr_step = 0.01,
  lev = 1,
  fee_rt = 0.0005,
  rec = TRUE
)

calc_strategy_performance_summary(
  eq,
  tgt_pos = tgt_pos,
  recorder = attr(eq, "recorder"),
  fee_rt = 0.0005
)

2. Latest-state action plan

state <- list(
  ctr_size = 1.0,
  ctr_step = 1.0,
  lev = 10.0,
  last_px = 100.0,
  ctr_unit = 0.0,
  avg_price = NaN,
  cash = 10000.0,
  pos_dir = 0L
)

plan <- strat_donchian_turtle_action_plan(
  DT,
  state,
  entry_n = 30L,
  exit_n = 10L,
  target_size = 0.95,
  strat_id = 307L
)

3. Warmup-aware strategy mining

walk_res <- mine_strategy_walk_forward(
  DT,
  strategy_fun = strat_ema_triple_trend_tgt_pos,
  param_grid = data.table::CJ(
    fast = c(10L, 20L),
    mid = c(30L, 50L),
    slow = c(80L, 120L),
    target_size = 0.95
  )[fast < mid & mid < slow],
  train_years = 1,
  test_years = 0.5,
  step_years = 0.5,
  n_best = 2L,
  min_train_rows = 100L,
  min_test_rows = 50L,
  warmup_days = 120L,
  strat_id = 106L,
  ctr_step = 0.01,
  lev = 1,
  fee_rt = 0.0005
)

summarize_walk_forward_results(walk_res, group_cols = c("fast", "mid", "slow"))
filter_walk_forward_results(
  walk_res,
  group_cols = c("fast", "mid", "slow"),
  min_windows = 1L,
  min_positive_return_rate = 0.5,
  max_avg_score_decay = 10
)

4. Cross-sectional allocator and portfolio backtest

panel <- CJ(
  date = as.Date("2020-01-01") + 0:9,
  asset = c("AAA", "BBB", "CCC")
)
panel[, score := fifelse(asset == "AAA", 0.8, fifelse(asset == "BBB", 0.4, 0.2)) + as.numeric(date - min(date)) / 100]
panel[, open := 100 + match(asset, c("AAA", "BBB", "CCC")) * 5 + as.numeric(date - min(date))]
panel[, close := open * (1 + score / 100)]
panel[, target_weight := strat_cross_sectional_rank_allocator_tgt_pos(
  panel,
  date_col = "date",
  asset_col = "asset",
  signal_col = "score",
  long_n = 2L,
  short_n = 0L,
  gross_exposure = 1.0
)]

portfolio_bt <- backtest_portfolio_weights(
  panel,
  initial_equity = 100000,
  fee_rt = 0.0005
)

portfolio_bt$equity[, .(date, equity, gross_exposure, turnover, fee_paid)]

5. Fixed-income carry/roll and hedge workflow

bond_dt <- data.table(
  par = rep(100, 5),
  c_rate = rep(0.05, 5),
  maturity = seq(2, 6),
  freq = rep(2, 5),
  ytm = c(0.045, 0.044, 0.043, 0.042, 0.041)
)

carry_tgt <- strat_bond_carry_roll_tgt_pos(
  bond_dt,
  long_threshold = 0,
  short_threshold = -0.02,
  target_size = 0.5
)

bond_state <- calc_bond_risk_state(
  par = 100,
  c_rate = 0.06,
  maturity = 3,
  freq = 2,
  ytm = 0.05,
  accrual_frac = 0.25
)

dv01_plan <- plan_duration_neutral_adjustment(
  current_dv01 = bond_state$dv01 * 1000,
  target_dv01 = 0,
  hedge_dv01 = -125
)

6. Option and volatility workflow

option_chain <- CJ(
  date = as.Date("2020-01-01") + 0:79,
  time_to_expiry = c(30, 60) / 365,
  type = c("put", "call")
)
option_chain[, option_log_forward_moneyness := fifelse(type == "put", -0.1, 0.1)]
option_chain[, close := 100 + as.numeric(date - min(date)) * 0.1]
option_chain[, iv := 0.2 + fifelse(type == "put", 0.03, -0.01) + sin(seq_len(.N) / 20) / 100]

iv_tgt <- strat_iv_directional_overlay_tgt_pos(
  option_chain,
  trend_n = 20L,
  skew_long_threshold = 0.02,
  skew_short_threshold = -0.02,
  overlay_mode = "confirm"
)

option_state <- calc_option_risk_state(
  S = 100,
  K = 100,
  time_to_expiry = 30 / 365,
  r = 0.04,
  sigma = 0.25,
  type = "call"
)

delta_plan <- plan_delta_neutral_adjustment(
  current_delta = option_state$delta * 100,
  target_delta = 0,
  hedge_delta = -50
)

7. Public strategy definitions for Vox

strategy_public_definition("donchian_turtle")
strategy_monitor_definition("donchian_turtle")

strategy_public_definition() is the canonical public-safe source for Vox strategy descriptions and effective default parameters. Parameter values are finite numbers or NULL; NULL explicitly marks an unbounded setting that is disabled by default so definitions remain JSON-safe. strategy_monitor_definition() is the canonical public-safe source for Strategy Monitor family and regime metadata. Current Vox monitor ids are buy_hold, ema_cross_adx, ema_cross_slope_confirm, rsi_revert, vol_target, donchian_turtle, bollinger_revert, and regime_switch.

Docs

Current Scope

Author

Oliver Zhou oliver.yxzhou@gmail.com

License

MIT License

mirror server hosted at Truenetwork, Russian Federation.