Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion documentation/cookbook/demo-data-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ CREATE TABLE 'market_data' (
timestamp TIMESTAMP,
symbol SYMBOL CAPACITY 16384 CACHE,
bids DOUBLE[][],
asks DOUBLE[][]
asks DOUBLE[][],
best_bid DOUBLE,
best_ask DOUBLE
) timestamp(timestamp) PARTITION BY HOUR TTL 3 DAYS;
```

Expand All @@ -102,6 +104,8 @@ CREATE TABLE 'market_data' (
- **`symbol`** - Currency pair (e.g., EURUSD, GBPJPY)
- **`bids`** - 2D array containing bid prices and volumes: `[[price1, price2, ...], [volume1, volume2, ...]]`
- **`asks`** - 2D array containing ask prices and volumes: `[[price1, price2, ...], [volume1, volume2, ...]]`
- **`best_bid`** - Best (highest) bid price. Equivalent to `bids[1][1]` but preferred when only the top-of-book price is needed, as it scans much less data
- **`best_ask`** - Best (lowest) ask price. Equivalent to `asks[1][1]` but preferred when only the top-of-book price is needed, as it scans much less data

The arrays are structured so that:
- `bids[1]` contains bid prices (descending order - highest first)
Expand Down
2 changes: 1 addition & 1 deletion documentation/cookbook/sql/finance/atr.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ You want to measure volatility to set appropriate stop-losses or position sizes.
```questdb-sql demo title="Calculate 14-period ATR"
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
@lookback := '$now - 2d..$now'

