尝试使用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
date
不是每日结构,有些intervall甚至没有每个月的所有工作日,所以必须每个月使用MAX()日以获得最后一个值等null
答案 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计算它。
结果屏幕: