1

私のDBには数十万行あります。株式または外国為替の RSI を計算しようとしています。

の式RSI(14)は次のとおりです。

100 - (100 / 1 + RS )

RS は平均利得 / 平均損失です。

この数式は、過去 14 行 (現在の行を含む) を振り返り、利益 (または上昇) があった行の値を平均し、その平均を損失があった行の平均で割ります。

私が MySQL で抱えている問題は、前の 14 行の平均ゲインと平均損失を選択することです。これはエクセルで簡単にできます。Excel で、利益または損失があったかどうかを分析する列を作成し、それを使用しますAVERAGEIF(Range,Criteria,Average_Range)。全く問題無い。しかし、Excel は、分析しなければならない膨大な数の行では機能しません。

私は次のようなことを考えました:

SELECT *, 
       id, 
       (SELECT 10000 * Avg(close - open) 
        FROM   `2011` 
        WHERE  id <= 25 
               AND id >= ( 25 - 13 ) 
               AND ( close - open ) >= 0) / (SELECT 10000 * Avg(open - close) 
                                             FROM   `2011` 
                                             WHERE  id <= 25 
                                                    AND id >= ( 25 - 13 ) 
                                                    AND ( open - close ) > 0) 
FROM   `2011` 
LIMIT  50 

制限 50 は、扱いやすい状態に保つためのものです。しかし、これは私がやりたいことをしません。数学の部分は適切に実行されますが、すべての行で同じ数が繰り返されます。

したがって、行 25 にある場合は、行 12 から 25 を調べます。次に、行 26 については、行 13 から 26 を調べます。これは、各行の新しい番号になります。代わりに、上記の SELECT ステートメントは、最後の列で同じ数値を繰り返します。これは、他のすべてのものとは異なる範囲を持っているため、行ごとに異なるはずです。

4

2 に答える 2

1

以下は、クエリを表現する簡単な方法です。

select t.*,
        100 - (100 / (1 + avg(case when close - open > 0 then close - open end)/avg(case when open - close > 0 then open - close end))
              ) as RS14
 from `2011` t join
      `2011` t2
      on t2.id between t.id - 14 and t
group by t.id

速くなるとは断言できませんが、そうなるかもしれません。id にもインデックスが必要です。

このような機能が本当に必要な場合、データベースを切り替えることはできますか? SQL Server 2012、Oracle、および Postgres はすべて、このタイプのクエリで機能する累積合計機能を提供します。

私はこの問題について考えてきましたが、クエリを効率的に実行できます。おそらく、より苦痛な方法は、明示的な結合を使用することです。

select
from `2011` t0 join
     `2011` t1
     on t0.id = t1.id + 1 join
     `2011` t2
     on t0.id = t1.id + 2 join
     . . .
     2011` t13
     on t0.id = t13.id + 13

さまざまなテーブルの 14 個の変数を使用して、必要な式を作成する必要があります。ただし、これは id のインデックスを効率的に使用し、高速である必要があります (おそらく、書き込みよりも実行の方が高速です)。

もう 1 つの方法は、14 番目ごとの値を非常に簡単に取得できるという観察から始まります。

select ((t.id-1) div 14)*14,
       100 - (100 / (1 + avg(case when close - open > 0 then close - open end)/avg(case when open - close > 0 then open - close end))           
from `2011` t
group by ((t.id-1) div 14)

表現が正確ではないかもしれません。アイデアは、集約を使用して 14 行をグループ化することです。

これで、次のようにして中間行を取得できます。

select (((t.id-1 + offset) div 14))*14+offset,
       100 - (100 / (1 + avg(case when close - open > 0 then close - open end)/avg(case when open - close > 0 then open - close end))           
from `2011` t cross join
     (select 0 as offset union all select 1 union all . . .
      select 13
     ) offsets
group by (((t.id-1 + offset) div 14))*14+offset

これにより、cross join間に行が取得されます。

これらの最後の 2 つのいずれかが非常にうまく機能するはずです。group by作成、保守、および変更が簡単なため、私は解決策を選びます。

于 2013-02-01T21:06:22.057 に答える
0

問題は、MySQL がスプレッドシートが行うことを自動的に行わないことです。これはid、外側のクエリに応じてサブクエリを調整することです。

次のような相関サブクエリが必要です。

SELECT A.*, A.id,
        (SELECT 10000 * AVG(B.close - B.open)
         FROM `2011` B
         WHERE B.id <= A.id
               AND B.id >= ( A.id - 13 )
               AND (B.close - B.open) >= 0 / (SELECT 10000 * AVG(C.open - C.close)
                                              FROM `2011` C
                                              WHERE C.id <= A.id
                                                    AND C.id >= (A.id - 13)
                                                    AND (C.open - C.close) > 0)
 FROM `2011` A
 LIMIT 50
于 2013-02-01T20:25:04.427 に答える