-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathq03_dam_vs_idm_premium.sql
More file actions
66 lines (62 loc) · 2.21 KB
/
Copy pathq03_dam_vs_idm_premium.sql
File metadata and controls
66 lines (62 loc) · 2.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
-- ============================================
-- Q03: DAM vs IDM Premium by Hour-of-Day
-- ============================================
-- BUSINESS CONTEXT:
-- Intraday (IDM) prices trade after Day-Ahead (DAM) closes. The premium
-- IDM commands over DAM reflects intraday supply/demand imbalances and
-- speculative positioning. Understanding when this premium is highest
-- lets traders decide whether to remain in DAM or actively participate
-- in IDM to capture value — or hedge a short position.
--
-- QUESTION: Does IDM trade at a premium or discount to DAM, and how
-- does this pattern vary by hour-of-day?
--
-- DEMONSTRATES: Window functions with PARTITION BY, aggregate analytics
-- ============================================
WITH hourly_premium AS (
SELECT
f.ts,
f.dam_price_try_mwh,
f.idm_price_try_mwh,
f.idm_price_try_mwh - f.dam_price_try_mwh AS premium_try_mwh,
(f.idm_price_try_mwh - f.dam_price_try_mwh)
/ NULLIF(f.dam_price_try_mwh, 0) * 100 AS premium_pct,
c.hour,
c.is_weekend
FROM fact_market_hourly f
JOIN dim_calendar c ON f.ts = c.ts
WHERE f.dam_price_try_mwh IS NOT NULL
AND f.idm_price_try_mwh IS NOT NULL
),
by_hour AS (
SELECT
hour,
is_weekend,
ROUND(AVG(premium_try_mwh), 2) AS avg_premium_try_mwh,
ROUND(AVG(premium_pct), 2) AS avg_premium_pct,
ROUND(STDDEV_SAMP(premium_try_mwh), 2) AS std_premium,
COUNT(*) AS obs_count,
-- Rank hours by average premium within weekday/weekend group
RANK() OVER (
PARTITION BY is_weekend
ORDER BY AVG(premium_try_mwh) DESC
) AS premium_rank
FROM hourly_premium
GROUP BY hour, is_weekend
)
SELECT
hour,
is_weekend,
avg_premium_try_mwh,
avg_premium_pct,
std_premium,
premium_rank,
obs_count,
CASE
WHEN avg_premium_try_mwh > 20 THEN 'strong_premium'
WHEN avg_premium_try_mwh > 5 THEN 'mild_premium'
WHEN avg_premium_try_mwh > -5 THEN 'near_parity'
ELSE 'discount'
END AS premium_regime
FROM by_hour
ORDER BY is_weekend, hour;