Refactor some unit and regression tests for speed improvements (#8970)
API Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled

* Reduce history unit tests duration

* Unit and regression tests speed improvements

* Minor change

* Fix unit test race condition
This commit is contained in:
Jhonathan Abreu
2025-09-12 10:15:09 -04:00
committed by GitHub
parent 5b465216f9
commit 5644520545
16 changed files with 219 additions and 144 deletions
@@ -33,10 +33,12 @@ class ConsolidateDifferentTickTypesRegressionAlgorithm(QCAlgorithm):
# Tick consolidators with max count
self.consolidate(TradeBar, equity.symbol, 10, TickType.TRADE, lambda trade_bar: self.on_trade_tick_max_count(trade_bar))
self._there_is_at_least_one_trade_bar = False
self.consolidate(QuoteBar, equity.symbol, 10, TickType.QUOTE, lambda quote_bar: self.on_quote_tick_max_count(quote_bar))
self._there_is_at_least_one_quote_bar = False
self._consolidation_count = 0
def on_trade_tick_max_count(self, trade_bar):
self._there_is_at_least_one_trade_bar = True
if type(trade_bar) != TradeBar:
@@ -47,6 +49,11 @@ class ConsolidateDifferentTickTypesRegressionAlgorithm(QCAlgorithm):
if type(quote_bar) != QuoteBar:
raise AssertionError(f"The type of the bar should be Quote, but was {type(quote_bar)}")
self._consolidation_count += 1
# Let's shortcut to reduce regression test duration: algorithms using tick data are too long
if self._consolidation_count >= 1000:
self.quit()
def on_quote_tick(self, tick):
self.there_is_at_least_one_quote_tick = True
if tick.tick_type != TickType.QUOTE:
@@ -63,7 +70,7 @@ class ConsolidateDifferentTickTypesRegressionAlgorithm(QCAlgorithm):
if not self.there_is_at_least_one_trade_tick:
raise AssertionError(f"There should have been at least one tick in OnTradeTick() method, but there wasn't")
if not self._there_is_at_least_one_trade_bar:
raise AssertionError("There should have been at least one bar in OnTradeTickMaxCount() method, but there wasn't")
@@ -19,15 +19,24 @@ from AlgorithmImports import *
class HistoryTickRegressionAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2013, 10, 11)
self.set_end_date(2013, 10, 11)
self.set_start_date(2013, 10, 12)
self.set_end_date(2013, 10, 13)
self._symbol = self.add_equity("SPY", Resolution.TICK).symbol
def on_end_of_algorithm(self):
history = list(self.history[Tick](self._symbol, timedelta(days=1), Resolution.TICK))
quotes = [x for x in history if x.tick_type == TickType.QUOTE]
trades = [x for x in history if x.tick_type == TickType.TRADE]
trades_count = 0
quotes_count = 0
for point in self.history[Tick](self._symbol, timedelta(days=1), Resolution.TICK):
if point.tick_type == TickType.TRADE:
trades_count += 1
elif point.tick_type == TickType.QUOTE:
quotes_count += 1
if not quotes or not trades:
if trades_count > 0 and quotes_count > 0:
# We already found at least one tick of each type, we can exit the loop
break
if trades_count == 0 or quotes_count == 0:
raise AssertionError("Expected to find at least one tick of each type (quote and trade)")
self.quit()
@@ -34,13 +34,17 @@ class PeriodBasedHistoryRequestNotAllowedWithTickResolutionRegressionAlgorithm(Q
"Tick history call with symbol array with explicit tick resolution")
history = self.history[Tick](spy, TimeSpan.from_hours(12))
if len(list(history)) == 0:
# Check whether history has data without enumerating the whole list
if not any(x for x in history):
raise AssertionError("On history call with implicit tick resolution: history returned no results")
history = self.history[Tick](spy, TimeSpan.from_hours(12), Resolution.TICK)
if len(list(history)) == 0:
if not any(x for x in history):
raise AssertionError("On history call with explicit tick resolution: history returned no results")
# We already tested what we wanted to test, we can quit now
self.quit()
def assert_that_history_throws_for_tick_resolution(self, history_call, history_call_description):
try:
history_call()
+1 -1
View File
@@ -23,7 +23,7 @@ class RegressionAlgorithm(QCAlgorithm):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
self.set_start_date(2013,10,7) #Set Start Date
self.set_end_date(2013,10,11) #Set End Date
self.set_end_date(2013,10,8) #Set End Date
self.set_cash(10000000) #Set Strategy Cash
# Find more symbols here: http://quantconnect.com/data
self.add_equity("SPY", Resolution.TICK)
+10 -3
View File
@@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from datetime import timedelta
from AlgorithmImports import *
# <summary>
@@ -31,14 +32,16 @@ class TickDataFilteringAlgorithm(QCAlgorithm):
#Add our custom data filter.
spy.set_data_filter(TickExchangeDataFilter(self))
self._order_time = None
# <summary>
# Data arriving here will now be filtered.
# </summary>
# <param name="data">Ticks data array</param>
def on_data(self, data):
if not data.contains_key("SPY"):
if not data.contains_key("SPY"):
return
spy_tick_list = data["SPY"]
# Ticks return a list of ticks this second
@@ -47,6 +50,10 @@ class TickDataFilteringAlgorithm(QCAlgorithm):
if not self.portfolio.invested:
self.set_holdings("SPY", 1)
self._order_time = self.time
# Let's shortcut to reduce regression test duration
elif self.time - self._order_time > timedelta(minutes=5):
self.quit()
# <summary>
# Exchange filter class
@@ -73,5 +80,5 @@ class TickExchangeDataFilter(SecurityDataFilter):
if isinstance(data, Tick):
if data.exchange == str(Exchange.ARCA):
return True
return False
@@ -30,16 +30,16 @@ class TickHistoryRequestWithoutTickSubscriptionRegressionAlgorithm(QCAlgorithm):
# Requesting history for SPY and IBM (separately) with tick resolution
spy_history = self.history[Tick](spy, timedelta(days=1), Resolution.TICK)
if len(list(spy_history)) == 0:
if not any(spy_history):
raise AssertionError("SPY tick history is empty")
ibm_history = self.history[Tick](ibm, timedelta(days=1), Resolution.TICK)
if len(list(ibm_history)) == 0:
if not any(ibm_history):
raise AssertionError("IBM tick history is empty")
# Requesting history for SPY and IBM (together) with tick resolution
spy_ibm_history = self.history[Tick]([spy, ibm], timedelta(days=1), Resolution.TICK)
if len(list(spy_ibm_history)) == 0:
if not any(spy_ibm_history):
raise AssertionError("Compound SPY and IBM tick history is empty")
self.quit()