使用 SQL Server 2014 计算简单移动平均线交叉

Calculate a Simple Moving Average Crossover using SQL Server 2014

如何实现简单移动平均线交叉?我在这里查看了其他一些 example/questions 问题,但是他们似乎都使用 ID 列,我的 table 没有 ID 并使用 TIME 作为唯一字段。

SMA 交叉用于确定股票 and/or 外汇市场的趋势。为了简洁起见,下面建议的查询输出是 10 天和 20 天的移动平均线。然而,在现实世界中,我将使用 60 天和 270 天的平均值。 继 (big thanks to Lucero) 之后,计算平均值有两个答案。第一个 ATR 平均值比第二个快得多。


我有以下数据:

TIME               BID-OPEN BID-HIGH BID-LOW BID-CLOSE
28/01/1981 22:00    130.34  130.34  130.34  130.34
29/01/1981 22:00    130.24  130.24  130.24  130.24
02/02/1981 22:00    126.91  126.91  126.91  126.91
03/02/1981 22:00    128.46  128.46  128.46  128.46
04/02/1981 22:00    128.59  128.59  128.59  128.59
05/02/1981 22:00    129.63  129.63  129.63  129.63
09/02/1981 22:00    129.27  129.27  129.27  129.27
10/02/1981 22:00    129.24  129.24  129.24  129.24
11/02/1981 22:00    128.24  128.24  128.24  128.24
12/02/1981 22:00    127.48  127.48  127.48  127.48
17/02/1981 22:00    127.81  127.81  127.81  127.81
18/02/1981 22:00    128.48  128.48  128.48  128.48
19/02/1981 22:00    126.61  126.61  126.61  126.61
23/02/1981 22:00    127.35  127.35  127.35  127.35
24/02/1981 22:00    127.39  127.39  127.39  127.39
25/02/1981 22:00    128.52  128.52  128.52  128.52
26/02/1981 22:00    130.1   130.1   130.1   130.1
02/03/1981 22:00    132.01  132.01  132.01  132.01
03/03/1981 22:00    130.56  130.56  130.56  130.56
04/03/1981 22:00    130.86  130.86  130.86  130.86
05/03/1981 22:00    129.93  129.93  129.93  129.93
09/03/1981 22:00    131.12  131.12  131.12  131.12
10/03/1981 22:00    130.46  130.46  130.46  130.46
11/03/1981 22:00    129.95  129.95  129.95  129.95
12/03/1981 22:00    133.19  133.19  133.19  133.19
16/03/1981 22:00    134.68  134.68  134.68  134.68
17/03/1981 22:00    133.92  133.92  133.92  133.92
18/03/1981 22:00    134.22  134.22  134.22  134.22
19/03/1981 22:00    133.46  133.46  133.46  133.46
23/03/1981 22:00    135.69  135.69  135.69  135.69
24/03/1981 22:00    134.67  134.67  134.67  134.67

下面建议的查询输出,过去 10 天和 20 天的 [BID-CLOSE] 值的平均值,将给出这样的输出:

(四舍五入到小数点后两位)

TIME             BID-CLOSE FAST-SMA SLOW-SMA    
28/01/1981 22:00    130.34  NULL    NULL
29/01/1981 22:00    130.24  NULL    NULL
02/02/1981 22:00    126.91  NULL    NULL
03/02/1981 22:00    128.46  NULL    NULL
04/02/1981 22:00    128.59  NULL    NULL
05/02/1981 22:00    129.63  NULL    NULL
09/02/1981 22:00    129.27  NULL    NULL
10/02/1981 22:00    129.24  NULL    NULL
11/02/1981 22:00    128.24  NULL    NULL
12/02/1981 22:00    127.48  128.84  NULL
17/02/1981 22:00    127.81  128.59  NULL
18/02/1981 22:00    128.48  128.41  NULL
19/02/1981 22:00    126.61  128.39  NULL
23/02/1981 22:00    127.35  128.27  NULL
24/02/1981 22:00    127.39  128.15  NULL
25/02/1981 22:00    128.52  128.04  NULL
26/02/1981 22:00    130.1   128.12  NULL
02/03/1981 22:00    132.01  128.40  NULL
03/03/1981 22:00    130.56  128.63  NULL
04/03/1981 22:00    130.86  128.97  128.90
05/03/1981 22:00    129.93  129.18  128.89
09/03/1981 22:00    131.12  129.45  128.93
10/03/1981 22:00    130.46  129.83  129.11
11/03/1981 22:00    129.95  130.09  129.18
12/03/1981 22:00    133.19  130.67  129.41
16/03/1981 22:00    134.68  131.29  129.66
17/03/1981 22:00    133.92  131.67  129.90
18/03/1981 22:00    134.22  131.89  130.14
19/03/1981 22:00    133.46  132.18  130.41
23/03/1981 22:00    135.69  132.67  130.82
24/03/1981 22:00    134.67  133.14  131.16

SMA = 简单移动平均线

作为起点,您可能希望使用 avg() over(),如下所示:

select time, 
    [bid-close],
    avg([bid-close]) over (order by time rows 9 preceding) as [fast-sma]
    avg([bid-close]) over (order by time rows 19 preceding) as [slow-sma]
from table

您可以通过将 window 函数包装在 ROW_NUMBER() 的条件中来阻止计算前 n 行的 SMA。

要检测正交叉和负交叉,您可以使用 LAG() 函数使用多条件检查当前值和先前值。

这应该能满足您的需求:

WITH sma_table AS
(
    SELECT
        time,
        bid_open,
        bid_high,
        bid_low,
        bid_close,
        CASE WHEN ROW_NUMBER() OVER (ORDER BY time) > 9 
             THEN AVG(bid_close) OVER (ORDER BY time ROWS 9 PRECEDING) 
        END AS sma_10,
        CASE WHEN ROW_NUMBER() OVER (ORDER BY time) > 19
             THEN AVG(bid_close) OVER (ORDER BY time ROWS 19 PRECEDING) 
        END AS sma_20
    FROM your_table
)
SELECT
    *,
    CASE WHEN bid_close > sma_10 
              AND LAG(bid_close) OVER (ORDER BY time) <= LAG(sma_10) OVER (ORDER BY time) 
              THEN 1
         WHEN bid_close < sma_10 
              AND LAG(bid_close) OVER (ORDER BY time) >= LAG(sma_10) OVER (ORDER BY time) 
              THEN -1
    END AS sma_10_crossover,
    CASE WHEN bid_close > sma_20 
              AND LAG(bid_close) OVER (ORDER BY time) <= LAG(sma_20) OVER (ORDER BY time) 
              THEN 1
         WHEN bid_close < sma_20 
              AND LAG(bid_close) OVER (ORDER BY time) >= LAG(sma_20) OVER (ORDER BY time) 
              THEN -1
    END AS sma_20_crossover
FROM sma_table