I'm still not sure about well-known functions, but limiting the gradient seems to be fairly effective.
The green series was computed in Pandas with:
def limit_gradient(y, grad_bound, iterations):
for _ in range(iterations + 1):
grad = y.diff() / y.index.to_series().diff().dt.days
y = y[(grad > -grad_bound) | grad.isna()]
grad = y.diff(periods=-1) / y.index.to_series().diff(periods=-1).dt.days
y = y[(grad < grad_bound) | grad.isna()]
return y
def limit_gradient(y, grad_bound, iterations):
for _ in range(iterations + 1):
# Forwards
grad = y.diff() / y.index.to_series().diff().dt.days
y = y[(grad > -grad_bound) | grad.isna()]
# Backwards
grad = y.diff(periods=-1) / y.index.to_series().diff(periods=-1).dt.days
y = y[(grad < grad_bound) | grad.isna()]
return y
It's not great where the gradient should be less than the given bound, e.g. at the bottom of the curve, where noise creeps in. Maybe the bound could be made to vary in time using the low-pass data.