Skip to content

NEM Market Briefs

The NEM Daily Brief is an AI-generated market summary produced automatically every morning at 05:30 AEST by Claude Sonnet 4.5 via Databricks FMAPI. The brief provides a structured narrative covering the previous day’s market conditions, key price events, generation highlights, and a forward outlook based on the weather forecast.

Each Daily Brief follows a consistent structure optimised for market participants:

# NEM Daily Market Brief — [Date]
Generated: [timestamp]
## Overnight Price Summary
[Regional price performance, direction, and notable movements]
## Generation Highlights
[Key fuel-type developments: wind ramp events, solar contributions,
coal unit outages, BESS activity]
## FCAS Market
[Ancillary service price conditions, contingency events]
## Price Event Analysis
[Deep-dive on any spikes, troughs, or sustained high-price periods]
## Gas Market Context
[STTM prices and any gas-electricity nexus developments]
## Forward Outlook
[Weather forecast and implied demand/price risk for next 24-48 hours]

The Market Brief is generated by pipelines/06_market_summary.py, which runs as a scheduled serverless job:

# 06_market_summary.py — simplified excerpt
import anthropic
SYSTEM_PROMPT = """
You are an expert Australian energy market analyst. Generate a concise daily
market brief for NEM participants.
IMPORTANT: Do not provide trading advice or investment recommendations.
Focus on factual market observations and data-driven analysis.
"""
def generate_daily_brief(market_data: dict) -> str:
client = anthropic.Anthropic(
base_url=f"{DATABRICKS_HOST}/serving-endpoints",
api_key=DATABRICKS_TOKEN,
)
response = client.messages.create(
model="databricks-claude-sonnet-4-5",
max_tokens=2048,
system=SYSTEM_PROMPT,
messages=[{
"role": "user",
"content": f"Generate a daily NEM market brief for {market_data['date']}. Data: {json.dumps(market_data)}"
}]
)
return response.content[0].text

The pipeline fetches the previous day’s market data from Gold tables, constructs a structured data payload, and passes it to Claude for narrative generation.

The brief uses an “anchor timestamp” to define which data window to summarise. This ensures consistent coverage even if the pipeline runs slightly late (network delays, warehouse cold start):

# Anchor timestamp calculation
from datetime import datetime, timedelta
import pytz
AEST = pytz.timezone('Australia/Sydney')
def get_brief_window():
"""
Returns (start_dt, end_dt) for the brief data window.
Window: previous day 04:00 AEST → current day 04:00 AEST
Anchor: current day 05:30 AEST (scheduled job time)
"""
now_aest = datetime.now(AEST)
anchor_today_0400 = now_aest.replace(hour=4, minute=0, second=0, microsecond=0)
anchor_yesterday_0400 = anchor_today_0400 - timedelta(days=1)
return anchor_yesterday_0400, anchor_today_0400

The 04:00 AEST window boundary is chosen because:

  1. AEMO’s settlement process calculates 30-minute prices with a 30-minute delay
  2. By 05:30 AEST, all data from the previous day’s 04:00 window is fully settled
  3. The window captures a full NEM trading day including peak morning demand

Generated briefs are stored in:

  • gold.market_briefs — Delta table with brief text, metadata, and quality score
  • gold.daily_market_summary — structured summary for API consumption
-- Retrieve the latest market brief
SELECT
brief_date,
generated_at,
brief_text,
word_count,
quality_score
FROM energy_copilot.gold.market_briefs
ORDER BY brief_date DESC
LIMIT 1;

Each brief is automatically scored on four dimensions:

  1. Completeness (0–25): Did the brief cover all required sections?
  2. Data accuracy (0–25): Do the numbers mentioned match the source data?
  3. Brevity (0–25): Is the brief within the target word count (400–800 words)?
  4. Tone compliance (0–25): Did the brief avoid trading advice language?

Briefs scoring below 70/100 are flagged for review and a fallback template brief is served instead.

Terminal window
# Latest market brief
GET /api/market-brief/latest
# Brief for specific date
GET /api/market-brief/2025-03-21
# Brief history (last 30 days)
GET /api/market-brief/history?days=30
# Response structure:
{
"brief_date": "2025-03-21",
"generated_at": "2025-03-21T05:32:14+10:00",
"brief_text": "## NEM Daily Market Brief — 21 March 2025\n...",
"word_count": 547,
"quality_score": 88
}

The Market Briefs dashboard (/front-office/market-briefs) shows:

  • Today’s brief as a formatted card with expandable sections
  • Brief history — last 30 days of briefs in a scrollable timeline
  • Key statistics extracted from each brief: max price, min price, dominant fuel, notable events
  • Brief search — full-text search across historical briefs