SQLITE移动平均线

时间:2016-11-19 22:21:21

标签: sqlite date-arithmetic moving-average

尝试使用SQLite每X个月获得移动平均值。 问题是我似乎无法想象或发现任何有关如何与X个月回顾期聚合的远程有用的东西,从而创建一个移动平均线。

CREATE TABLE "nav" (
    `id`    TEXT,
    `nav`   NUMERIC,
    `date`  TEXT
);

示例数据

id      nav     date
1380    15.3    2005-01-09
1380    15.4    2005-01-16
1380    15.5    2005-01-23
1380    15.55   2005-01-30
1380    15.66   2005-02-06
1380    15.45   2005-02-13
1380    15.26   2005-02-20
1380    15.14   2005-02-27
1380    14.95   2005-03-06
1380    15.24   2005-03-13
1380    15.6    2005-03-20
1380    15.7    2005-03-27
1380    15.86   2005-04-03
1380    15.78   2005-04-10
1380    15.58   2005-04-17
1380    15.84   2005-04-24
1380    15.88   2005-05-01
1380    16.2    2005-05-08
1380    16.29   2005-05-15
1380    16.32   2005-05-22
1380    16.59   2005-05-29
1380    16.96   2005-06-05
1380    16.76   2005-06-12
1380    17.32   2005-06-19
1380    17.63   2005-06-26
1380    17.6    2005-07-03
1380    17.36   2005-07-10
1380    17.36   2005-07-17
1380    17.27   2005-07-24
1380    16.86   2005-07-31
1380    16.68   2005-08-07
1380    17.21   2005-08-14
1380    16.87   2005-08-21
1380    16.52   2005-08-28
1380    16.77   2005-09-04
1380    17.1    2005-09-11
1380    17.37   2005-09-18
1380    17.29   2005-09-25
1380    17.24   2005-10-02
1380    17.52   2005-10-09
1380    17.72   2005-10-16
1380    17.65   2005-10-23
1380    18.18   2005-10-30
1380    18.31   2005-11-06
1380    18.42   2005-11-13
1380    18.13   2005-11-20
1380    18.12   2005-11-27
1380    17.92   2005-12-04
1380    17.74   2005-12-11
1380    17.93   2005-12-18
1380    17.94   2005-12-25
1380    17.39   2006-01-01
1380    17.4    2006-01-08
1380    17.37   2006-01-15
1380    17.22   2006-01-22
1380    17.47   2006-01-29
1380    17.53   2006-02-05
1380    17.77   2006-02-12
1380    17.95   2006-02-19
1380    17.85   2006-02-26
1380    17.88   2006-03-05
1380    17.42   2006-03-12
1380    17.71   2006-03-19
1380    17.71   2006-03-26
1380    17.53   2006-04-02
1380    17.54   2006-04-09
1380    17.21   2006-04-16
1380    16.84   2006-04-23
1380    16.68   2006-04-30
1380    16.59   2006-05-07
1380    16.82   2006-05-14
1380    16.72   2006-05-21
1380    16.34   2006-05-28
1380    16.72   2006-06-04
1380    16.83   2006-06-11
1380    16.84   2006-06-18
1380    16.54   2006-06-25
1380    16.41   2006-07-02
1380    16.76   2006-07-09
1380    16.77   2006-07-16
1380    16.69   2006-07-23
1380    16.48   2006-07-30
1380    16.65   2006-08-06
1380    16.61   2006-08-13
1380    16.78   2006-08-20
1380    16.88   2006-08-27
1380    17.03   2006-09-03
1380    16.9    2006-09-10
1380    16.85   2006-09-17
1380    17.04   2006-09-24
1380    17.1    2006-10-01
1380    17.28   2006-10-08
1380    17.02   2006-10-15
1380    16.91   2006-10-22
1380    16.85   2006-10-29
1380    16.53   2006-11-05
1380    16.53   2006-11-12
1380    16.17   2006-11-19
1380    15.87   2006-11-26
1380    15.94   2006-12-03
1380    16.22   2006-12-10
1380    16.07   2006-12-17
1380    16.09   2006-12-24
1380    16.42   2006-12-31
1380    16.54   2007-01-07
1380    16.57   2007-01-14
1380    16.61   2007-01-21
1380    16.5    2007-01-28
1380    16.53   2007-02-04
1380    16.67   2007-02-11
1380    16.73   2007-02-18
1380    16.71   2007-02-25
1380    16.81   2007-03-04
1380    16.54   2007-03-11
1380    16.59   2007-03-18
1380    16.67   2007-03-25
1380    16.42   2007-04-01
1380    16.35   2007-04-08
1380    16.11   2007-04-15
1380    15.96   2007-04-22
1380    16.1    2007-04-29
1380    16.3    2007-05-06
1380    16.33   2007-05-13
1380    16.35   2007-05-20
1380    16.61   2007-05-27
1380    16.62   2007-06-03
1380    16.92   2007-06-10
1380    16.57   2007-06-17
1380    16.43   2007-06-24
1380    16.17   2007-07-01
1380    15.95   2007-07-08
1380    15.97   2007-07-15
1380    16.23   2007-07-22
1380    16.17   2007-07-29
1380    16.36   2007-08-05
1380    16.68   2007-08-12
1380    16.61   2007-08-19
1380    16.57   2007-08-26
1380    16.4    2007-09-02
1380    16.16   2007-09-09
1380    15.83   2007-09-16
1380    15.71   2007-09-23
1380    15.73   2007-09-30
1380    15.6    2007-10-07
1380    15.61   2007-10-14
1380    15.55   2007-10-21
1380    15.57   2007-10-28
1380    15.44   2007-11-04
1380    15.47   2007-11-11
1380    15.4    2007-11-18
1380    15.52   2007-11-25
1380    15.7    2007-12-02
1380    15.96   2007-12-09
1380    16.1    2007-12-16
1380    15.78   2007-12-23
1380    15.55   2007-12-30
1380    15.6    2008-01-06
1380    15.82   2008-01-13
1380    15.83   2008-01-20
1380    15.68   2008-01-27
1380    16.01   2008-02-03
1380    15.61   2008-02-10
1380    15.46   2008-02-17
1380    15.2    2008-02-24
1380    15.1    2008-03-02
1380    14.89   2008-03-09
1380    15.02   2008-03-16
1380    14.69   2008-03-23
1380    14.69   2008-03-30
1380    14.67   2008-04-06
1380    14.75   2008-04-13
1380    14.75   2008-04-20
1380    15      2008-04-27
1380    14.88   2008-05-04
1380    14.87   2008-05-11
1380    14.6    2008-05-18
1380    14.88   2008-05-25
1380    15      2008-06-01
1380    15.07   2008-06-08
1380    15      2008-06-15
1380    14.81   2008-06-22
1380    14.84   2008-06-29
1380    14.74   2008-07-06
1380    14.82   2008-07-13
1380    14.98   2008-07-20
1380    15.06   2008-07-27
1380    15.52   2008-08-03
1380    15.64   2008-08-10
1380    15.69   2008-08-17
1380    15.95   2008-08-24
1380    16.44   2008-08-31
1380    16.77   2008-09-07
1380    16.48   2008-09-14
1380    16.44   2008-09-21
1380    17.49   2008-09-28
1380    17.66   2008-10-05
1380    18.44   2008-10-12
1380    19.42   2008-10-19
1380    19.34   2008-10-26
1380    19.62   2008-11-02
1380    19.57   2008-11-09
1380    20.77   2008-11-16
1380    20.18   2008-11-23
1380    20.97   2008-11-30
1380    19.96   2008-12-07
1380    19.4    2008-12-14
1380    19.6    2008-12-21
1380    19.46   2008-12-28
1380    19.75   2009-01-04
1380    20.31   2009-01-11
1380    20.78   2009-01-18
1380    20.56   2009-01-25

