【问题标题】:MYSQL: 30 day moving average stock pricesMYSQL:30天移动平均股价
【发布时间】:2015-09-19 21:36:42
【问题描述】:

目标选择每只股票最近30个交易日的平均收盘价,基于输入日期而不是最新日期

鉴于此;

1) 如果输入日期为 2015-09-18,选择最近 30 个交易日的平均收盘价,例如: (2015-09-18, 2015-09-17, 2015-09-16,...30天)

2) 如果输入日期为 2015-09-01,选择最近 30 个交易日的平均收盘价,例如: (2015-09-01, 2015-09-31, 2015-09-28,...30天)

3) 表格列:ticker |代码 |日期 |开放|高 |低 |关闭 |音量

4) 表格仅包含 TRADING 日的记录,不包括周末和节假日

5) 对于每只股票,都有数千天的记录,但我们只需要任何给定时间点的 30 天均线

Input date: 2015-09-01
Desired output

date     | ticker | code |  30 day average closing price 
2015-09-01  AAA    1122     1.33
2015-09-01  BBB    3344     0.79
... 
...
...and so on for each stock

【问题讨论】:

    标签: mysql


    【解决方案1】:

    作为起点,请参阅https://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_date-add 这些函数。应该像(未测试):

    SELECT `date`, ticker, avg(`close`) from TRADES where
    date <= '2015-09-01' and date >= DATE_SUB('2015-09-01', INTERVAL 30 DAY)
    GROUP BY ticker
    

    【讨论】:

    • 只有在每一天都是交易日时才有效。我不这么认为。
    • 谢谢亚历克斯,但这不起作用,因为该表只存储交易日。日期分项将考虑周末,因此减去 30 天将导致少于 30 天
    • 经过 10 多个小时的研究,我发现了如何按照我想要的方式进行操作,但查询执行速度太慢。最后,我选择了第二个最佳选择,即运行 date sub 40 多天,我将得到 +/- 30 天,这已经足够了。谢谢阿克塞尔
    【解决方案2】:

    编辑 这个版本应该是灵活的,我希望不要太慢。由于不知道表中的内容以及表的名称是什么意思,我假设一个表价格表,代码='AAA','BBB' 等等,close 表示价格。您给定的日期应该是“2015-09-12”。用你喜欢的任何东西替换“2015-09-12”。

    30 应该是交易天数。用'limit 30'中的任何你想要的替换。

    股票代码 |代码 |日期 |开放|高 |低 |关闭 |音量

    试试这个版本

    select pt.code, sum(pt.close) / count(*) as average
    from pricetable pt 
    inner join 
      ( select distinct `date`
        from pricetable 
        where `date` <= '2015-09-12' # your given date
        order by `date` desc 
        limit 30 # the number of trading days
      ) as  d on d.`date` = pt.`date`
    where code in ("AAA","BBB","CCC")
    group by code
    order by average desc;
    

    如果子选择太慢,请使用后面的一些版本。

    您绝对应该制作一个包含日历日的表格,并且他们会得到一个列来标记交易日。如果它们还包含对 30 天前和 90 天前的引用会容易得多。

     create table calendar_days 
     (
        id int(11) not null auto_increment primary key, 
        calday date not null, 
        is_trading tinyint, 
        trading_before_30 date, 
        trading_before_90 date
     );
    

    然后就简单了:

    select pt.stockname, sum(pt.closing_price) / count(*) as avg_close
    from calendar_days d
    inner join pricetable pt on pt.day between d.calday and d.trading_before_30
    where d.calday = '2015-08-15'
    group by pt.stockname;
    

    您可以从股票表中轻松填写日历日表。

    编辑:这样您可以在当天的第一次请求时填写它,假设只有个交易日在此表中。

    insert into calendar_days (calday, is_trading) 
    select distinct day, 1
    from pricetable pt 
    where pt.day > (select max(calday from calendar_days);
    
    update calendar_days d1 
    inner join calendar_days d2 on d2.nr = d1.nr - 29
    set d1.trading_before_30 = d2.calday 
    where d1.trading_before_30 is null;
    

    您当然可以尝试从您的股票价格表中动态构建最近 30 个交易日的列表,但是该表每天有很多条目,因此这会不必要地减慢您的查询速度 - 日期会发生变化很少,每天只有一次。

    您甚至可以在结束日表中添加一个触发器,以便在每次插入时检查是否要重新填写日历日。

    没有该表的版本如下所示:

    drop temporary table if exists tmp_days;
    create temporary table tmp_days (tradingday date not null primary key);
    insert into tmp_days 
    select distinct `day` 
    from pricetable 
    where day <= '2015-08-15'
    order by day desc limit 30;
    

    然后

    select pt.stockname, sum(pt.price) / count(*) as average
    from pricetable pt 
    inner join tmp_days d on d.tradingday = pt.day;
    

    临时表仅在一个连接中可见。

    【讨论】:

    • flaschenpost,谢谢,但是这行不通,最好只存储交易日,因为这样更容易维护表格。并非所有假期都是提前知道的,有时可能会有临时假期
    • 我到目前为止:SELECT * FROM dailydata WHERE date
    • @user6890 我添加了没有固定表的临时表版本,但这会减慢一点。我什至可以将其合并到子选择中。
    • flaschenpost,如果我要制作变体而不是 30MA..我需要 23 MA....而不是接近 MA,则解决方案不是那么灵活,我可能需要成交量 MA。 .. 但是.. 我从这里找到了部分解决方案:sqlines.com/mysql/how-to/get_top_n_each_group 该页面仍有 1 个问题.. 这是这一行: country_rank := IF(current_country = country, country_rank + 1, 1) AS country_rank, current_country 始终为 NULL,这导致 country_rank 始终为 1。如果您可以帮助我从链接中解决问题,我将获得最终解决方案来分享
    • @user6890 我喜欢变量,我只是不明白为什么这里需要它们。您的请求大约是给定日期的最后 30 天的平均值。你需要它来列出几天吗?我的意思是一只股票,以及几个连续日期的移动平均线?然后我会选择变量,但只有这样。
    猜你喜欢
    • 1970-01-01
    • 2023-01-30
    • 2021-04-19
    • 1970-01-01
    • 2016-11-30
    • 1970-01-01
    • 2011-06-29
    • 2020-10-03
    • 1970-01-01
    相关资源
    最近更新 更多