ds@mcpanalytics.aiEmail your data and your question and get an answer about your own data, with the method shown.Email your data and question. Get an answer.

Cash Flow Trend Analysis

By MCP Analytics Team | Published , updated

A business can be profitable on paper while the money does not arrive evenly. A construction company runs flush from May through September and tight from November through March. A SaaS company collecting annual subscriptions in January needs to plan for the August trough. Most finance teams track cash flow in spreadsheets with running totals and color-coded cells, but they cannot answer the most basic planning question: how much cash do we need to reserve for the slow season? This analysis decomposes your cash flow into trend and seasonal patterns so you can answer that question with data instead of anxiety.

Worked Example: A Simulated Cash Flow Series

Question: How does made-up net cash change over time, and which months are high or low?

Data: The script below makes 36 monthly net cash values in made-up dollars, with a fixed seed so the same values appear every run. The data build in three things: a trend of 8 dollars a month, a seasonal shape that runs from -200 in January to +200 in July, and random noise. They contain no one-off events and no costs.

Method: The script fits the trend and the 12 month effects together by least squares. Taking each month's average before removing the trend would mix part of the trend into the month effects, so the two are estimated in one fit.

import numpy as np

seed = 17
rng = np.random.default_rng(seed)
months = np.array(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                   'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'])
season = np.array([-200, -160, -80, 0, 80, 150, 200, 160, 80, 0, -80, -150],
                  dtype=float)
t = np.arange(36, dtype=float)
month_id = (t.astype(int) % 12)
trend_true = 1000 + 8 * t
cash = trend_true + season[month_id] + rng.normal(0, 25, size=36)

# Estimate trend and month effects together by least squares
# (trend plus 12 month indicators, no separate intercept).
X = np.column_stack([t] + [(month_id == m).astype(float) for m in range(12)])
coef = np.linalg.lstsq(X, cash, rcond=None)[0]
slope = coef[0]
month_level = coef[1:]
season_est = month_level - month_level.mean()
trough_id = int(np.argmin(season_est))
peak_id = int(np.argmax(season_est))
print(f'Simulated data, seed {seed}')
print(f'Input: {len(cash)} monthly net cash values, in made-up dollars, '
      f'over {len(cash)//12} years')
print('Method: fit the trend and the month effects together by least squares')
print('Built in: trend 8 dollars per month; Jan -200 and Jul +200, '
      'so a peak-to-trough gap of 400 dollars')
print(f'Estimated trend: {slope:.1f} dollars per month')
print(f'Lowest month effect: {months[trough_id]} '
      f'{season_est[trough_id]:.1f} dollars vs. average')
print(f'Highest month effect: {months[peak_id]} '
      f'{season_est[peak_id]:.1f} dollars vs. average')
print('Estimated peak-to-trough gap: '
      f'{season_est[peak_id] - season_est[trough_id]:.1f} dollars')
print('Limit: only three cycles are shown; a real cash plan must include '
      'costs, starting cash, and one-off events')

Printed output of the script above:

Simulated data, seed 17
Input: 36 monthly net cash values, in made-up dollars, over 3 years
Method: fit the trend and the month effects together by least squares
Built in: trend 8 dollars per month; Jan -200 and Jul +200, so a peak-to-trough gap of 400 dollars
Estimated trend: 8.2 dollars per month
Lowest month effect: Jan -199.5 dollars vs. average
Highest month effect: Jul 192.8 dollars vs. average
Estimated peak-to-trough gap: 392.3 dollars
Limit: only three cycles are shown; a real cash plan must include costs, starting cash, and one-off events

Result: The built-in trend is 8 dollars a month and the built-in swing is 400 dollars. Fitting both together recovers a trend of 8.2 and a swing of 392.3, with January at -199.5 and July at 192.8 against the built-in -200 and +200. The fit is close because the data were built from exactly this shape. A real cash series can contain effects this model does not include, and a missed effect means the estimate is weaker than it looks, not that no effect exists.