基本上我想要...(假数据)

id      nav     date            average_6m
1380    15.6    2008-01         14.1
1380    15.61   2008-02         14.12
1380    14.69   2008-03         14.2
1380    15      2008-04         14.5
1380    14.88   2008-05         14.4
1380    14.84   2008-06         14.3
1380    15.06   2008-07         14.6
1380    16.44   2008-08         15.2
1380    17.49   2008-09         15.9
1380    19.34   2008-10         16.4
1380    20.97   2008-11         18.4
1380    19.46   2008-12         18.2
1380    20.56   2009-01         18.4

挑战

  1. date不是每日结构,有些intervall甚至没有每个月的所有工作日,所以必须每个月使用MAX()日以获得最后一个值等
  2. 如果没有X个月的回顾,平均值必须/必须得到null

2 个答案:

答案 0 :(得分:0)

首先,过滤掉不是本月最后一行的所有行。 然后使用scalar subquery计算移动平均线;带有m3子查询的条件可确保AVG()子查询找不到任何行,如果不存在六个。

WITH months(id, nav, date) AS (
  SELECT id, nav, MAX(date)
  FROM nav
  GROUP BY strftime('%Y-%m', date)
)
SELECT id,
       nav,
       strftime('%Y-%m', date),
       (SELECT AVG(nav)
        FROM months AS m2
        WHERE m2.date BETWEEN date(months.date, 'start of month', '-5 months')
                          AND months.date
          AND (SELECT COUNT(*)
               FROM months AS m3
               WHERE m3.date BETWEEN date(months.date, 'start of month', '-5 months')
                                 AND months.date
              ) = 6
       ) AS average_6m
FROM months;

答案 1 :(得分:0)

"正确"回答这似乎是"不要"。

由于我使用的是sqlite + php,我觉得用PHP做这个更简单更有效,所以我为它创建了一个简单的帮助函数:

/**
*   Moving average calculations
*   @param $arr: array with princing data
*   @param $ma: moving average; no. of rows
*   @param $nav: key for pricing data
*/

function sma( $arr, $ma=6, $nav='nav' ){


    foreach( $arr as $key => $val ){

        $avg = 0;
        $average = 0;

        // check if look-back period, else set 0
        if( $key-$ma > -2 ) {

            // create lookback period
            $range = range(0,$ma-1);

            foreach($range as $r){
                $tmp = $key - $r;
                $avg = $avg + $arr[$tmp][$nav];
            }

            // round with 2 decimal point
            $average = round( ($avg/$ma) * 100 ) / 100;         

        }

        // add to current key
        $newkey = 'sma'.$ma;
        $arr[$key][$newkey] = $average;

    }


    return $arr;

} // sma()

由于我们在PHP中使用数组,因此性能损失可以忽略不计,并且可能少于使用SQLite计算它。

结果屏幕:

enter image description here