cummax()
cummax(x) The cummax() function computes the cumulative maximum of a vector, returning a vector of the same length where each element is the maximum of all preceding elements.
Syntax
cummax(x)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
x | numeric | required | A numeric vector |
Examples
Basic usage
The cummax() function scans a vector from left to right, tracking the largest value encountered at each position. The result always matches the input length, starts equal to the first element, and is guaranteed to be non-decreasing. This property makes it useful for tracking running bests, all-time highs, and peak detection in time series data.
x <- c(1, 2, 3, 4, 5)
cummax(x)
# [1] 1 2 3 4 5
# With decreasing values
y <- c(5, 4, 3, 2, 1)
cummax(y)
# [1] 5 5 5 5 5
# With mixed values
z <- c(3, 1, 4, 1, 5)
cummax(z)
# [1] 3 3 4 4 5
Tracking running maximum
A common application of cummax() is tracking the highest value observed up to each point in a sequence. In business contexts, this represents the best single-day sales figure so far through a quarter, or the peak customer count recorded at each hour during the day. The running maximum highlights trend inflection points where new records are set, and flat stretches show where the previous record still stands unchallenged.
# Sales data
sales <- c(100, 150, 80, 200, 175)
# Running maximum revenue
cummax(sales)
# [1] 100 150 150 200 200
Common patterns
Peak detection
Computing all-time highs is the classic use of cummax() in finance. Stock price analysis uses the running maximum to identify drawdowns: the distance between current price and historical peak. A drawdown of zero means the series is at a new high, while positive drawdown values measure how far the current observation has fallen from its previous peak. This metric is fundamental to risk assessment and portfolio performance tracking.
# Stock prices
prices <- c(100, 95, 105, 98, 110, 105, 115)
# All-time highs
cummax(prices)
# [1] 100 100 105 105 110 110 115
Performance tracking
Beyond financial data, cummax() applies to any sequential measurement where you want to track the best-so-far value. Test scores, athletic performances, sensor readings, and quality control metrics all benefit from a running maximum that shows whether improvement is ongoing or has plateaued. The function transforms a raw sequence into a monotonic summary that highlights progress and identifies the points where new benchmarks are set.
# Test scores over time
scores <- c(85, 78, 92, 88, 95, 90, 98)
# Best score so far
cummax(scores)
# [1] 85 85 92 92 95 95 98
cummax() and cummin() in practice
cummax() returns the running maximum, each position holds the largest value seen so far from left to right. This is useful for tracking drawdowns in financial time series (how far below the historical peak is the current value), watermark problems (has this metric ever been exceeded?), and monotonicity checks.
The common drawdown calculation is cummax(price) - price, which gives the distance from the historical high at each point. A value of zero means the series is at a new high; positive values indicate how far below the peak the current observation is.
cummax() propagates NA values: once an NA appears, all subsequent values are also NA. Remove missing values first with na.omit() or handle them explicitly if you want the running maximum to skip over gaps in the data.
cummax() handles ties by keeping the existing maximum (the first occurrence takes precedence). The result is always non-decreasing. A series of all equal values returns that value repeated. For time series work, cummax() is commonly used together with diff(): diff(cummax(x) == x) identifies the positions where new highs are set — a -1 at position i means the series left a new-high state, and 1 means it entered one.
A related pattern is computing the maximum drawdown of a series: max(cummax(prices) - prices). This gives the largest peak-to-trough decline, a standard risk measure in finance. The drawdown at any point is cummax(prices) - prices[i]; the maximum across all time points is the maximum drawdown. cummax() makes this single-pass computation possible without writing an explicit loop.
cummax() and cummin() handle NA values by propagating them forward: once an NA appears in the sequence, all subsequent values are also NA. Use cummax(x[!is.na(x)]) if you want to skip missing values and compute the running maximum over non-missing elements only. This propagation behavior mirrors how max() handles NA by default (returning NA unless na.rm = TRUE) but applies position by position to the entire sequence.
Drawdown calculation on financial data
The maximum drawdown — the largest peak-to-trough decline — is a standard risk metric computed directly with cummax():
# Daily closing prices over 20 trading days
prices <- c(100, 102, 101, 98, 95, 97, 103, 108, 105, 100,
96, 93, 99, 104, 107, 110, 106, 102, 98, 101)
highs <- cummax(prices) # running peak
drawdown <- highs - prices # distance below peak at each day
max_dd <- max(drawdown) # largest decline
max_dd
# [1] 15
# Days where a new high was set
which(diff(highs) > 0)
# [1] 1 5 6 7 13 14 15
which(diff(highs) > 0) identifies the exact positions where the cumulative maximum increased — in other words, the days that set a new record. For portfolio reporting, you would pair this with prices[which(diff(highs) > 0) + 1] to extract the new record values. The + 1 offset accounts for diff() returning one fewer element than its input.