Expected Behavior
AutoRegressiveIntegratedMovingAverage fits any order set its constructor accepts.
Actual Behavior
Any order set with arOrder > maOrder throws IndexOutOfRangeException on the bar that
fills the window. ARIMA(2, 0, 1) is the smallest. At period 50, 24 of the 80 accepted order
sets throw.
MovingAverageStep walks the lagged errors and indexes the AR lags with the same counter:
var laggedErrors = LaggedSeries(_maOrder, _residuals.ToArray());
for (var i = 0; i < laggedErrors.Length; i++)
{
var doubles = lags[i].ToList();
doubles.AddRange(laggedErrors[i]);
lags[i] is the row for time i + _arOrder and laggedErrors[j] the row for j + _maOrder,
so the counters agree only when the orders do. lags holds data.Length - _arOrder rows and
laggedErrors holds data.Length - _maOrder, so _arOrder > _maOrder runs off the end.
The other direction does not throw. It pairs an AR row from one bar with error terms from
another, and the model is fitted on rows that never coexisted.
Potential Solution
Walk time rather than a row index, t from Math.Max(_arOrder, _maOrder) to
data.Length - 1, reading lags[t - _arOrder] and laggedErrors[t - _maOrder], with the
target vector and the residual loop starting at the same offset.
Separately, the two catch blocks added for #8039 read the row width off row zero,
lags.ToArray()[0].Length and appendedData.ToArray()[0].Length, so when the fit fails
because there are no rows the handler throws instead of substituting zeros. Both widths are
known from the orders.
Reproducing the Problem
var arima = new AutoRegressiveIntegratedMovingAverage(2, 0, 1, 50, true);
var reference = new DateTime(2020, 1, 1);
for (var i = 0; i < 60; i++)
{
arima.Update(reference.AddDays(i), 100m + (decimal)Math.Sin(i / 3d) * 5m);
}
// System.IndexOutOfRangeException on the 50th update
Every test in AutoregressiveIntegratedMovingAverageTests uses
new AutoRegressiveIntegratedMovingAverage("ARIMA", 1, 0, 1, 50), the diagonal where the two
orders match and the loop bound is accidentally right.
System Information
master at d865a40.
Checklist
Expected Behavior
AutoRegressiveIntegratedMovingAveragefits any order set its constructor accepts.Actual Behavior
Any order set with
arOrder > maOrderthrowsIndexOutOfRangeExceptionon the bar thatfills the window.
ARIMA(2, 0, 1)is the smallest. At period 50, 24 of the 80 accepted ordersets throw.
MovingAverageStepwalks the lagged errors and indexes the AR lags with the same counter:lags[i]is the row for timei + _arOrderandlaggedErrors[j]the row forj + _maOrder,so the counters agree only when the orders do.
lagsholdsdata.Length - _arOrderrows andlaggedErrorsholdsdata.Length - _maOrder, so_arOrder > _maOrderruns off the end.The other direction does not throw. It pairs an AR row from one bar with error terms from
another, and the model is fitted on rows that never coexisted.
Potential Solution
Walk time rather than a row index,
tfromMath.Max(_arOrder, _maOrder)todata.Length - 1, readinglags[t - _arOrder]andlaggedErrors[t - _maOrder], with thetarget vector and the residual loop starting at the same offset.
Separately, the two
catchblocks added for #8039 read the row width off row zero,lags.ToArray()[0].LengthandappendedData.ToArray()[0].Length, so when the fit failsbecause there are no rows the handler throws instead of substituting zeros. Both widths are
known from the orders.
Reproducing the Problem
Every test in
AutoregressiveIntegratedMovingAverageTestsusesnew AutoRegressiveIntegratedMovingAverage("ARIMA", 1, 0, 1, 50), the diagonal where the twoorders match and the loop bound is accidentally right.
System Information
master at d865a40.
Checklist
masterbranch