Bu soruyu ele almak için gerçek bir örnek vereyim
Ohlc verilerim üzerinde ağırlıklı bir hareketli ortalama hesaplamam gerekiyordu, her biri için bir sembol ile yaklaşık 134000 mumum var
- Seçenek 1 Python / Node vb.
- Seçenek 2 SQL'de yapın!
Hangisi daha iyi?
- Bunu Python'da yapmak zorunda olsaydım, esasen, saklanan tüm kayıtları en kötü şekilde almalıyım, hesaplamayı yapmam ve bence büyük bir IO israfı olan her şeyi geri kurtarmam gerekirdi
- Her yeni mum aldığınızda ağırlıklı hareketli ortalama değişiklikleri, düzenli aralıklarla büyük miktarlarda IO yapacağım anlamına geliyor, bu da benim işaretimde iyi bir fikir değil
- SQL'de tek yapmam gereken, muhtemelen her şeyi hesaplayan ve saklayan bir tetikleyici yazmaktır, bu yüzden her bir çift için her seferinde nihai WMA değerlerini almanız yeterlidir ve bu çok daha verimlidir
Gereksinimler
- Her mum için WMA'yı hesaplamam ve saklamam gerekirse Python'da yapardım
- Ama sadece son değere ihtiyacım olduğundan, SQL Python'dan çok daha hızlı
Size biraz cesaret vermek için, bu ağırlıklı bir hareketli ortalama yapmak için Python sürümüdür
WMA kod yoluyla yapılır
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 ile 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()
İster inanın ister inanmayın , sorgu AĞIRLIKLI HAREKETLİ ORTALAMA yapmanın Pure Python sürümünden daha hızlı çalışır !!!Bu sorguyu yazmaya adım adım gittim, orada durun ve iyi olacaksınız
hız
0.42141127300055814 saniye Python
0.23801879299935536 saniye SQL
Veritabanımda 1000 hisse arasında bölünmüş 134000 sahte OHLC kaydı var, böylece SQL uygulama sunucunuzdan daha iyi performans gösterebilir