Limit: Only three seasonal cycles are shown. A real cash plan must also include costs, starting cash, and one-off events. More repeats of the seasonal cycle give a steadier estimate; this example uses three.

Sources

  • Hyndman RJ, Athanasopoulos G. Forecasting: Principles and Practice (3rd ed.). otexts.com/fpp3. Covers: seasonal decomposition and time series forecasting.

The Cash Flow Visibility Problem

The problem is not that business owners are careless. It is that cash flow patterns are genuinely hard to see in raw transaction data. When you look at three years of bank statements, you see individual transactions: rent payments, payroll runs, client invoices, equipment purchases. What you do not see is the shape of the seasonal pattern buried underneath.

A QuickBooks cash flow report shows you what happened last month. It does not tell you that your business dips every February, recovers in April, peaks in July, and then slowly declines through the fall. Knowing that pattern, and knowing its magnitude, transforms your working capital planning. Instead of scrambling for a credit line every February, you reserve the right amount of cash from the July peak to cover the February trough.

This analysis uses time series decomposition to separate your cash flow into three distinct signals: the long-term trend (is your business genuinely growing?), the seasonal pattern (which months are consistently strong or weak?), and the residual (one-off events like a large contract win or an unexpected repair). Once separated, each component tells you something actionable.

What This Analysis Shows You

The core output is a decomposition chart with four panels:

Beyond decomposition, the analysis generates a 90-day forward projection with uncertainty bands. This projection extends the observed trend and seasonal patterns into the future, giving you a month-by-month estimate of cash position. The uncertainty band widens as you project further out. The first month is relatively confident, the third month is an educated range.

Who This Is For

CFOs, controllers, and bookkeepers at companies with $1M to $30M in revenue: businesses large enough to have real cash flow variability but without a dedicated treasury management system. Industries with pronounced seasonality benefit the most: construction, hospitality, retail, agriculture, education, consulting, and any project-based business where revenue arrives in lumps.

The current alternative for most of these teams is a weekly Excel cash flow tracker updated manually from bank statement downloads. Tools that project forward from the current balance do not by themselves show the seasonal pattern or how large the slow-season trough is. A decomposition does.

What Data You Need

A CSV export from your bank account or accounting system. You need two columns:

Optional but valuable:

For best results, use actual bank transactions rather than accrual-basis accounting data. Cash flow analysis is about when money actually moves, not when revenue is recognized. Most banks offer CSV download of transaction history. QuickBooks and Xero both export cash-basis reports.

More repeats of the seasonal cycle give a steadier estimate of trend and seasonality. The worked example above uses three years of monthly data.

How to Use the Results

Set Your Cash Reserve Target

The seasonal component chart shows your worst month relative to your average. If your seasonal trough is -$80,000 below the monthly average and it lasts three months, you need roughly $240,000 in cash reserves (or credit facility access) to cover the slow season without disruption. This is the single most actionable number in the report, and most business owners have never calculated it from their actual data.

Time Major Expenses

If your decomposition shows that cash peaks in July and troughs in February, schedule discretionary spending (equipment purchases, software renewals, conference attendance, bonus payments) for the peak months when cash is abundant. This sounds obvious, but without seeing the seasonal chart, most businesses time expenses based on calendar habits rather than cash availability.

Negotiate Better Terms

Armed with a clear seasonal pattern, you can negotiate payment terms that align with your cash cycle. Ask suppliers for 60-day terms during your slow season instead of 30. Offer early-payment discounts to clients during your strong months when you want to accelerate inflows. The decomposition chart is a persuasive document to show your banker or supplier.

Separate Growth From Seasonality

The trend line answers one of the most important strategic questions: is the underlying business growing? A company that looks flat in raw cash flow might actually be growing 8% per year. The growth is masked by seasonal variation. Conversely, a business that feels like it is growing might just be riding an unusually strong seasonal period. The trend line strips away the seasonal effect so the underlying direction is easier to see.

When to Use Something Else

Your turn

Bring your own data and the question you actually need answered.

MCP AnalyticsData science by email Send us your data and your question, and we will reply. ds@mcpanalytics.ai