この質問に取り組むために実際の例を挙げましょう
ohlcデータの加重移動平均を計算する必要がありました。計算するために、それぞれに記号が付いた約134000のキャンドルがあります。
- オプション1 Python / Nodeなどで実行する
- オプション2 SQL自体で実行する!
どちらがいいですか?
- 私がこれをPythonで行う必要がある場合、基本的に、最悪の場合はすべての保存されたレコードをフェッチし、計算を実行してすべてを保存する必要があります。
- 新しいキャンドルを取得するたびに加重移動平均が変化することは、定期的に大量のIOを実行することを意味しますが、これは私の兆候ではありません
- SQLでは、おそらくすべてを計算して保存するトリガーを作成するだけでよいので、時々、各ペアの最終WMA値をフェッチするだけで済み、それがはるかに効率的です。
必要条件
- すべてのキャンドルのWMAを計算して保存する必要がある場合は、Pythonで計算します
- しかし、最後の値しか必要ないため、SQLはPythonよりもはるかに高速です。
励ましを与えるために、これは加重移動平均を実行するPythonバージョンです
WMAはコードで実行
import psycopg2
import psycopg2.extras
from talib import func
import timeit
import numpy as np
with psycopg2.connect('dbname=xyz user=xyz') as conn:
with conn.cursor() as cur:
t0 = timeit.default_timer()
cur.execute('select distinct symbol from ohlc_900 order by symbol')
for symbol in cur.fetchall():
cur.execute('select c from ohlc_900 where symbol = %s order by ts', symbol)
ohlc = np.array(cur.fetchall(), dtype = ([('c', 'f8')]))
wma = func.WMA(ohlc['c'], 10)
# print(*symbol, wma[-1])
print(timeit.default_timer() - t0)
conn.close()
SQLによるWMA
"""
if the period is 10
then we need 9 previous candles or 15 x 9 = 135 mins on the interval department
we also need to start counting at row number - (count in that group - 10)
For example if AAPL had 134 coins and current row number was 125
weight at that row will be weight = 125 - (134 - 10) = 1
10 period WMA calculations
Row no Weight c
125 1
126 2
127 3
128 4
129 5
130 6
131 7
132 8
133 9
134 10
"""
query2 = """
WITH
condition(sym, maxts, cnt) as (
select symbol, max(ts), count(symbol) from ohlc_900 group by symbol
),
cte as (
select symbol, ts,
case when cnt >= 10 and ts >= maxts - interval '135 mins'
then (row_number() over (partition by symbol order by ts) - (cnt - 10)) * c
else null
end as weighted_close
from ohlc_900
INNER JOIN condition
ON symbol = sym
WINDOW
w as (partition by symbol order by ts rows between 9 preceding and current row)
)
select symbol, sum(weighted_close)/55 as wma
from cte
WHERE weighted_close is NOT NULL
GROUP by symbol ORDER BY symbol
"""
with psycopg2.connect('dbname=xyz user=xyz') as conn:
with conn.cursor() as cur:
t0 = timeit.default_timer()
cur.execute(query2)
# for i in cur.fetchall():
# print(*i)
print(timeit.default_timer() - t0)
conn.close()
信じられないかもしれませんが、クエリは、重み付け移動平均を実行するPure Pythonバージョンよりも高速に実行されます!!! 私はそのクエリを書くために一歩一歩進んだので、そこにぶらさげればうまくいくでしょう
速度
0.42141127300055814秒Python
0.23801879299935536秒のSQL
データベースに134000の偽のOHLCレコードがあり、1000株に分割されています。これは、SQLがアプリサーバーよりも優れている例です。