이 질문을 해결하기 위해 실제 예를 들어 보겠습니다.
내 ohlc 데이터에 대한 가중 이동 평균을 계산해야했으며, 각각에 대한 기호가있는 약 134000 개의 양초가 있습니다.
- 옵션 1 Python / Node 등에서 수행
- 옵션 2 SQL 자체로 수행하십시오!
어느 것이 더 낫습니까?
- 파이썬 에서이 작업을 수행해야한다면 본질적으로 최악의 경우 모든 저장된 레코드를 가져 와서 계산을 수행하고 모든 것을 다시 저장해야합니다. 내 의견으로는 IO의 막대한 낭비입니다.
- 새로운 양초를 얻을 때마다 가중 이동 평균 변화는 정기적 인 간격으로 엄청난 양의 IO를 수행한다는 것을 의미합니다.
- SQL에서해야 할 일은 아마도 모든 것을 계산하고 저장하는 트리거를 작성하는 것입니다. 따라서 각 쌍의 최종 WMA 값을 매번 가져와야하므로 훨씬 효율적입니다.
요구 사항
- 모든 촛불에 대해 WMA를 계산하고 저장해야한다면 파이썬에서 할 것입니다.
- 그러나 마지막 값만 필요하므로 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()
믿거 나 말거나 , 쿼리는 WEIGHTED MOVING AVERAGE를 수행하는 순수 Python 버전보다 빠르게 실행됩니다 !!! 나는 그 쿼리를 작성하는 단계적으로 갔으므로 거기에 매달 아라. 그러면 잘 할 것이다.
속도
0.42141127300055814 초 파이썬
0.23801879299935536 초 SQL
내 데이터베이스에 134000 개의 가짜 OHLC 레코드가 1000 개 주식으로 나누어 져 있으므로 SQL이 앱 서버를 능가하는 예입니다.