WITH with_prev AS (
SELECT
Expand Down
18 changes: 7 additions & 11 deletions documentation/cookbook/sql/finance/donchian-channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,22 @@ You want to identify breakout levels and trading ranges. Moving averages smooth
```questdb-sql demo title="Calculate 20-period Donchian Channels"
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
@lookback := '$now - 2d..$now'

WITH channels AS (
SELECT
timestamp,
symbol,
close,
max(high) OVER (
PARTITION BY symbol
ORDER BY timestamp
ROWS BETWEEN 19 PRECEDING AND CURRENT ROW
) AS upper_channel,
min(low) OVER (
PARTITION BY symbol
ORDER BY timestamp
ROWS BETWEEN 19 PRECEDING AND CURRENT ROW
) AS lower_channel
max(high) OVER w AS upper_channel,
min(low) OVER w AS lower_channel
FROM market_data_ohlc_15m
WHERE symbol = @symbol
AND timestamp IN @lookback
WINDOW w AS (
PARTITION BY symbol ORDER BY timestamp
ROWS BETWEEN 19 PRECEDING AND CURRENT ROW
)
)
SELECT
timestamp,
Expand Down
7 changes: 4 additions & 3 deletions documentation/cookbook/sql/finance/keltner-channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ You want volatility bands that adapt to market conditions but are smoother than
```questdb-sql demo title="Calculate Keltner Channels (20-period EMA ± 2× ATR)"
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
@lookback := '$now - 2d..$now'

WITH with_prev AS (
SELECT
Expand Down Expand Up @@ -49,9 +49,10 @@ with_indicators AS (
timestamp,
symbol,
close,
avg(close, 'period', 20) OVER (PARTITION BY symbol ORDER BY timestamp) AS ema20,
avg(tr, 'period', 20) OVER (PARTITION BY symbol ORDER BY timestamp) AS atr
avg(close, 'period', 20) OVER w AS ema20,
avg(tr, 'period', 20) OVER w AS atr
FROM with_tr
WINDOW w AS (PARTITION BY symbol ORDER BY timestamp)
)
SELECT
timestamp,
Expand Down
7 changes: 4 additions & 3 deletions documentation/cookbook/sql/finance/macd.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@ You want to identify trend changes and momentum shifts. Simple moving averages l
```questdb-sql demo title="Calculate MACD with signal line and histogram"
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
@lookback := '$now - 2d..$now'

WITH ema AS (
SELECT
timestamp,
symbol,
close,
avg(close, 'period', 12) OVER (PARTITION BY symbol ORDER BY timestamp) AS ema12,
avg(close, 'period', 26) OVER (PARTITION BY symbol ORDER BY timestamp) AS ema26
avg(close, 'period', 12) OVER w AS ema12,
avg(close, 'period', 26) OVER w AS ema26
FROM market_data_ohlc_15m
WHERE symbol = @symbol
AND timestamp IN @lookback
WINDOW w AS (PARTITION BY symbol ORDER BY timestamp)
),
macd_line AS (
SELECT
Expand Down
41 changes: 29 additions & 12 deletions documentation/cookbook/sql/finance/maximum-drawdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'

WITH with_peak AS (
WITH ohlc AS (
SELECT
timestamp,
symbol,
last(price) AS close
FROM fx_trades
WHERE symbol = @symbol
AND timestamp IN @lookback
SAMPLE BY 15m ALIGN TO CALENDAR
),
with_peak AS (
SELECT
timestamp,
symbol,
Expand All @@ -27,9 +37,7 @@ WITH with_peak AS (
ORDER BY timestamp
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_peak
FROM market_data_ohlc_15m
WHERE symbol = @symbol
AND timestamp IN @lookback
FROM ohlc
),
with_drawdown AS (
SELECT
Expand All @@ -56,9 +64,10 @@ ORDER BY timestamp;
```

The query:
1. Tracks the running maximum (peak) price using `max() OVER (... UNBOUNDED PRECEDING)`
2. Calculates current drawdown as percentage from peak
3. Tracks the minimum (worst) drawdown seen so far
1. Aggregates raw trades into 15-minute bars using the last trade price as close
2. Tracks the running maximum (peak) price using `max() OVER (... UNBOUNDED PRECEDING)`
3. Calculates current drawdown as percentage from peak
4. Tracks the minimum (worst) drawdown seen so far

## Interpreting results

Expand All @@ -69,14 +78,22 @@ The query:

## Finding drawdown periods

```questdb-sql title="Identify significant drawdown periods"
DECLARE @symbol := 'EURUSD'
```questdb-sql demo title="Identify significant drawdown periods"
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'

WITH with_peak AS (
WITH ohlc AS (
SELECT timestamp, symbol, last(price) AS close
FROM fx_trades
WHERE symbol = @symbol
AND timestamp IN @lookback
SAMPLE BY 15m ALIGN TO CALENDAR
),
with_peak AS (
SELECT timestamp, symbol, close,
max(close) OVER (PARTITION BY symbol ORDER BY timestamp ROWS UNBOUNDED PRECEDING) AS running_peak
FROM market_data_ohlc_15m
WHERE symbol = @symbol
FROM ohlc
),
with_drawdown AS (
SELECT timestamp, symbol, close, running_peak,
Expand Down
31 changes: 21 additions & 10 deletions documentation/cookbook/sql/finance/obv.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,30 @@ DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'

WITH with_direction AS (
WITH ohlc AS (
SELECT
timestamp,
symbol,
last(price) AS close,
sum(quantity) AS volume
FROM fx_trades
WHERE symbol = @symbol
AND timestamp IN @lookback
SAMPLE BY 15m ALIGN TO CALENDAR
),
with_direction AS (
SELECT
timestamp,
symbol,
close,
total_volume AS volume,
volume,
CASE
WHEN close > lag(close) OVER (PARTITION BY symbol ORDER BY timestamp) THEN volume
WHEN close < lag(close) OVER (PARTITION BY symbol ORDER BY timestamp) THEN -volume
WHEN close > lag(close) OVER w THEN volume
WHEN close < lag(close) OVER w THEN -volume
ELSE 0
END AS directed_volume
FROM fx_trades_ohlc_1m
WHERE symbol = @symbol
AND timestamp IN @lookback
FROM ohlc
WINDOW w AS (PARTITION BY symbol ORDER BY timestamp)
)
SELECT
timestamp,
Expand All @@ -47,9 +57,10 @@ ORDER BY timestamp;
```

The query:
1. Compares each close to the previous close
2. Assigns positive volume if price went up, negative if down, zero if unchanged
3. Calculates cumulative sum of directed volume
1. Aggregates raw trades into 15-minute bars with closing price and total volume
2. Compares each bar's close to the previous close
3. Assigns positive volume if price went up, negative if down, zero if unchanged
4. Calculates cumulative sum of directed volume

## Interpreting results

Expand Down
2 changes: 1 addition & 1 deletion documentation/cookbook/sql/finance/rate-of-change.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ You want a simple momentum indicator that shows how fast price is changing. Raw
```questdb-sql demo title="Calculate 12-period Rate of Change"
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
@lookback := '$now - 2d..$now'

WITH with_lag AS (
SELECT
Expand Down
5 changes: 3 additions & 2 deletions documentation/cookbook/sql/finance/rolling-stddev.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ WITH stats AS (
timestamp,
symbol,
price,
AVG(price) OVER (PARTITION BY symbol ORDER BY timestamp) AS rolling_avg,
AVG(price * price) OVER (PARTITION BY symbol ORDER BY timestamp) AS rolling_avg_sq
AVG(price) OVER w AS rolling_avg,
AVG(price * price) OVER w AS rolling_avg_sq
FROM fx_trades
WHERE timestamp IN '$yesterday' AND symbol = 'EURUSD'
WINDOW w AS (PARTITION BY symbol ORDER BY timestamp)
)
SELECT
timestamp,
Expand Down
7 changes: 4 additions & 3 deletions documentation/cookbook/sql/finance/rsi.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ You want to identify when an asset may be overbought or oversold based on recent
```questdb-sql demo title="Calculate 14-period RSI with EMA smoothing"
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
@lookback := '$now - 2d..$now'

WITH changes AS (
SELECT
Expand All @@ -41,9 +41,10 @@ smoothed AS (
timestamp,
symbol,
close,
avg(gain, 'period', 14) OVER (PARTITION BY symbol ORDER BY timestamp) AS avg_gain,
avg(loss, 'period', 14) OVER (PARTITION BY symbol ORDER BY timestamp) AS avg_loss
avg(gain, 'period', 14) OVER w AS avg_gain,
avg(loss, 'period', 14) OVER w AS avg_loss
FROM gains_losses
WINDOW w AS (PARTITION BY symbol ORDER BY timestamp)
)
SELECT
timestamp,
Expand Down
18 changes: 7 additions & 11 deletions documentation/cookbook/sql/finance/stochastic.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,22 @@ You want to identify overbought and oversold conditions based on where price is
```questdb-sql demo title="Calculate Stochastic %K and %D"
DECLARE
@symbol := 'EURUSD',
@lookback := '$now - 1M..$now'
@lookback := '$now - 2d..$now'

WITH ranges AS (
SELECT
timestamp,
symbol,
close,
min(low) OVER (
PARTITION BY symbol
ORDER BY timestamp
ROWS BETWEEN 13 PRECEDING AND CURRENT ROW
) AS lowest_low,
max(high) OVER (
PARTITION BY symbol
ORDER BY timestamp
ROWS BETWEEN 13 PRECEDING AND CURRENT ROW
) AS highest_high
min(low) OVER w AS lowest_low,
max(high) OVER w AS highest_high
FROM market_data_ohlc_15m
WHERE symbol = @symbol
AND timestamp IN @lookback
WINDOW w AS (
PARTITION BY symbol ORDER BY timestamp
ROWS BETWEEN 13 PRECEDING AND CURRENT ROW
)
),
with_k AS (
SELECT
Expand Down
Loading