Skip to content

Run the reset contract over every indicator, not only the tested ones - #9729

Open
mkzung wants to merge 1 commit into
QuantConnect:masterfrom
mkzung:feature-9726-indicator-reset-contract-tests
Open

Run the reset contract over every indicator, not only the tested ones#9729
mkzung wants to merge 1 commit into
QuantConnect:masterfrom
mkzung:feature-9726-indicator-reset-contract-tests

Conversation

@mkzung

@mkzung mkzung commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Description

Tests/Indicators/IndicatorResetContractTests.cs, one new file. It constructs every indicator in the assembly by reflection, at three periods, and asserts two things: the same series replayed around a Reset() gives the same values and the same ready flag, and the indicator is back in its default state afterwards, using TestHelper.AssertIndicatorIsInDefaultState.

Related Issue

Closes #9726

Motivation and Context

CommonIndicatorTests<T> states eleven contracts and runs them only for an indicator with a test class deriving from it: 115 of the 202 concrete indicators. Six reset defects were merged this month out of that gap.

The case for it is not a bug count, since it is green on master. It is what happens when the six merged fixes are reverted, keeping the fixture:

Failed!  Failed: 21, Passed: 1121, Skipped: 70, Total: 1212
merged fix cases how it shows
#9686 advance decline watermark 12 IsReady differs at index 1, across the four indicators sharing the base
#9687 ConnorsRSI previous input 3 the value differs, first at index 4
#9688 SuperTrend previous close 1 the value differs at index 0, at period 1 only
#9694 MidPrice rolling extremes 2 the value differs at index 0, at periods 2 and 14
#9705 IntradayVwap running sums 3 IsReady true after the reset
#9706 NewHighsNewLows readiness 0 the fixture registers assets, so the untracked state never arises

Three notes on the shape, since each was a choice:

Three periods, because of #9688. SuperTrend assigned its previous close on the early return it takes while the average true range warms up, so at any period above one that return fires on the first update and the stale value never shows.

The price series never revisits a level. A repeating one caught two of the six, because a value carried across a reset is one the indicator meets again a few bars later anyway.

Anything unreachable is an Assert.Ignore carrying its reason, so the runner counts it and names it rather than passing over it. On master that is 70 cases over 18 indicators: 36 the fixture cannot construct, 18 that throw on the series, 16 where a constructor refuses that period and the ignore quotes the indicator's own message.

Two of the five that throw are worth a look on their own: AutoRegressiveIntegratedMovingAverage is #9714, and ChoppinessIndex at a period of one is #9724.

Requires Documentation Change

No.

How Has This Been Tested?

Passed!  Failed: 0, Passed: 1142, Skipped: 70, Total: 1212, Duration: 391 ms

on b0006b29a, plus the reverted-fix run above. The neighbouring fixtures are unaffected: IndicatorTests, ChoppinessIndexTests, MidPriceTests, SuperTrendTests, IntradayVwapTests, ConnorsRelativeStrengthIndexTests, AdvanceDeclineDifferenceTests and NewHighsNewLows together give 0 failed.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (non-breaking change which improves implementation)
  • Performance (non-breaking change which improves performance. Please add associated performance test and results)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Non-functional change (xml comments/documentation/etc)

Checklist:

  • My code follows the code style of this project.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My branch follows the naming convention bug-<issue#>-<description> or feature-<issue#>-<description>

CommonIndicatorTests states eleven contracts and runs them for the 115
indicators that have a test class deriving from it. The other 87 concrete
indicators in the assembly are never asked.

This fixture drives every one of them by reflection. It feeds a series,
resets, feeds the same series again, and asserts the values and the ready
flag match, then asserts the indicator is back in its default state using
TestHelper.AssertIndicatorIsInDefaultState.

Three periods rather than one, because a field can be assigned on a branch
only one period takes: a value written on the early return an indicator
makes while a sub-indicator warms up is overwritten on the first update
whenever that warm-up lasts more than one bar.

The series length follows the warm-up period, so an indicator with a long
one is compared over values it produced while ready rather than only over
its pre-ready value.

A type the fixture cannot construct, cannot feed, or that throws on the
series is reported with Assert.Ignore and the reason, so the runner counts
it and names it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The reset contract runs for 115 of the 202 indicators

1 participant