/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using NUnit.Framework;
using QuantConnect.Algorithm;
using QuantConnect.Brokerages.Backtesting;
using QuantConnect.Data.Market;
using QuantConnect.Lean.Engine;
using QuantConnect.Lean.Engine.TransactionHandlers;
using QuantConnect.Tests.Engine.DataFeeds;
namespace QuantConnect.Tests.Engine
{
///
/// Tests the ProcessSplitSymbols method directly via reflection to ensure
/// it properly skips processing during warmup in live mode.
///
[TestFixture]
public class ProcessSplitSymbolsDuringWarmupTests
{
private QCAlgorithm _algorithm;
private AlgorithmManager _algorithmManager;
private BrokerageTransactionHandler _transactionHandler;
private TestResultHandler _resultHandler;
private BacktestingBrokerage _brokerage;
private MethodInfo _processSplitSymbolsMethod;
[SetUp]
public void SetUp()
{
// Create algorithm instance
_algorithm = new QCAlgorithm();
// Initialize data manager
_algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(_algorithm));
_algorithm.SetDateTime(new DateTime(2025, 10, 10, 19, 0, 0));
// Add equity with market price
var spy = _algorithm.AddEquity("SPY", Resolution.Daily);
spy.SetMarketPrice(new Tick { Value = 100m, Symbol = spy.Symbol, Time = _algorithm.Time });
// Initialize transaction components
_transactionHandler = new BrokerageTransactionHandler();
_resultHandler = new TestResultHandler();
_brokerage = new BacktestingBrokerage(_algorithm);
_transactionHandler.Initialize(_algorithm, _brokerage, _resultHandler);
_algorithm.Transactions.SetOrderProcessor(_transactionHandler);
// Create AlgorithmManager and get ProcessSplitSymbols method via reflection
_algorithmManager = new AlgorithmManager(false);
_processSplitSymbolsMethod = typeof(AlgorithmManager).GetMethod(
"ProcessSplitSymbols",
BindingFlags.NonPublic | BindingFlags.Instance
);
Assert.IsNotNull(_processSplitSymbolsMethod, "ProcessSplitSymbols method should be found via reflection");
}
[TearDown]
public void TearDown()
{
_transactionHandler?.Exit();
_brokerage?.Dispose();
_resultHandler?.Exit();
}
[TestCase(false, false, true)]
[TestCase(true, false, true)]
[TestCase(false, true, true)]
[TestCase(true, true, true)]
[TestCase(false, false, false)]
[TestCase(true, false, false)]
[TestCase(false, true, false)]
[TestCase(true, true, false)]
public void ProcessSplitSymbolsDoesNotThrow(bool liveMode, bool isWarmingUp, bool hasHoldings)
{
_algorithm.SetLiveMode(liveMode);
if (!isWarmingUp)
{
_algorithm.SetFinishedWarmingUp();
}
Assert.AreEqual(isWarmingUp, _algorithm.IsWarmingUp, $"Algorithm should be warming up: {isWarmingUp}");
var splitWarnings = new List
{
new Split(
Symbols.SPY,
_algorithm.Time,
100m,
0.5m,
SplitType.Warning
)
};
if (hasHoldings)
{
_algorithm.Securities[Symbols.SPY].Holdings.SetHoldings(350, 100);
}
Assert.DoesNotThrow(() =>
{
_processSplitSymbolsMethod.Invoke(
_algorithmManager,
new object[] { _algorithm, splitWarnings, new List() }
);
});
Assert.AreEqual(0, splitWarnings.Count, "Split warning should be removed");
}
}
}