Modular, execution-oriented strategy workflows that transform market features, portfolio state, and dynamic quantitative analysis into actionable signals, target positions, portfolio adjustments, and order intents. The package emphasizes path-dependent historical simulation so strategy decisions remain consistent with evolving account state, execution assumptions, and market conditions.
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.
devtools::install_github("OliverLDS/strategyr")
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
)
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
)
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
)
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)]
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
)
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
)
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.
Oliver Zhou [email protected]
MIT License