Skip to main content

Rolling Windows

For Data Analysts

Rolling windows calculate metrics over a sliding time period, smoothing out daily fluctuations to reveal underlying trends. Olytix Core supports rolling sums, averages, and custom aggregations over configurable window sizes.

Understanding Rolling Windows

Rolling windows apply aggregations over a fixed-size window that moves forward through time:

┌─────────────────────────────────────────────────────────────────────┐
│ 7-Day Rolling Average Example │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Day 1 Day 2 Day 3 Day 4 Day 5 Day 6 Day 7 Day 8 │
│ 100 120 90 110 130 95 105 115 │
│ │
│ ├───────────────── Window 1 ─────────────────┤ │
│ │ Avg: (100+120+90+110+130+95+105)/7 = 107 │ │
│ │
│ ├───────────────── Window 2 ─────────────────┤ │
│ │ Avg: (120+90+110+130+95+105+115)/7 = 109 │ │
│ │
│ As each day passes, the window slides forward, dropping the │
│ oldest value and including the newest. │
│ │
└─────────────────────────────────────────────────────────────────────┘

Built-in Rolling Windows

Olytix Core provides pre-configured rolling windows for common use cases:

FunctionWindow SizeUse Case
rolling_7d7 daysWeekly trends, smoothing daily noise
rolling_14d14 daysBi-weekly patterns
rolling_30d30 daysMonthly trends
rolling_90d90 daysQuarterly trends
rolling_365d365 daysAnnual trends, year-over-year smoothing

7-Day Rolling Window

Rolling Sum

Calculate 7-day rolling revenue:

# metrics/rolling.yml
metrics:
- name: revenue_rolling_7d
type: derived
expression: orders.total_revenue
description: "Sum of revenue over the past 7 days"
meta:
time_intelligence:
type: rolling_sum
window_size: 7
window_grain: day
time_dimension: orders.order_date

Rolling Average

Calculate 7-day rolling average:

metrics:
- name: revenue_rolling_7d_avg
type: derived
expression: orders.total_revenue
description: "Average daily revenue over the past 7 days"
meta:
time_intelligence:
type: rolling_avg
window_size: 7
window_grain: day
time_dimension: orders.order_date

Query Example

{
"metrics": ["revenue", "revenue_rolling_7d_avg"],
"dimensions": ["orders.order_date.day"],
"filters": [
{
"member": "orders.order_date",
"operator": "inDateRange",
"values": ["2024-03-01", "2024-03-31"]
}
]
}

Response:

{
"data": [
{
"orders.order_date.day": "2024-03-01",
"revenue": 5200.00,
"revenue_rolling_7d_avg": 4850.00
},
{
"orders.order_date.day": "2024-03-02",
"revenue": 4100.00,
"revenue_rolling_7d_avg": 4720.00
},
{
"orders.order_date.day": "2024-03-03",
"revenue": 6300.00,
"revenue_rolling_7d_avg": 4890.00
}
]
}

30-Day Rolling Window

Monthly Trend Analysis

metrics:
- name: revenue_rolling_30d
type: derived
expression: orders.total_revenue
description: "Sum of revenue over the past 30 days"
meta:
time_intelligence:
type: rolling_sum
window_size: 30
window_grain: day
time_dimension: orders.order_date

- name: revenue_rolling_30d_avg
type: derived
expression: orders.total_revenue
description: "Average daily revenue over the past 30 days"
meta:
time_intelligence:
type: rolling_avg
window_size: 30
window_grain: day
time_dimension: orders.order_date

- name: orders_rolling_30d_count
type: derived
expression: orders.order_count
description: "Number of orders over the past 30 days"
meta:
time_intelligence:
type: rolling_sum
window_size: 30
window_grain: day

Comparing Short and Long Windows

Analyze trends by comparing different window sizes:

metrics:
- name: revenue_7d_vs_30d_ratio
type: derived
expression: |
revenue_rolling_7d_avg / NULLIF(revenue_rolling_30d_avg, 0)
description: |
Ratio of 7-day average to 30-day average.
Values > 1 indicate recent acceleration.
Values < 1 indicate recent deceleration.
format: "decimal"

Custom Window Sizes

Configuring Custom Windows

Define any window size for your analysis:

metrics:
# 14-day window
- name: revenue_rolling_14d
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_sum
window_size: 14
window_grain: day

# 90-day window
- name: revenue_rolling_90d
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_sum
window_size: 90
window_grain: day

# 52-week window (annual)
- name: revenue_rolling_52w
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_sum
window_size: 52
window_grain: week

Window Grain Options

Specify the unit of the window:

GrainDescriptionExample
dayDaily granularity7-day, 30-day windows
weekWeekly granularity4-week, 13-week windows
monthMonthly granularity3-month, 12-month windows
metrics:
# 4-week rolling average (weekly granularity)
- name: revenue_rolling_4w
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_avg
window_size: 4
window_grain: week

# 3-month rolling sum (monthly granularity)
- name: revenue_rolling_3m
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_sum
window_size: 3
window_grain: month

Rolling Window Aggregations

Available Aggregation Types

TypeFunctionUse Case
rolling_sumSUMTotal over window
rolling_avgAVGAverage over window
rolling_minMINMinimum in window
rolling_maxMAXMaximum in window
rolling_countCOUNTCount over window
moving_averageAVGAlias for rolling_avg

Example: Multiple Aggregations

metrics:
- name: revenue_rolling_7d_sum
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_sum
window_size: 7
window_grain: day

- name: revenue_rolling_7d_avg
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_avg
window_size: 7
window_grain: day

- name: revenue_rolling_7d_min
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_min
window_size: 7
window_grain: day

