# coding: utf-8
# OHLCVデータを取得する期間数
count = 20
# 移動平均期間:n
n = 3
import time, requests
# 現在時刻と取得開始時刻
to_time = int(time.time())
from_time = to_time - count * 60
# OHLCVデータ取得
param = {"period": 1, "from": from_time, "to": to_time}
url = "https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution={period}&from={from}&to={to}".format(**param)
data = requests.get(url).json()
# 終値リスト(最新のcount件数分)
close = data["c"][-count:]
# 確認表示
print(close)
[6379, 6379.5, 6387, 6388, 6388, 6386, 6381, 6386, 6383.5, 6380, 6380, 6378, 6376, 6376, 6375.5, 6376, 6378, 6376, 6374, 6374]
# 係数:a
a = 2 / (n + 1)
# 終値リストの要素数を取得(=count)
length = len(close)
# 設定値確認
print("n =", n)
print("a =", a)
print("length =", length)
n = 3 a = 0.5 length = 20
# 補足説明文リスト(計算式)
messages = []
# EMA計算結果リスト
ema = []
# 最初は1分前がないので終値を設定
ema.append(close[0])
# 結果確認
message = "ema[%2d] = %.2f" % (0, ema[-1])
print(message)
messages.append("---")
# 終値リストの要素数の数だけ繰り返しEMAを順番に計算していく(先頭除く)
for i in range(1, length):
# 現在のEMA = 1分前のEMA+α*(現在の終値-1分前のEMA)
result = ema[-1] + a * (close[i] - ema[-1])
# EMAリストに追加
ema.append(result)
# 結果確認
message = "%.1f + %.1f * (%.1f - %.2f)" % (ema[-2],a,close[i],ema[-2])
print("ema[%2d] = " % i + message + " = %.2f" % result)
messages.append(message)
ema[ 0] = 6379.00 ema[ 1] = 6379.0 + 0.5 * (6379.5 - 6379.00) = 6379.25 ema[ 2] = 6379.2 + 0.5 * (6387.0 - 6379.25) = 6383.12 ema[ 3] = 6383.1 + 0.5 * (6388.0 - 6383.12) = 6385.56 ema[ 4] = 6385.6 + 0.5 * (6388.0 - 6385.56) = 6386.78 ema[ 5] = 6386.8 + 0.5 * (6386.0 - 6386.78) = 6386.39 ema[ 6] = 6386.4 + 0.5 * (6381.0 - 6386.39) = 6383.70 ema[ 7] = 6383.7 + 0.5 * (6386.0 - 6383.70) = 6384.85 ema[ 8] = 6384.8 + 0.5 * (6383.5 - 6384.85) = 6384.17 ema[ 9] = 6384.2 + 0.5 * (6380.0 - 6384.17) = 6382.09 ema[10] = 6382.1 + 0.5 * (6380.0 - 6382.09) = 6381.04 ema[11] = 6381.0 + 0.5 * (6378.0 - 6381.04) = 6379.52 ema[12] = 6379.5 + 0.5 * (6376.0 - 6379.52) = 6377.76 ema[13] = 6377.8 + 0.5 * (6376.0 - 6377.76) = 6376.88 ema[14] = 6376.9 + 0.5 * (6375.5 - 6376.88) = 6376.19 ema[15] = 6376.2 + 0.5 * (6376.0 - 6376.19) = 6376.10 ema[16] = 6376.1 + 0.5 * (6378.0 - 6376.10) = 6377.05 ema[17] = 6377.0 + 0.5 * (6376.0 - 6377.05) = 6376.52 ema[18] = 6376.5 + 0.5 * (6374.0 - 6376.52) = 6375.26 ema[19] = 6375.3 + 0.5 * (6374.0 - 6375.26) = 6374.63
import pandas as pd
# 終値リストをSeries化してEWMの平均を計算
pd_ema = pd.Series(close).ewm(span=n).mean()
display(pd_ema)
0 6379.000000 1 6379.333333 2 6383.714286 3 6386.000000 4 6387.032258 5 6386.507937 6 6383.732283 7 6384.870588 8 6384.183953 9 6382.089932 10 6381.044455 11 6379.521856 12 6377.760713 13 6376.880303 14 6376.190130 15 6376.095064 16 6377.047539 17 6376.523768 18 6375.261881 19 6374.630940 dtype: float64
# 終値リスト、計算式リスト、自作EMAリストをDataFrame化
df = pd.DataFrame([[r[0], r[1], r[2]] for r in zip(close, messages, ema)], columns=["終値", "計算式", "EMA"])
# pandas EMA列を追加
df["pandas EMA"] = pd_ema
# 自作EMAとpandas EMAの差分列を追加
df["差分"] = df["EMA"] - df["pandas EMA"]
# 結果表示
display(df)
終値 | 計算式 | EMA | pandas EMA | 差分 | |
---|---|---|---|---|---|
0 | 6379.0 | --- | 6379.000000 | 6379.000000 | 0.000000 |
1 | 6379.5 | 6379.0 + 0.5 * (6379.5 - 6379.00) | 6379.250000 | 6379.333333 | -0.083333 |
2 | 6387.0 | 6379.2 + 0.5 * (6387.0 - 6379.25) | 6383.125000 | 6383.714286 | -0.589286 |
3 | 6388.0 | 6383.1 + 0.5 * (6388.0 - 6383.12) | 6385.562500 | 6386.000000 | -0.437500 |
4 | 6388.0 | 6385.6 + 0.5 * (6388.0 - 6385.56) | 6386.781250 | 6387.032258 | -0.251008 |
5 | 6386.0 | 6386.8 + 0.5 * (6386.0 - 6386.78) | 6386.390625 | 6386.507937 | -0.117312 |
6 | 6381.0 | 6386.4 + 0.5 * (6381.0 - 6386.39) | 6383.695312 | 6383.732283 | -0.036971 |
7 | 6386.0 | 6383.7 + 0.5 * (6386.0 - 6383.70) | 6384.847656 | 6384.870588 | -0.022932 |
8 | 6383.5 | 6384.8 + 0.5 * (6383.5 - 6384.85) | 6384.173828 | 6384.183953 | -0.010125 |
9 | 6380.0 | 6384.2 + 0.5 * (6380.0 - 6384.17) | 6382.086914 | 6382.089932 | -0.003018 |
10 | 6380.0 | 6382.1 + 0.5 * (6380.0 - 6382.09) | 6381.043457 | 6381.044455 | -0.000998 |
11 | 6378.0 | 6381.0 + 0.5 * (6378.0 - 6381.04) | 6379.521729 | 6379.521856 | -0.000127 |
12 | 6376.0 | 6379.5 + 0.5 * (6376.0 - 6379.52) | 6377.760864 | 6377.760713 | 0.000151 |
13 | 6376.0 | 6377.8 + 0.5 * (6376.0 - 6377.76) | 6376.880432 | 6376.880303 | 0.000129 |
14 | 6375.5 | 6376.9 + 0.5 * (6375.5 - 6376.88) | 6376.190216 | 6376.190130 | 0.000086 |
15 | 6376.0 | 6376.2 + 0.5 * (6376.0 - 6376.19) | 6376.095108 | 6376.095064 | 0.000044 |
16 | 6378.0 | 6376.1 + 0.5 * (6378.0 - 6376.10) | 6377.047554 | 6377.047539 | 0.000015 |
17 | 6376.0 | 6377.0 + 0.5 * (6376.0 - 6377.05) | 6376.523777 | 6376.523768 | 0.000009 |
18 | 6374.0 | 6376.5 + 0.5 * (6374.0 - 6376.52) | 6375.261889 | 6375.261881 | 0.000007 |
19 | 6374.0 | 6375.3 + 0.5 * (6374.0 - 6375.26) | 6374.630944 | 6374.630940 | 0.000004 |
EMAは前期間の値を使って連続的に計算します。
初回の値の設定により、計算値に差が生じる可能性がありますが、
繰り返し計算していくことで差は縮小していきます。
処理時間を計測
# 終値リスト件数
count = 10000
# 現在時刻と取得開始時刻
to_time = int(time.time())
from_time = to_time - count * 60
# OHLCVデータ取得
param = {"period": 1, "from": from_time, "to": to_time}
url = "https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution={period}&from={from}&to={to}".format(**param)
data = requests.get(url).json()
# 終値リスト(最新のcount件数分)
close = data["c"][-count:]
# 自作EMA計算
def ema(lst, term):
ret = []
a = 2 / (term + 1)
ret.append(lst[0])
for i in range(1, length):
result = ret[-1] + a * (lst[i] - ret[-1])
ret.append(result)
return ret
# pandas EMA計算
def pd_ema(lst, term):
return pd.Series(lst).ewm(span=term).mean()
# 自作EMA計測
%timeit ret = ema(close, n)
# pandas EMA計測
%timeit ret = pd_ema(close, n)
# 自作EMA計算時間計測
#start = time.perf_counter()
#ret = ema(close, n)
#elapsed_time = time.perf_counter() - start
#print("[自作EMA] processing time : %.5f[ms]" % (elapsed_time * 1000))
# pandas EMA計算時間計測
#start = time.perf_counter()
#ret = pd_ema(close, n)
#elapsed_time = time.perf_counter() - start
#print("[pandas EMA] processing time : %.5f[ms]" % (elapsed_time * 1000))
6.11 µs ± 93.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 2.43 ms ± 20.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)