examples: fix and harmonize the strategy backtests across all languages (#324)
The strategy_* examples were only syntax-smoked in CI, never run, which hid two classes of problem: 1. Python strategy_macd_adx / strategy_bollinger_squeeze passed three separate arguments to the candle indicators ADX/ATR, whose .update() takes a single candle — a TypeError at runtime — and read the ADX tuple at index 0 (plus_di) instead of 2 (adx). Both fixed. 2. The Go / C# / R / Java strategies defaulted to synthetic data and used a different (annualised) one-line summary, so they printed wildly different numbers from the Rust/Python/Node/C/WASM suite. Rewrite them to the shared per-trade backtest (load the bundled BTCUSDT CSV by default, same entry/exit logic, same print_summary output). All nine runnable bindings now print byte-identical backtest summaries on the same data (MACD+ADX 246 trades / -47.19%, RSI 37 / -17.84%, Bollinger 1 / -7.82%), verified by diffing each language's output against the Python reference. WASM shares the same logic and bundled dataset (browser-rendered).
This commit is contained in:
@@ -1,24 +1,54 @@
|
||||
# Trend follower: enter long on a MACD histogram cross up, but only when ADX(14) > 20
|
||||
# confirms a trend; exit when the histogram crosses back below zero.
|
||||
library(wickra)
|
||||
# Strategy example: MACD crossover with ADX trend-strength filter.
|
||||
#
|
||||
# Enters long on a MACD histogram cross up (the histogram turns positive) while
|
||||
# ADX(14) > 20 (a directional market); exits on the opposite MACD crossover
|
||||
# regardless of ADX. 0.1% fees per trade. The R counterpart of
|
||||
# examples/python/strategy_macd_adx.py, printing the same summary. Uses the
|
||||
# checked-in examples/data/btcusdt-1h.csv dataset (pass a CSV path to override).
|
||||
suppressPackageStartupMessages(library(wickra))
|
||||
source("_common.R")
|
||||
|
||||
FEE <- 0.001
|
||||
ADX_FLOOR <- 20
|
||||
|
||||
args <- commandArgs(trailingOnly = TRUE)
|
||||
bars <- if (length(args) >= 1) load_ohlcv_csv(args[1]) else synthetic_candles(2000)
|
||||
bars <- if (length(args) >= 1) load_ohlcv_csv(args[1]) else bundled_candles("btcusdt-1h.csv")
|
||||
|
||||
opens <- bars$open; highs <- bars$high; lows <- bars$low
|
||||
closes <- bars$close; vols <- bars$volume; ts <- bars$timestamp
|
||||
n_bars <- length(closes)
|
||||
|
||||
macd <- MacdIndicator(12, 26, 9); adx <- Adx(14)
|
||||
returns <- numeric(0); trades <- 0L; in_pos <- FALSE; entry <- 0; prev_hist <- NA_real_
|
||||
for (i in seq_len(nrow(bars))) {
|
||||
b <- bars[i, ]
|
||||
m <- update(macd, b$close)
|
||||
a <- update(adx, b$open, b$high, b$low, b$close, b$volume, b$timestamp)
|
||||
in_pos <- FALSE; entry_price <- 0; closed <- numeric(0); equity <- 1
|
||||
equity_curve <- numeric(n_bars); have_prev <- FALSE; prev_sign <- FALSE
|
||||
|
||||
for (i in seq_len(n_bars)) {
|
||||
m <- update(macd, closes[i])
|
||||
a <- update(adx, opens[i], highs[i], lows[i], closes[i], vols[i], ts[i])
|
||||
price <- closes[i]
|
||||
equity_curve[i] <- if (in_pos) equity * (price / entry_price) else equity
|
||||
if (is.na(m[["macd"]]) || is.na(a[["adx"]])) next
|
||||
trending <- a[["adx"]] > 20
|
||||
if (!in_pos && trending && is.finite(prev_hist) && prev_hist <= 0 && m[["histogram"]] > 0) {
|
||||
in_pos <- TRUE; entry <- b$close; trades <- trades + 1L
|
||||
} else if (in_pos && m[["histogram"]] < 0) {
|
||||
returns <- c(returns, (b$close - entry) / entry); in_pos <- FALSE
|
||||
|
||||
hist_sign <- m[["histogram"]] > 0
|
||||
cross_up <- have_prev && !prev_sign && hist_sign
|
||||
cross_down <- have_prev && prev_sign && !hist_sign
|
||||
have_prev <- TRUE; prev_sign <- hist_sign
|
||||
|
||||
if (!in_pos && cross_up && a[["adx"]] > ADX_FLOOR) {
|
||||
entry_price <- price; equity <- equity * (1 - FEE); in_pos <- TRUE
|
||||
} else if (in_pos && cross_down) {
|
||||
trade_ret <- price / entry_price - 1
|
||||
closed <- c(closed, trade_ret)
|
||||
equity <- equity * (1 + trade_ret) * (1 - FEE)
|
||||
in_pos <- FALSE
|
||||
}
|
||||
prev_hist <- m[["histogram"]]
|
||||
}
|
||||
print_equity("MACD + ADX trend", summarize_equity(returns, trades))
|
||||
|
||||
if (in_pos) {
|
||||
trade_ret <- closes[n_bars] / entry_price - 1
|
||||
closed <- c(closed, trade_ret)
|
||||
equity <- equity * (1 + trade_ret) * (1 - FEE)
|
||||
}
|
||||
|
||||
print_summary("MACD + ADX Trend Filter (1h, BTCUSDT)",
|
||||
closes[1], closes[n_bars], n_bars, closed, equity, equity_curve)
|
||||
|
||||
Reference in New Issue
Block a user