StockSharp/StockSharp · error · ArgumentException

Indicator cannot be composite.

Error message

Indicator cannot be composite.

What it means

ValidateIndicators() is called by the multi-indicator Bind overloads (2 through 8 indicators). It rejects any indicator that implements IComplexIndicator (a composite indicator with multiple result outputs) because the decimal extraction logic val.ToDecimal(indicator.Source) assumes a single-result indicator. Composite indicators produce multiple result values that cannot be mapped to a single decimal, so binding them through this path would produce incorrect data.

Source

Thrown at Algo.Strategies/Legacy/StrategyOld_HighLevel.cs:662

				iv1.ToDecimal(indicator1.Source),
				iv2.ToDecimal(indicator2.Source),
				iv3.ToDecimal(indicator3.Source),
				iv4.ToDecimal(indicator4.Source),
				iv5.ToDecimal(indicator5.Source),
				iv6.ToDecimal(indicator6.Source),
				iv7.ToDecimal(indicator7.Source),
				iv8.ToDecimal(indicator8.Source)), false);
		}

		private static void ValidateIndicators(params IIndicator[] indicators)
		{
			foreach (var ind in indicators)
			{
				if (ind is null)
					throw new ArgumentNullException(nameof(indicators));

				if (ind is IComplexIndicator)
					throw new ArgumentException(LocalizedStrings.IndicatorNotComposite, nameof(indicators));
			}
		}

		public ISubscriptionHandler<T> Bind(IIndicator[] indicators, Action<T, decimal[]> callback)
		{
			if (callback is null)
				throw new ArgumentNullException(nameof(callback));

			if (indicators is null)
				throw new ArgumentNullException(nameof(indicators));

			if (indicators.Any(i => i is IComplexIndicator))
				throw new ArgumentException(LocalizedStrings.IndicatorNotComposite, nameof(indicators));

			return BindEx(indicators, (v, ivs) => callback(v, [.. ivs.Select((val, idx) => val.ToDecimal(indicators[idx].Source))]), false);
		}

		public ISubscriptionHandler<T> BindWithEmpty(IIndicator[] indicators, Action<T, decimal?[]> callback)

View on GitHub (pinned to 601a191de6)

Solutions

  1. Replace composite indicators with their individual simple sub-indicators (e.g., use the MACD's SignalLine or Histogram component directly rather than the MACD container).
  2. For composite indicators, use BindEx with IIndicatorValue[] callbacks instead of Bind with decimal[] callbacks, which handles multi-output values.
  3. Check indicator is not IComplexIndicator before passing to Bind overloads that validate.

Example fix

// before
handler.Bind(new[] { sma, macd }, (msg, vals) => { ... });
// macd is IComplexIndicator -> throws

// after
handler.Bind(new[] { sma, macd.SignalLine }, (msg, vals) => { ... });
// or use BindEx:
handler.BindEx(new[] { sma, macd }, (msg, ivs) => { ... }, false);
Defensive patterns

Strategy: validation

Validate before calling

foreach (var ind in indicators)
{
    if (ind is IComplexIndicator)
        throw new InvalidOperationException($"{ind.GetType().Name} is composite; use BindEx or sub-indicators.");
}

Type guard

static bool IsSimpleIndicator(IIndicator ind) => ind is not IComplexIndicator;

Prevention

When it happens

Trigger: Passing a composite indicator (e.g., one implementing IComplexIndicator like Macd or any multi-output indicator) to a Bind overload that calls ValidateIndicators.

Common situations: Using a MACD, Band, or other multi-output indicator in a multi-indicator Bind call. Refactoring a single-output indicator into a composite without updating the binding code. Misidentifying an indicator as simple when it actually implements IComplexIndicator.

Related errors


AI-assisted analysis of StockSharp/StockSharp@601a191de6 (2026-08-13). Data as JSON: /api/errors/c6a2c29a5ce649e3. Report an issue: GitHub.