- name: revenue_rolling_7d_max
type: derived
expression: orders.total_revenue
meta:
time_intelligence:
type: rolling_max
window_size: 7
window_grain: day

Advanced Rolling Window Options

Include or Exclude Current Period

Control whether the current period is included in the window:

metrics:
# Include current day (default)
- name: revenue_rolling_7d_inclusive
meta:
time_intelligence:
type: rolling_sum
window_size: 7
include_current_period: true # Default

# Exclude current day (trailing window)
- name: revenue_trailing_7d
meta:
time_intelligence:
type: rolling_sum
window_size: 7
include_current_period: false

Offset Windows

Calculate windows with an offset from the current period:

metrics:
# 7-day sum, but from 8-14 days ago
- name: revenue_prior_week_rolling
meta:
time_intelligence:
type: rolling_sum
window_size: 7
window_grain: day
offset: 7 # Start 7 days before current

Handle Incomplete Windows

Configure behavior for periods where the full window is not available:

metrics:
- name: revenue_rolling_7d_strict
meta:
time_intelligence:
type: rolling_avg
window_size: 7
null_if_incomplete: true # Return NULL if < 7 days available

Partitioned Rolling Windows

Calculate rolling windows within segments:

metrics:
- name: revenue_rolling_7d_by_region
type: derived
expression: orders.total_revenue
description: "7-day rolling revenue calculated per region"
meta:
time_intelligence:
type: rolling_sum
window_size: 7
window_grain: day
partition_by:
- orders.region

Query result shows independent rolling calculations per region:

{
"data": [
{
"orders.region": "North America",
"orders.order_date.day": "2024-03-15",
"revenue_rolling_7d_by_region": 245000.00
},
{
"orders.region": "Europe",
"orders.order_date.day": "2024-03-15",
"revenue_rolling_7d_by_region": 178000.00
}
]
}

Cube-Level Rolling Measures

Define rolling calculations directly on cubes:

# cubes/orders.yml
cubes:
- name: orders
sql: "SELECT * FROM {{ ref('fct_orders') }}"

measures:
- name: total_revenue
type: sum
sql: order_amount

- name: order_count
type: count

- name: revenue_rolling_7d
type: number
sql: |
SUM(order_amount) OVER (
ORDER BY order_date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
)
description: "7-day rolling revenue sum"

- name: avg_order_value_rolling_30d
type: number
sql: |
AVG(order_amount) OVER (
ORDER BY order_date
ROWS BETWEEN 29 PRECEDING AND CURRENT ROW
)
description: "30-day rolling average order value"

dimensions:
- name: order_date
type: time
sql: order_date

Common Rolling Window Patterns

Trend Detection

Identify acceleration or deceleration:

metrics:
- name: revenue_7d_avg
meta:
time_intelligence:
type: rolling_avg
window_size: 7
window_grain: day

- name: revenue_28d_avg
meta:
time_intelligence:
type: rolling_avg
window_size: 28
window_grain: day

- name: trend_indicator
type: derived
expression: |
CASE
WHEN revenue_7d_avg > revenue_28d_avg * 1.1 THEN 'accelerating'
WHEN revenue_7d_avg < revenue_28d_avg * 0.9 THEN 'decelerating'
ELSE 'stable'
END
description: "Trend based on short vs long rolling average"

Smoothed Growth Rate

Calculate growth on smoothed values:

metrics:
- name: revenue_7d_avg
meta:
time_intelligence:
type: rolling_avg
window_size: 7
window_grain: day

- name: revenue_7d_avg_prior_week
meta:
time_intelligence:
type: rolling_avg
window_size: 7
window_grain: day
offset: 7

- name: smoothed_wow_growth
type: derived
expression: |
(revenue_7d_avg - revenue_7d_avg_prior_week)
/ NULLIF(revenue_7d_avg_prior_week, 0) * 100
format: "percent"
description: "Week-over-week growth using 7-day smoothed averages"

SLA Compliance Monitoring

Track rolling compliance percentages:

metrics:
- name: orders_delivered_on_time_30d
type: derived
expression: orders.on_time_delivery_count
meta:
time_intelligence:
type: rolling_sum
window_size: 30
window_grain: day

- name: orders_total_30d
type: derived
expression: orders.order_count
meta:
time_intelligence:
type: rolling_sum
window_size: 30
window_grain: day

- name: on_time_delivery_rate_30d
type: derived
expression: |
orders_delivered_on_time_30d / NULLIF(orders_total_30d, 0) * 100
format: "percent"
description: "30-day rolling on-time delivery rate"

Best Practices

1. Choose Appropriate Window Sizes

Match window size to your analysis needs:

Analysis TypeRecommended Window
Daily operations7-day
Weekly trends14-day or 4-week
Monthly reporting30-day
Quarterly trends90-day
Annual patterns365-day

2. Document Window Behavior

Clearly describe what the window includes:

- name: revenue_rolling_7d
description: |
Sum of revenue for the current day plus the previous 6 days.
Includes: today, yesterday, ..., 6 days ago (7 days total).
Window slides forward daily.

3. Handle Missing Data

Consider NULL values in your calculations:

metrics:
- name: avg_order_value_7d
type: derived
expression: |
CASE
WHEN orders_rolling_7d > 0
THEN revenue_rolling_7d / orders_rolling_7d
ELSE NULL
END
description: "7-day average order value, NULL if no orders"

4. Use Consistent Granularity

Ensure time dimension granularity matches window grain:

# Correct: Daily granularity with day-based window
dimensions:
- name: order_date
type: time
sql: order_date
granularities: [day]

metrics:
- name: revenue_rolling_7d
meta:
time_intelligence:
window_grain: day # Matches dimension granularity

Next Steps