# \[ANN\] Durbyn.jl — Time Series Forecasting in Julia

**URL:** <https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544>\
**Category:** Package Announcements\
**Tags:** package\
**Created:** [September 21, 2025, 8:35pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544 "2025-09-21T20:35:22Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![anon28281882](https://avatars.discourse-cdn.com/v4/letter/a/7ab992/32.png) [@anon28281882](https://discourse.julialang.org/u/anon28281882)\
**Post date:** [September 29, 2025, 11:59pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/41 "2025-09-29T23:59:43Z")

</div>

> [@Resul.Akay](#):
>
> C++ (for example) has been used as a backend in R and Python for long time. Why not Julia? easy to learn, and it is fast.

In general, on the surface, it is to some extent quite similar in Julia as well, though not as pronounced as in other ecosystems. Depending on how you look at it, one could even argue that there is a lot of C++ in Julia because of LLVM. However, I don’t think that claim is fully justified, since, at least as far as I know, thanks to this high-level assembly, much can be expressed directly in Julia’s syntax. Anyway, for example, the upcoming comp neuro & machine learning framework built on `Enzyme.jl`, `Reactant.jl`, and `Lux.jl` relies at its lower levels on LLVM IR and C++, at the middle level mainly on MLIR, and at the higher level primarily on Julia.

To answer your question: honestly, I think **it may be more rewarding to focus on innovation** than on supporting other ecosystems, especially given that **Julia, like Python** , is a general purpose language. That said, although I have recently become again more optimistic about Julia (with developments such as `PackageCompiler.jl`, `JuliaC.jl`, `BorrowChecker.jl`, `Enzyme.jl`, `Reactant.jl`, `Lux.jl`, and ongoing `research on the GC`), I believe there remains a significant risk, mainly due to **the speed at which other ecosystems are advancing**.

Personally, I am committed to Julia while also experimenting with q/kdb-x. I believe Julia is particularly well suited for time series analysis. By the way, could you share more information about the Time Series Analysis & Forecasting Society and its activities? And would you consider presenting `Durbyn.jl` at one of the [JuliaDynamics monthly meetings](https://discourse.julialang.org/t/juliadynamics-monthly-meetings-round-2/132357)? Thanks again for the package!

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [September 30, 2025, 6:20am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/42 "2025-09-30T06:20:39Z")

</div>

@anon28281882 From my perspective, the new compiler packages make Julia a strong candidate to be used as a backend for other languages. At the same time, I feel the bigger risk for Julia doesn’t come so much from **R** or **Python** , but rather from **Rust** , which is advancing quickly in performance-sensitive areas.

In my view, the Julia community could also benefit from engaging more with industry practitioners – people like me who work with large-scale forecasting problems – so that tools stay practical and relevant in production.

On a personal note, I’d be very happy to present in Julia community forums. Since I’ve only recently become involved in open source (most of my development work until now was for my employer), I haven’t had much interaction with the community before. If there’s an opportunity to contribute and share, I’d really welcome it.

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [September 30, 2025, 8:39am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/43 "2025-09-30T08:39:32Z")

</div>

There’s a related discussion happening on LinkedIn: [LinkedIn Post](https://www.linkedin.com/posts/activity-7378703114020790272-nZ2I).

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [October 1, 2025, 8:06pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/44 "2025-10-01T20:06:52Z")

</div>

Nice to see this effort.  
Re custom tables, I worked on some large scale forecasting problems where we also needed custom table implementations for performance, but we also kept all core functions generic by adopting the Tables.jl interface, and then just added the custom table also using that same interface. We could have supported any number of table types without touching any of the model code.

---

<div class="post-metadata">

**Author:** ![anon28281882](https://avatars.discourse-cdn.com/v4/letter/a/7ab992/32.png) [@anon28281882](https://discourse.julialang.org/u/anon28281882)\
**Post date:** [October 2, 2025, 10:22pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/45 "2025-10-02T22:22:01Z")

</div>

> [@Resul.Akay](#):
>
> @anon28281882 […] At the same time, I feel the bigger risk for Julia doesn’t come so much from **R** or **Python** , but rather from **Rust** , which is advancing quickly in performance-sensitive areas.

Well, yeah, I agree with you, it does look like not only performance-sensitive areas but almost the entire internet is being rewritten in Rust. In general, this kind of strategic analysis is closer to my background than programming itself. From my experience, it usually takes a lot of time and effort to identify all the relevant factors, opportunities, and strengths. It’s a fascinating topic, especially since it feels like the programming industry might currently be undergoing some structural changes.

I have to admit I haven’t done any deep thinking on this subject. I sustain, that my general impression is that sometimes other ecosystems seem to be advancing a bit faster than Julia’s. That being said, there’s also the question of quality. What I wanted to convey is that the packages and scientific work I mentioned earlier, as well as many other efforts I probably don’t know about, could put Julia in a much stronger position than it might seem at first glance, hence, our friends working with Rust might end up just spinning their wheels … :- )

> [@Resul.Akay](#):
>
> In my view, the Julia community could also benefit from engaging more with industry practitioners – people like me who work with large-scale forecasting problems – so that tools stay practical and relevant in production.

I think we actually are engaging. I guess, it’s hard to argue otherwise. Every post gets answered, there are already forty three messages in this topic, over 1.3k views, and high-quality advice on package performance and user interface.

> [@Resul.Akay](#):
>
> On a personal note, I’d be very happy to present in Julia community forums.

I think the best approach would be to contact the organizer of the [JuliaDynamics monthly meetings](https://discourse.julialang.org/t/juliadynamics-monthly-meetings-round-2/132357) directly with a message. From what I understand, your package is very much related to the kinds of topics usually discussed there. I am also aware that there are other opportunities, like during [JuliaConn](https://juliacon.org) which is a conference on the Julia programming language, however, I don’t know any details.

> [@Resul.Akay](#):
>
> There’s a related discussion happening on LinkedIn: [LinkedIn Post](https://www.linkedin.com/posts/activity-7378703114020790272-nZ2I).

I’m sorry, I wasn’t able to check that discussion. I have “LIn” heavily restricted on my computer, and I also have a long standing habit of not posting under my real name online. That said, I did send you an invite there. I’m always happy to make connections.

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [October 5, 2025, 9:13am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/46 "2025-10-05T09:13:17Z")

</div>

That’s exactly the plan — the goal is to build an **internal data infrastructure** , tentatively called **`PanelData`** , that’s lightweight and efficient while still **supporting all widely used Julia tabular formats** at the user level.

By keeping the internals minimal but exposing a **Tables.jl-compatible interface** , we can ensure Durbyn remains performant and scalable while integrating smoothly with the broader Julia data ecosystem – all without introducing unnecessary dependencies.

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [October 5, 2025, 3:02pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/47 "2025-10-05T15:02:57Z")

</div>

Julia provides excellent capabilities for writing **hardware-agnostic code** , allowing the same algorithm to run seamlessly on CPUs or GPUs. For example:

```Julia
using LinearAlgebra
using GPUArrays
using Adapt
using CUDA
using KernelAbstractions

@kernel function phi_kernel(y, phi, n, max_iter)
    i = @index(Global)
    if i <= max_iter
        acc_dot = zero(eltype(y))
        acc_norm = zero(eltype(y))
        for j = 1:(n - i)
            acc_dot += y[i + j] * y[j]
            acc_norm += y[j]^2
        end
        phi[i] = acc_dot / acc_norm
    end
end

function compute_phi(y::Union{AbstractGPUArray{T}, AbstractArray{T}}, max_iter::Int=15) where {T<:AbstractFloat}
    n = length(y)
    phi = similar(y, max_iter)
    backend = get_backend(y)

    kernel_inst = phi_kernel(backend)
    kernel_inst(y, phi, n, max_iter; ndrange=(max_iter,))

    return phi
end

```

Unfortunately, some standard libraries don’t yet fully support GPU arrays. Otherwise, the same computation could be expressed as simply as:

```julia
# Original equation from ARAR model 
function compute_phi(;y::AbstractArray, max_iter::Int=15)
    phi = [dot(y[i+1:end], y[1:end-i]) / sum(y[1:end-i].^2) for i in 1:max_iter]
    return phi
end

```

If we make better use of these features, Julia has everything needed to become a truly powerful, modern, and cross-hardware language.  
And just to be clear, I don’t mean these values don’t already exist, but with **even more constructive feedback, community collaboration, and structured code review** (similar to the CRAN process in R), Julia’s ecosystem could reach an exceptional level of reliability and performance.

---

<div class="post-metadata">

**Author:** ![anon28281882](https://avatars.discourse-cdn.com/v4/letter/a/7ab992/32.png) [@anon28281882](https://discourse.julialang.org/u/anon28281882)\
**Post date:** [October 9, 2025, 6:14pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/48 "2025-10-09T18:14:29Z")

</div>

I’m afraid I don’t have much to add. I’ve used `KernelAbstractions.jl` a few times, but I don’t have much experience with it. More often, I’ve used `AcceleratedKernels.jl`, which, as far as I understand, is a higher level abstraction built on top of `KernelAbstractions.jl`. As for support for various hardware architectures, I agree with you. Some of the packages I mentioned earlier can even run on TPUs. I’m not sure if it’s technically possible to program FPGAs using Julia, but that would be really cool. Regarding GPU array support, I’ve often thought it would be great if package maintainers always included a section about multithreading or parallel processing on the front page of their GitHub repositories.This would probably make the package ecosystem more coherent and, overall, be beneficial for the community.

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [October 14, 2025, 9:21am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/49 "2025-10-14T09:21:47Z")

</div>

An initial benchmark for R forecast vs R smooth vs Julia Durbyn:

```r
> packageVersion("forecast")
[1] ‘8.24.0’
> library(forecast)
> system.time({fit <- ets(AirPassengers, model = "ZZZ")})
   user system elapsed 
   0.31 0.00 0.31 
> fc = forecast(fit, h = 12)
> autoplot(fc)

```

```r
> packageVersion("smooth")
[1] ‘4.3.0’
> library(smooth)
> system.time({fit <- es(AirPassengers, model = "ZZZ")})
   user system elapsed 
  0.198 0.000 0.198 
> fc = forecast(fit, h = 12)
> plot(fc)

```

```julia

using Durbyn
using Durbyn.ExponentialSmoothing

ap = air_passengers();
fit_ets = ets(ap, 12, "ZZZ")
@time fit_ets = ets(ap, 12, "ZZZ");
# 0.011112 seconds
fc_ets = forecast(fit_ets, h = 12)
plot(fc_ets)

```

---

<div class="post-metadata">

**Author:** ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)\
**Post date:** [October 14, 2025, 10:09am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/50 "2025-10-14T10:09:39Z")

</div>

30x faster, it looks like. Very nice! 🏎

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [October 23, 2025, 8:38am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/51 "2025-10-23T08:38:01Z")

</div>

# New features to come next week

Formula interface with Tables.jl support.

I started with Arima.  
Thank you for your suggestions, now Table.jl supported.  
I introduce some R dplyr like functions to help R users to be able to us the Durbyn.jl

# Durbyn ARIMA Grammar

The Durbyn forecasting grammar lets you describe ARIMA and SARIMA models with a concise,  
readable syntax. This guide covers each grammar component and shows how to combine them  
when fitting models via `ArimaSpec` and `@formula`.

* * *

## 1. Formula Basics

Use the `@formula` macro to define the relationship between a target series and its  
ARIMA structure:

```julia
@formula(sales = p() + d() + q())

```

Every formula must provide a target (left-hand side) and one or more terms on the  
right-hand side. Terms may specify ARIMA orders, seasonal orders, exogenous variables,  
or automatic-exogenous selection (see below).

* * *

## 2. Non-Seasonal Orders

| Function | Meaning | Default or form |
| --- | --- | --- |
| `p()` | Non-seasonal AR order | Search range 2–5 |
| `p(k)` | Fix AR order | Uses `k` exactly |
| `p(min,max)` | Search AR order range | Searches `min` through `max` |
| `d()` | Differencing order (auto) | `auto_arima` chooses |
| `d(k)` | Fix differencing order | Uses `k` exactly |
| `q()` | Non-seasonal MA order | Search range 2–5 |
| `q(k)` | Fix MA order | Uses `k` exactly |
| `q(min,max)` | Search MA order range | Searches `min` through `max` |

Any range (min,max) triggers full `auto_arima` search. If all orders are fixed,  
the formula interface automatically calls the faster `arima` routine.

* * *

## 3. Seasonal Orders

Seasonal counterparts include `P`, `D`, and `Q`:

```julia
@formula(sales = p() + d() + q() + P() + Q())

```

| Function | Meaning | Default or form |
| --- | --- | --- |
| `P()` | Seasonal AR order | Search range 1–2 |
| `P(k)` | Fix seasonal AR order | Uses `k` exactly |
| `P(min,max)` | Search seasonal AR order range | Searches `min` through `max` |
| `D()` | Seasonal differencing (auto) | `auto_arima` chooses |
| `D(k)` | Fix seasonal differencing order | Uses `k` exactly |
| `Q()` | Seasonal MA order | Search range 1–2 |
| `Q(k)` | Fix seasonal MA order | Uses `k` exactly |
| `Q(min,max)` | Search seasonal MA order range | Searches `min` through `max` |

Remember to provide the seasonal period `m` when fitting (`fit(spec, data, m=12)`).

* * *

## 4. Exogenous Regressors

### 4.1 Explicit Variables

Add predictors by listing column names:

```julia
@formula(sales = p() + q() + price + promotion)

```

These become `VarTerm`s—during fitting Durbyn pulls the matching columns from your data.

### 4.2 Automatic Selection (`auto()`)

Use `auto()` to include _all_ numeric columns except the target, group columns, and  
optional date column. Examples:

```julia
@formula(sales = auto()) # pure auto ARIMA + automatic xregs
@formula(sales = p() + q() + auto()) # combine with explicit ARIMA orders

```

Automatic selection is mutually exclusive with explicit exogenous variables or  
`xreg_formula`.

* * *

## 5. Complex Designs (`xreg_formula`)

For interactions or transformations, supply a secondary formula when constructing  
`ArimaSpec`:

```julia
spec = ArimaSpec(
    @formula(sales = p() + q()),
    xreg_formula = Formula("~ temperature * promotion + price^2")
)

```

The `xreg_formula` is evaluated via `Utils.model_matrix`, producing the necessary  
design matrix before fitting.

* * *

## 6. Putting It Together

```julia
spec = ArimaSpec(
    @formula(sales = p(0,3) + d() + q(0,3) + P() + Q() + auto()),
    m = 12,
    stepwise = false # passthrough option to auto_arima
)
fitted = fit(spec, panel_data; groupby = [:store], datecol = :date)

```

Key points:

- Any range triggers automatic model selection.
- Fixed orders call fast direct estimation.
- Exogenous support includes explicit columns, `auto()`, or complex formulas.
- Combine with `PanelData` to store group/date metadata cleanly.

This grammar provides a declarative, composable way to describe ARIMA/SARIMA models  
without manual tuning loops.

* * *

## 7. End-to-End Example (Retail Panel)

```julia
using CSV
using Downloads
using Tables
using Durbyn
using Durbyn.TableOps

# Download and reshape data
local_path = Downloads.download(
    "https://raw.githubusercontent.com/Akai01/example-time-series-datasets/refs/heads/main/Data/retail.csv"
)
retail = CSV.File(local_path)
tbl = Tables.columntable(retail)

glimpse(tbl) # Column overview

# Convert to long format
tbl_long = pivot_longer(tbl; id_cols = :date, names_to = :series, values_to = :value)
glimpse(tbl_long)

# Wrap in PanelData with group/date metadata, A simple struc for meta data, still a Table 
panel_tbl = PanelData(tbl_long; groupby = :series, date = :date, m = 12)
glimpse(panel_tbl)

# Auto ARIMA with automatic xreg selection
spec = ArimaSpec(@formula(value = auto()))
# spec = ArimaSpec(@formula(value = p() + d() + q() + Q() + D() + Q() )) # Auto ARIMA
# spec = ArimaSpec(@formula(value = p(1)) # ARIMA(1,0,0)(0,0,0)[m]
fitted = fit(spec, panel_tbl)

# Inspect fitted models
glimpse(fitted)

# Forecast 12 steps ahead for every series
fc = forecast(fitted, h = 12)

# Inspect Forecast result
glimpse(fc)

# Forecast Table
fc_tbl = forecast_table(fc)
glimpse(fc_tbl)

```

---

<div class="post-metadata">

**Author:** ![Snowy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/snowy/32/36765_2.png) [@Snowy](https://discourse.julialang.org/u/Snowy)\
**Post date:** [October 23, 2025, 9:55pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/52 "2025-10-23T21:55:17Z")

</div>

This is great. When do you plan on registering the package? Or, when will it be stable enough to use in production?

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [October 24, 2025, 7:42am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/53 "2025-10-24T07:42:38Z")

</div>

I plan to register the package in the **first quarter of 2026**.

The low-level base models, such as `arima()`, `auto_arima()`, and `ets()` are now stable from an API perspective and will not undergo any breaking changes. I’ll continue to refactor and optimize their internals, but the external interfaces will remain consistent.

At the moment, I’m introducing a **formula interface grammar** and building **parallelization capabilities** to support large-scale forecasting problems efficiently.

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [October 28, 2025, 9:06pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/54 "2025-10-28T21:06:02Z")

</div>

Most of the time, we fit multiple models simultaneously. For such cases, we add an additional layer that allows specifying and training several model configurations at once:

```julia

# Fit multiple model specifications at once
models = model(
    ArimaSpec(@formula(sales = p() + q())),
    EtsSpec(e("A"), t("A"), s("A")),
    ArimaSpec(@formula(sales = p(2) + d(1) + q(2))),
    names = ["auto_arima", "ets_aaa", "arima_212"]
)

# Fit all models
fitted = fit(models, data, m = 12)

# Forecast with all models
fc = forecast(fitted, h = 12)

```

Hence, the code will not be pushed to GitHub this week, as we are incorporating this additional layer and ensuring proper integration before committing.

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [November 5, 2025, 8:43am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/55 "2025-11-05T08:43:12Z")

</div>

Durbyn.jl is ready with grammar of forecasting, parallelization and panel data interface.

> **[Grammar · Durbyn.jl](https://taf-society.github.io/Durbyn.jl/dev/grammar/)**
>
> Documentation for Durbyn.jl.

Please give a feedback if you encountered any problems.

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [November 18, 2025, 10:00am UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/56 "2025-11-18T10:00:08Z")

</div>

# New model introduced in Durbyn.jl.

## BATS:

The **BATS** framework extends exponential smoothing to accommodate multiple, possibly long seasonal cycles together with Box–Cox variance stabilization and ARMA error correction which was introduced by De Livera, Hyndman & Snyder (2011) as part of the innovation-state-space family and is now in Durbyn.jl

See the Docs: [BATS · Durbyn.jl](https://taf-society.github.io/Durbyn.jl/dev/bats/)

TBATS will soon be there too

---

<div class="post-metadata">

**Author:** ![Aoxo\_MoxoA](https://avatars.discourse-cdn.com/v4/letter/a/3d9bf3/32.png) [@Aoxo\_MoxoA](https://discourse.julialang.org/u/Aoxo_MoxoA)\
**Post date:** [November 21, 2025, 3:41pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/57 "2025-11-21T15:41:37Z")

</div>

## 🚀 Speedruns, Robustness, and the _Curious Case_ of Nelder-Mead (An Analysis Inspired by Durbyn.jl)

Hello Julia Community,

I recently stumbled upon the interesting **Durbyn.jl** repository, and the discussion there regarding the choice of optimization backend sparked the idea for a little **whimsical investigation**. We used **NonlinearOptimizationTestFunctions.jl** to put three different Nelder-Mead (NM) implementations through a **speedrun** and a **robustness check**. The result reveals a fascinating conflict between speed and thoroughness that directly illuminates the design decisions behind Durbyn.jl!

Our three competitors were:

1. **Durbyn’s NM:** Our simple, rudimentary implementation, which mirrors the core **Durbyn.jl** solver.
2. **Optim.jl:** The standard `NelderMead` method.
3. **NLopt:** The robust `LN_NELDERMEAD` method.

* * *

### Our Setup: The Projection-Penalty Trick

To test NM solvers on **constrained functions** (those with bounds), we wrapped the objective function f(x) with a combined **Projection and Penalty Wrapper**.

This trick forces the optimizer to remain in the feasible region, while the underlying function is always evaluated at a safe, projected point.

f\_{\text{wrapped}}(x) = f(\text{clip}(x, l, u)) + \lambda \cdot \| \text{Violation} \|\_2

* * *

## The Results: Fast Failures vs. Slow Perfection

The data shows a wild rollercoaster ride between speed (function calls) and reliability (robustness).

### 1. Overall Robustness (Who Solves Problems At All?)

First, the overview: How often did the algorithm find the target minimum (|\text{Result} - \text{Target}| \le 10^{-6})?

| Method | Best (Count) | Worst (Count) | Overall Avg. Calls |
| --- | --- | --- | --- |
| **Durbyn’s NM** | 27 | **170** | 1425.6 |
| **Optim.jl** | 157 | 13 | 3809.9 |
| **NLopt** | **180** | **3** | 1555.9 |

- **Conclusion:**  **NLopt** is the undisputed **robustness champion** (180 Best results). **Durbyn’s NM** is catastrophic for general problems (170 Worst results), showing the limits of its simple stopping criterion on complex functions.

### 2. The _Speedrun_ Test: Efficiency on Equal Footing

Since Durbyn’s NM fails so often, the average value of 1425 calls is misleading. We must measure speed only for the **19 easy functions** where **all three solvers successfully converged**. This is the fair comparison!

| Method | Avg. Calls (Only **19** Common Successes) | Key Behavior |
| --- | --- | --- |
| **Durbyn’s NM** | **6.1** | **The Speedrun Champion.** Stops as soon as it touches the minimum. |
| **Optim.jl** | 47.0 | Professional Standard: Efficient and prudent. |
| **NLopt** | **4054.5** | **The Pedant.** Finds the solution, then spends 4,000 calls _confirming_ it’s absolutely right. |

### The Whimsical Observation & Durbyn.jl Validation

This bizarre contrast—a **664x speed difference** when solving the exact same easy problems—is almost entirely due to **convergence criteria** :

- **Durbyn’s NM:** Achieves extreme speed by using an extremely **loose stop criterion**. Great for speedruns, but risky for general use.
- **NLopt:** Its robustness comes with an **efficiency tax**. The algorithm is excessively thorough, consuming thousands of calls to _rigorously_ confirm convergence to the last decimal place.

This validates the Durbyn.jl team’s design decision: For the specific, likely well-behaved objective functions in time series, prioritizing **maximum speed** (an average of \approx 6 calls!) is a clever, domain-specific optimization, accepting that general robustness is sacrificed.

* * *

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [November 21, 2025, 5:08pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/58 "2025-11-21T17:08:20Z")

</div>

Thank you for this very nice and insightful analysis, truly appreciated. It was great to see such a thorough comparison, and we’re grateful you took the time to benchmark the different Nelder-Mead implementations.

As we’ve mentioned before, the Durbyn.jl Nelder–Mead solver was never intended to compete with **Optim.jl** or **NLopt**. It is not a general-purpose optimizer; it was designed specifically for the particular time-series likelihood problems that Durbyn.jl targets. The package is still under heavy development, and the solver itself is intentionally minimalistic.

I would also encouragge the Julia community to try out Durbyn.jl and share feedback. Benchmarks like yours are extremely valuable to us, and we really appreciate the effort that wentt into this ones.

If possible, I would kindly ask whether you could also test the ETS or ARIMA model estimations tasks, simply by replacing the Durbyn.jl solver with **Optim.jl** and **NLopt** , and share your results. That would offer very helpful insights into how these established optimizers perform on the actual use cases Durbyn.jl is built for.

Thanks again for the excellent analysis and for sparking such a constructive discussion!

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [November 25, 2025, 1:36pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/59 "2025-11-25T13:36:58Z")

</div>

# TBATS added to Durbyn.jl

**Durbyn.jl** now includes **TBATS** models, enabling forecasting with complex seasonality: multiple seasonal periods, non-integer periods, Fourier-based seasonality, Box-Cox transforms, and ARMA errors.

If you work with high-frequency or multi-seasonal data (call centers, energy load, traffic, etc.), TBATS is now available in Durbyn.jl.

Docs: _[TBATS · Durbyn.jl](https://taf-society.github.io/Durbyn.jl/dev/tbats/)_

> ⚠ **PERFORMANCE NOTICE** : TBATS is currently **not optimized** and will run significantly slower than expected. This is a known limitation under active development. Optimization improvements are planned for future releases. Please do not report performance-related issues at this time.

---

<div class="post-metadata">

**Author:** ![Resul.Akay](https://avatars.discourse-cdn.com/v4/letter/r/b782af/32.png) [@Resul.Akay](https://discourse.julialang.org/u/Resul.Akay)\
**Post date:** [November 26, 2025, 2:21pm UTC](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544/60 "2025-11-26T14:21:55Z")

</div>

BATS now has grammar interface:

```julia
using Durbyn
using Durbyn.ModelSpecs

# Create sample data
data = (sales = randn(120) .+ 10,)

# Basic BATS with defaults (automatic component selection)
spec = BatsSpec(@formula(sales = bats()))
fitted = fit(spec, data)
fc = forecast(fitted, h = 12)

# BATS with monthly seasonality
spec = BatsSpec(@formula(sales = bats(seasonal_periods=12)))
fitted = fit(spec, data)
fc = forecast(fitted, h = 12)

# BATS with multiple seasonal periods (e.g., hourly data with daily and weekly)
spec = BatsSpec(@formula(sales = bats(seasonal_periods=[24, 168])))
fitted = fit(spec, data)
fc = forecast(fitted, h = 12)

# BATS with specific component selection
spec = BatsSpec(@formula(sales = bats(
    seasonal_periods=12,
    use_box_cox=true,
    use_trend=true,
    use_damped_trend=false,
    use_arma_errors=true
)))
fitted = fit(spec, data)
fc = forecast(fitted, h = 12)

# Additional options at fit time
fitted = fit(spec, data, bc_lower=0.0, bc_upper=1.5, biasadj=true)

```

[Previous page](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544.md?page=2)

[Next page](https://discourse.julialang.org/t/ann-durbyn-jl-time-series-forecasting-in-julia/132544.md?page=4)
