-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathtechnical_price_universe.sql
More file actions
108 lines (95 loc) · 3.22 KB
/
Copy pathtechnical_price_universe.sql
File metadata and controls
108 lines (95 loc) · 3.22 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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
{{ config(
description='Unified daily OHLCV universe across stock/ETF/index price sources for the technical-analysis framework (issue #109)'
) }}
/*
Technical Price Universe
Grain: one row per source_universe, symbol, exchange, date.
Normalizes adjusted OHLCV columns from existing market staging models
into a single spine that downstream indicator/signal models consume.
- S&P 500 stocks use split-adjusted prices (split_adjusted_prices) so
indicators are not distorted by splits.
- ETF/index sources prefer MarketStack-adjusted fields, falling back
to raw values when the adjusted column is NULL.
No new ingestion: only sources already present in the project.
*/
{% set etf_universes = [
{'model': 'stg_us_sectors', 'universe': 'us_sector_etf'},
{'model': 'stg_major_indices', 'universe': 'major_index'},
{'model': 'stg_fixed_income', 'universe': 'fixed_income_etf'},
{'model': 'stg_currency', 'universe': 'currency_etf'},
{'model': 'stg_commodity_etfs', 'universe': 'commodity_etf'},
{'model': 'stg_global_markets', 'universe': 'global_market'},
] %}
WITH unioned AS (
SELECT
'sp500_stock' AS source_universe,
symbol,
COALESCE(exchange, 'UNKNOWN') AS exchange,
name,
asset_type,
'USD' AS price_currency,
source_table,
date,
split_adj_open AS open,
split_adj_high AS high,
split_adj_low AS low,
split_adj_close AS close,
split_adj_volume AS volume
FROM {{ ref('split_adjusted_prices') }}
{% for entry in etf_universes %}
UNION ALL
SELECT
'{{ entry.universe }}' AS source_universe,
symbol,
COALESCE(exchange, 'UNKNOWN') AS exchange,
name,
asset_type,
price_currency,
'{{ entry.model }}' AS source_table,
date,
COALESCE(adj_open, open) AS open,
COALESCE(adj_high, high) AS high,
COALESCE(adj_low, low) AS low,
COALESCE(adj_close, close) AS close,
COALESCE(adj_volume, volume) AS volume
FROM {{ ref(entry.model) }}
{% endfor %}
),
filtered AS (
SELECT *
FROM unioned
WHERE date IS NOT NULL
AND symbol IS NOT NULL
AND close IS NOT NULL
AND close > 0
-- Collapse duplicate vendor rows at the grain, keeping the most-traded row
QUALIFY ROW_NUMBER() OVER (
PARTITION BY source_universe, symbol, exchange, date
ORDER BY volume DESC
) = 1
)
SELECT
source_universe,
symbol,
exchange,
name,
asset_type,
price_currency,
source_table,
date,
open,
-- Vendor data occasionally reports close outside the high/low range
-- (see test_ohlc_consistency). Clamp so low <= close <= high always
-- holds; range-based indicators (stochastic, Williams %R, ATR,
-- Donchian) rely on this invariant.
GREATEST(COALESCE(high, close), close) AS high,
LEAST(COALESCE(low, close), close) AS low,
close,
volume,
-- Trading-bar counter per instrument; downstream models use this for
-- indicator warmup gating and forward-return offsets.
ROW_NUMBER() OVER (
PARTITION BY source_universe, symbol, exchange
ORDER BY date
) AS bars_available
FROM filtered