5

我可以使用一些帮助(最好是虚拟指南)来更新下表:

CREATE TABLE `SYMBOL` (
  `day` date NOT NULL,
  `open` decimal(8,3) DEFAULT NULL,
  `high` decimal(8,3) DEFAULT NULL,
  `low` decimal(8,3) DEFAULT NULL,
  `close` decimal(8,3) DEFAULT NULL,
  `volume` bigint(20) DEFAULT NULL,
  `adj_close` decimal(8,3) DEFAULT NULL,
  `moving_average` decimal(8,3) DEFAULT NULL,
  PRIMARY KEY (`day`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

现在,moving_average 列是空的。所有其他列都已填充(暂时,我可以接受这是“静态的”,它不需要在我添加行时更新 - 尽管如果这很容易做到,那就太好了)。这是我希望计算的 20 天移动平均线。

我已尽我所能执行此处的步骤:

如何使用 MySQL 计算移动平均线?

我的查询是这样的:

SELECT
     `close`,
     (
     SELECT
          AVG(`close`) AS moving_average
     FROM
          SYMBOL T2
     WHERE
          (
               SELECT
                    COUNT(*)
               FROM
                    SYMBOL T3
               WHERE
                    `day` BETWEEN T2.day AND T1.day
          ) BETWEEN 1 AND 20
     )
FROM
     SYMBOL T1

我是否正确修改了查询?将结果写入moving_average 列需要做什么?

当我运行上述内容时,没有任何反应(它说它正在运行,没有错误,让它运行很长时间后我才停止它)。列moving_average 仍然有NULL 值。

我还看了这个答案: 如何在 MySQL 中计算多个移动平均线

但是,我不确定我需要对我的表的回复进行什么更改。

任何帮助表示赞赏。

4

2 回答 2

2

有两种方法可以做到这一点:

  1. 创建一个update更新表中每一行的查询
  2. 创建一个完成这项工作的存储过程

我个人更喜欢选项2:

delimiter $$
create procedure movingAvg()
begin
    declare mv double;
    declare t date;
    declare done int default false;
    declare cur_t cursor for
         select distinct day from symbol
         order by day;
    declare cur_mv cursor for
         select avg(close) from symbol
         where day between date_add(t, interval -19 day) and t;
         -- Here you define the interval of your MV.
         -- If you want a 20-day MV, then the interval is between t-19 and t
    declare continue handler for not found set done=true;

    open cur_t;
    loop_day: loop
        fetch cur_t into t;
        if not done then
            open cur_mv;
            fetch cur_mv into mv;
            close cur_mv;
            update SYMBOL
                set moving_average = mv
                where day=t;
        else
            leave loop_day;
        end if;
    end loop loop_day;
    close cur_t;
end;
delimiter ;
于 2012-10-21T13:56:49.783 回答
0

这是一个可能的解决方案:

update SYMBOLS
from (
   select a.day
        , avg(b.close) as moving_average
   from   SYMBOLS a
   cross join SYMBOLS b
   where b.day BETWEEN date_sub(a.day, INTERVAL 19 DAY) and a.day
      and a.moving_average is null
   group by a.day
   ) x
set moving_average=x.moving_average
where SYMBOLS.day=x.day

对不起,我自己不使用 mysql,所以我猜测日期算术语法。我添加了一个条件,只更新你moving_average为空的行。

UPDATE: Be sure you understand that this solution is based on a 365-day calendar. Most stock market averages like "20-day" or "30-day" are based on a trading calendar which excludes weekends and holidays. You would need to create a trading calendar table youself (a simple list of all trade dates). If you want to do that, you might want to ask a new question to that effect.

于 2012-10-21T17:06:13.190 回答