2012-10-21 19 views
5

ho potuto usare qualche aiuto (preferibilmente una guida fittizio) per aggiornare la tabella seguente:Il calcolo e la tabella di aggiornamento con media mobile di chiusura corsi azionari MYSQL

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; 

La colonna moving_average è ora vuota. Tutte le altre colonne sono popolate (per il momento, sto bene con questo essere "statico", non ha bisogno di aggiornare mentre aggiungo le righe - anche se se è facile farlo, sarebbe grandioso). È una media mobile di 20 giorni che spero di calcolare.

Ho provato eseguendo i passaggi qui al meglio delle mie capacità:

How do I calculate a moving average using MySQL?

La mia domanda è questa:

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 

Avere ho modificato correttamente la domanda? Cosa deve essere fatto per scrivere i risultati nella colonna moving_average?

Quando eseguo quanto sopra, non succede nulla (dice che è in esecuzione, senza errori, dopo averlo lasciato funzionare per un lungo periodo l'ho appena interrotto). La colonna moving_average ha ancora valori NULL.

Ho anche guardato questa risposta: How to calculated multiple moving average in MySQL

Tuttavia, io sono sicuro di cosa ho bisogno per modificare la risposta per il mio tavolo.

Qualsiasi aiuto è apprezzato.

+2

La dichiarazione che hai postato non contiene alcuna dichiarazione di aggiornamento. Solo una selezione. Naturalmente, questo significa che nulla verrà aggiornato. – SchmitzIT

risposta

2

Ci sono due modi per farlo:

  1. Creare una query di update che aggiorna ogni riga nella tabella
  2. Creare una stored procedure che fa il lavoro

Io personalmente preferisco l'opzione 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 ; 
+0

Grazie a Barranka - Ho copiato e incollato questo e ho tentato di eseguirlo. Il risultato era "Query was empty". Ho anche fatto "mostrare lo stato della procedura" ed era vuoto. Dovrei modificare ulteriormente? Ad ogni modo, grazie per l'aiuto! – gcubed

+0

@ user1644609 potrebbe essere necessario controllare che io abbia scritto tutto correttamente (penso di non aver sbagliato, ma c'è sempre la possibilità che mi sia sfuggito qualcosa), e quindi controllare il tuo tavolo ... i calcoli sono corretti? – Barranka

+0

Ho provato a "debuggarlo", ma sinceramente non so se è corretto o meno. Ne ho giocato un po '(e continuerò a) ma non sono stato in grado di creare la stored procedure, né di inserire la data nella colonna moving_average. Ma grazie per avermi messo su una pista. – gcubed

0

Ecco una possibile soluzione:

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 

Mi spiace di non utilizzare mysql da solo, quindi suppongo che la sintassi aritmetica delle date. E ho aggiunto una condizione per aggiornare solo le righe in cui il tuo moving_average è nullo.

AGGIORNAMENTO: Assicurarsi di comprendere che questa soluzione è basata su un calendario di 365 giorni. La maggior parte delle medie del mercato azionario come "20 giorni" o "30 giorni" sono basate su un calendario commerciale che esclude i fine settimana e le vacanze. Dovresti creare una tabella del calendario di trading (un semplice elenco di tutte le date commerciali). Se vuoi farlo, potresti voler fare una nuova domanda in tal senso.