{"record":{"id":"d833d1b29085195c","repo":"StockSharp/StockSharp","slug":"candlesseries-d833d1","errorCode":null,"errorMessage":"candlesSeries","messagePattern":"candlesSeries","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"Algo.Gpu/Indicators/GpuFiniteVolumeElementCalculator.cs","lineNumber":53,"sourceCode":"\t/// <summary>\n\t/// Initializes a new instance of the <see cref=\"GpuFiniteVolumeElementCalculator\"/> class.\n\t/// </summary>\n\t/// <param name=\"context\">ILGPU context.</param>\n\t/// <param name=\"accelerator\">ILGPU accelerator.</param>\n\tpublic GpuFiniteVolumeElementCalculator(Context context, Accelerator accelerator)\n\t\t: base(context, accelerator)\n\t{\n\t\t_kernel = Accelerator.LoadAutoGroupedStreamKernel<Index3D, ArrayView<GpuCandle>, ArrayView<GpuIndicatorResult>, ArrayView<int>, ArrayView<int>, ArrayView<GpuFiniteVolumeElementParams>>(FiniteVolumeElementKernel);\n\t}\n\n\t/// <inheritdoc />\n\tpublic override GpuIndicatorResult[][][] Calculate(GpuCandle[][] candlesSeries, GpuFiniteVolumeElementParams[] parameters)\n\t{\n\t\tArgumentNullException.ThrowIfNull(candlesSeries);\n\t\tArgumentNullException.ThrowIfNull(parameters);\n\n\t\tif (candlesSeries.Length == 0)\n\t\t\tthrow new ArgumentOutOfRangeException(nameof(candlesSeries));\n\n\t\tif (parameters.Length == 0)\n\t\t\tthrow new ArgumentOutOfRangeException(nameof(parameters));\n\n\t\tvar seriesCount = candlesSeries.Length;\n\n\t\tvar totalSize = 0;\n\t\tvar seriesOffsets = new int[seriesCount];\n\t\tvar seriesLengths = new int[seriesCount];\n\n\t\tfor (var s = 0; s < seriesCount; s++)\n\t\t{\n\t\t\tseriesOffsets[s] = totalSize;\n\t\t\tvar len = candlesSeries[s]?.Length ?? 0;\n\t\t\tseriesLengths[s] = len;\n\t\t\ttotalSize += len;\n\t\t}\n","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/StockSharp/StockSharp/blob/601a191de678bff83da28b14828f8885214ca71c/Algo.Gpu/Indicators/GpuFiniteVolumeElementCalculator.cs#L35-L71","documentation":"The Finite Volume Element (FVE) calculator computes a volume-weighted oscillator measuring the proportion of volume associated with upward versus downward price movement. Its Calculate method dispatches a 3DD ILGPU kernel over a series x parameters x candles grid, requiring a pre-computed totalSize (the flattened candle count across all sub-arrays) to size GPU memory buffers. An empty candlesSeries (outer Length == 0) keeps totalSize at 0, producing zero-length buffers and a degenerate kernel grid; ArgumentOutOfRangeException(nameof(candlesSeries)) fires at method entry to abort before any GPU allocation or dispatch.","triggerScenarios":"Calling Calculate with a GpuCandle[][] whose outer Length is 0 (e.g., calculator.Calculate(Array.Empty<GpuCandle[]>(), parameters)). Also triggered when a LINQ pipeline, API deserializer, or database query returns an empty collection that is forwarded to Calculate without checking the element count.","commonSituations":"Newly listed symbols with no historical candle data in the data store; a date-range filter that excludes all available candles (weekends, holidays, future dates); a backfill job that failed silently or has not completed; a REST API or database query returning zero rows forwarded without a count check; a test fixture that constructed the calculator but forgot to populate candle data.","solutions":["Guard the call site: check candlesSeries.Length > 0 before invoking Calculate and return an empty GpuIndicatorResult[][][] or log a warning instead of letting it throw.","Verify the upstream data provider (REST API, database, file cache) actually returned rows; log the series count at the data boundary.","If building the series from multiple sources or filters, ensure at least one sub-array with candles survives deduplication and date-range filtering.","For batch pipelines, skip the calculator for symbols flagged as having insufficient data rather than passing an empty array through."],"exampleFix":"// before -- throws ArgumentOutOfRangeException (ParamName: candlesSeries)\nvar results = calculator.Calculate(candlesSeries, parameters);\n\n// after -- guard before calling\nif (candlesSeries is null || candlesSeries.Length == 0)\n{\n    logger.LogWarning(\"GpuFiniteVolumeElementCalculator: no candle series, skipping\");\n    return Array.Empty<GpuIndicatorResult[][][]>();\n}\nvar results = calculator.Calculate(candlesSeries, parameters);","handlingStrategy":"validation","validationCode":"// Pre-call validation for GpuFiniteVolumeElementCalculator.Calculate\nif (candlesSeries is null || candlesSeries.Length == 0)\n{\n    logger.LogWarning(\"GpuFiniteVolumeElementCalculator: candle series is null or empty\");\n    return Array.Empty<GpuIndicatorResult[][][]>();\n}","typeGuard":"static bool HasCandleSeries(GpuCandle[][]? candlesSeries) =>\n    candlesSeries is { Length: > 0 };","tryCatchPattern":"GpuIndicatorResult[][][] results;\ntry\n{\n    results = calculator.Calculate(candlesSeries, parameters);\n}\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"candlesSeries\")\n{\n    logger.LogWarning(\"GpuFiniteVolumeElementCalculator: candle series was empty, returning empty results\");\n    results = Array.Empty<GpuIndicatorResult[][][]>();\n}","preventionTips":["Null- and empty-check every jagged array before passing it to a GPU calculator.","Log element counts at each data boundary (API, cache, file) to catch upstream gaps early.","Skip calculation for symbols flagged as having insufficient data instead of passing an empty array through.","Write edge-case unit tests that pass empty and single-element series to verify guard behavior."],"tags":["gpu","argument-validation","candle-data","ilgpu","finite-volume-element"],"backgroundTag":null,"analyzedSha":"601a191de678bff83da28b14828f8885214ca71c","analyzedAt":"2026-08-13T20:43:24.460Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}