Systemicalpha

Conditional Mean

systemic:core-cmeanMathfunction1 cr

Inputs

NameTypeDescription
WindowintegerEnter a constant nonnegative whole number explicitly. **0** uses all usable pairs so far within the supplied history. **N > 0** uses the latest N usable pairs and requires N pairs before producing a result.
ConditionbooleanarrayConnect a true/false rule. True selects the paired value; false consumes a window position without entering the average. Null or NaN excludes the pair from the window.
ValuesfloatarrayConnect the numeric series to average, such as returns or trading volume. Each value pairs with Condition at the same aligned timestamp, and its unit becomes the output's unit.

Outputs

NameTypeDescription
Conditional MeanfloatarrayThe average of Values selected by true conditions in the chosen window, in the same unit as Values. Historical output follows the aligned input positions; live output contains only the newest reading.

Does a market behave differently on the days you care about? Conditional Mean lets you ask that question of a numeric series. Give it Values, a true/false Condition, and a Window. It averages only the values whose condition is true. You can compare average trading volume on down days with volume on up days, or study returns in different volatility regimes.

The result describes the observations selected by your rule. It does not establish that the rule caused them, and a difference between two averages is not a forecast.

What is averaged?

For the usable paired bars in the selected window (W_t), the calculation is

CMean⁡t=∑i∈WtXi 1(Ci=true)∑i∈Wt1(Ci=true).\operatorname{CMean}_t = \frac{\sum_{i\in W_t} X_i\,\mathbf{1}(C_i=\mathrm{true})} {\sum_{i\in W_t}\mathbf{1}(C_i=\mathrm{true})}.

Here (X_i) is a numeric value and (C_i) is its condition on the same bar. The indicator (\mathbf{1}(C_i=\mathrm{true})) is 1 for true and 0 for false. In plain language: add the selected values, then divide by the number of selected values. A false condition keeps its bar in the window but contributes neither a value nor a count to the average. A selected numeric zero does contribute to the count. If the denominator is zero, the answer is null, because there is no selected value to average.

This is a sample average of observations meeting a rule. It is not a volume-weighted average: if Values is volume, each selected bar's volume is one value in the average. It is also different from replacing every unselected value with zero, which would lower the result by dividing by all bars.

See the selection happen

This small arithmetic example is illustrative, not market data. All six value/condition pairs are usable.

BarValueConditionExpanding meanWindow = 3
11true1null
22false1null
33true22
44false23
55true34
66true3.755.5

At bar 6, fill the window first, then select true rows:

flowchart LR
    A["At bar 6: six usable pairs"] --> B["Window 3 takes bars 4–6"]
    B --> C["Select true: bars 5 and 6"]
    C --> D["Mean: (5 + 6) / 2 = 5.5"]
    A --> E["Window 0 takes bars 1–6"]
    E --> F["Select true: bars 1, 3, 5, and 6"]
    F --> G["Mean: (1 + 3 + 5 + 6) / 4 = 3.75"]

Choose the history you mean

Enter Window explicitly when connecting the module.

WindowHistory consideredFirst possible reading
0Every usable pair so farThe first pair with a true condition
1Only the current usable pairIts value if true; null if false
N > 1The most recent N usable pairsAfter N usable pairs, if at least one is true

The supplied history is bounded. Window 0 cannot include observations that are no longer supplied, and a rolling window needs enough usable pairs within that history.

The window is filled before false conditions are filtered. In the arithmetic table above, the three-pair window at bar 4 holds bars 2, 3 and 4. Their conditions are false, true and false, so the only selected value is 3. The true pair at bar 1 has already left the window. A full window with no true condition returns null.

A rolling window can therefore report null for two different reasons: it lacks enough usable pairs, or it has enough pairs but none passes the condition. A long expanding history is stable but can hide recent changes. A short rolling history reacts faster but may average only one or two selected bars. The output does not report that selected count, so inspect the condition alongside it before trusting a smooth-looking line.

Gaps, NaN and zero

Systemic distinguishes a null gap (no stored observation at a position) from NaN (an observation stored at a timestamp whose value is not numeric). That distinction matters when inspecting the source data. For this calculation, neither supplies a usable numeric pair. If either input is null or NaN at the current position, the output there is null; that position does not consume a place in the window. The next usable pair resumes the calculation using earlier usable pairs. A numeric zero remains a valid value, and a false condition remains a valid condition.

For example, with Window = 2 and true conditions throughout, Values of 10, NaN, 0, 30 produce null, null, 5, 15. The stored NaN at the second position has a timestamp but does not enter the mean. The zero at the third position does: ((10+0)/2=5). Replacing NaN with a null gap yields the same calculated series, although the underlying data events differ. A missing condition has the same exclusion effect for this calculation; it is not silently treated as false.

Connected series are aligned on a common timeline before this module sees them. A slower series may be carried forward across faster positions. Those repeated readings can create additional usable pairs, change which bars fill a rolling window, and change the mean. Check the connected frequencies and aligned values before comparing results across assets or timeframes.

Explore two market questions

1. Is activity different on falling days?

Connect an asset's daily trading volume to Values. Use Less Than (<) to compare its daily return with zero and connect that result to Condition. In a second Conditional Mean, use Greater Than (>) to select up days. A zero-return day belongs to neither group. Give both modules the same volume series and Window. Their windows cover the same dates only if both have the same usable-pair pattern; missing conditions can change that. The two groups may contain different numbers of selected bars, and a few unusually busy sessions can drive a difference in means.

This is a useful question because price changes and trading volume have a documented relationship, but it is not sensible to assume the same pattern or direction for every asset. Jonathan Karpoff's survey in the Journal of Financial and Quantitative Analysis reviews evidence on that relationship and its possible explanations. Plot the volume and condition as well as both means: are the selected days numerous enough, and does the comparison survive a different window or sample period? It can help describe activity around declines; it cannot, by itself, identify who traded or why.

2. How do returns look after a high-volatility reading?

Connect daily equity returns to Values. Connect Macro: Market Indicators, set to FRED Volatility Index (VIXCLS), to Lag → Series. Set Lag → Periods = 1, compare its Shifted output with a threshold using Greater Than (>), then connect that result to Condition. A second Conditional Mean can use a complementary low-VIX comparison on the same lagged series. Inspect the aligned dates before interpreting the comparison: the prior VIX reading must have been available before the return interval you are studying. Cboe's VIX methodology describes an estimate of expected 30-day U.S. equity-market volatility derived from S&P 500 option prices. VIX does not forecast the return's direction.

Compare the two means across several windows and sample periods, and inspect how often the high-VIX condition actually occurred. A threshold selected after seeing the results can make the comparison look stronger than it is. If you intend to use the reading for a trading decision, keep the condition on information that existed before the return interval begins and test it on later data. The mean is a description of past selected returns, not evidence that high VIX causes any particular future return.

Reading the output

The result has the same unit as Values: volume in shares if Values is share volume, percent if Values is a percent return. A null output is not zero. It can mean a missing input at this position, a rolling window still filling, or a full window with no true condition. In live execution, the module supplies the latest reading only; that reading can also be null.

The conditional mean is most useful beside the original Values series and the Condition series. Together they show what was selected and whether the average is being carried by many observations or only a few. If the selected condition is rare, consider a longer history and compare separate time periods before drawing a conclusion.

Rendering diagrams...
© 2026 WanoLabs. All rights reservedAlpha build v0.1.5