QuantConnect/Lean · error · RegressionTestException

Fee rate should be 0.0025, but was {feeRate}

Error message

Fee rate should be 0.0025, but was {feeRate}

What it means

Asserts _spy.ShortableProvider.FeeRate returns exactly 0.0025m at end-of-algorithm Time. The custom CustomSPYShortableProvider returns a constant 0.0025m; a different value means the custom provider is not the one installed (the default provider answered instead).

Source

Thrown at Algorithm.CSharp/CustomShortableProviderRegressionAlgorithm.cs:68

            }
        }

        public override void OnEndOfAlgorithm()
        {
            var transactions = Transactions.OrdersCount;
            if (transactions != 1)
            {
                throw new RegressionTestException($"Algorithm should have just 1 order, but was {transactions}");
            }
            var orderQuantity = Transactions.GetOrderById(_orderId).Quantity;
            if (orderQuantity != -1001)
            {
                throw new RegressionTestException($"Quantity of order {_orderId} should be -1001, but was {orderQuantity}");
            }
            var feeRate = _spy.ShortableProvider.FeeRate(_spy.Symbol, Time);
            if (feeRate != 0.0025m)
            {
                throw new RegressionTestException($"Fee rate should be 0.0025, but was {feeRate}");
            }
            var rebateRate = _spy.ShortableProvider.RebateRate(_spy.Symbol, Time);
            if (rebateRate != 0.0507m)
            {
                throw new RegressionTestException($"Fee rate should be 0.0507, but was {rebateRate}");
            }
        }

        private class CustomSPYShortableProvider : IShortableProvider
        {
            public decimal FeeRate(Symbol symbol, DateTime localTime) => 0.0025m;

            public decimal RebateRate(Symbol symbol, DateTime localTime) => 0.0507m;

            public long? ShortableQuantity(Symbol symbol, DateTime localTime)
            {
                if (localTime < new DateTime(2013, 10, 4, 16, 0, 0))
                {

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Call _spy.SetShortableProvider(new CustomSPYShortableProvider()) AFTER SetBrokerageModel.
  2. Ensure _spy is the stored Security from AddEquity, not a recomputed reference.
  3. Verify CustomSPYShortableProvider.FeeRate returns 0.0025m (constant) and is not shadowed by an interface default.
  4. Re-assert the provider type at OnEndOfAlgorithm to detect silent overwrites.

Example fix

// before: brokerage overwrites the shortable provider
_spy.SetShortableProvider(new CustomSPYShortableProvider());
SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage);

// after: install custom provider after brokerage defaults
SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage);
_spy.SetShortableProvider(new CustomSPYShortableProvider());
Defensive patterns

Strategy: validation

Validate before calling

// Assert the custom provider is installed before reading rates
if (!(_spy.ShortableProvider is CustomSPYShortableProvider))
    throw new InvalidOperationException("Custom shortable provider not installed");
var fee = _spy.ShortableProvider.FeeRate(_spy.Symbol, Time);

Type guard

bool HasCustomShortableProvider(Security s) => s.ShortableProvider is CustomSPYShortableProvider;

Prevention

When it happens

Trigger: Calling FeeRate on _spy.ShortableProvider and getting a non-0.0025 value, indicating SetShortableProvider did not persist or was overwritten.

Common situations: SetShortableProvider called before SetBrokerageModel so the brokerage overwrote it; provider set on a different Security reference; or the brokerage model's default shortable provider took precedence.

Related errors


AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13). Data as JSON: /api/errors/810363425b5c1852. Report an issue: GitHub.