%matplotlib inline
import numpy as np
import pandas as pd
from pandas import DataFrame, Series
import matplotlib.pyplot as plt
from matplotlib import style
style.use('ggplot')
hst_path = 'USDJPY5.hst'
with open(hst_path, 'rb') as f:
dtype = [('Time','u8'), ('Open','f8'), ('High','f8'), ('Low','f8'),
('Close','f8'), ('Volume','i8'), ('s','i4'), ('r','i8')]
df = pd.DataFrame(np.frombuffer(f.read()[148:], dtype=dtype).astype(dtype[:-3]))
df = df.set_index(pd.to_datetime(df['Time'], unit='s')).drop('Time', axis=1)
print(len(df))
df['Close'].resample('D').last().dropna().plot(figsize=(15,5))
ret = df['Close'].pct_change().fillna(0).apply(np.log1p)
ret0930_0955 = ret[(ret.index.hour==9) & (ret.index.minute>=30)]
ret0930_0955.cumsum().plot(figsize=(15,5))
もう少し細かく見てみる
09:30からの5分間隔の足別に見てみる
for m in np.unique(ret0930_0955.index.minute):
ret0930_0955[ret0930_0955.index.minute==m].cumsum().plot(figsize=(15,5))
plt.legend(np.unique(ret0930_0955.index.minute), loc='best', fontsize=12)
たぶん仲値の影響ですね(´・ω・`)
ついでにゴトー日の09:30~09:50部分とそうでないときのも見てみましょう
※青ラインがゴトー日、赤がそうでない日で、標本数で割った値を累積してます
ret_5_10 = ret[(ret.index.day%5==0) & (ret.index.hour==9) &
(ret.index.minute>=30) & (ret.index.minute<55)]
ret_no_5_10 = ret[~(ret.index.day%5==0) & (ret.index.hour==9) &
(ret.index.minute>=30) & (ret.index.minute<55)]
(ret_5_10/len(ret_5_10)).cumsum().plot(figsize=(15,3), c='b')
(ret_no_5_10/len(ret_no_5_10)).cumsum().plot(figsize=(15,3), c='r')
plt.legend(['5,10', 'no 5,10'], loc='best', fontsize=14)
plt.show()
ret0930_0950 = ret[(ret.index.hour==9) & (ret.index.minute>=30) & (ret.index.minute<55)]
ret0930_0950.groupby(ret0930_0950.index.day).mean().plot.bar(figsize=(15,3))
2016くらいからはっきりしてる感じはあるけどそれ以前は大差無い感じ?
ret0930_0955[ret0930_0955.index.minute<55].cumsum().plot(figsize=(15,5))
ret0930_0955[ret0930_0955.index.minute>=55].cumsum().plot(figsize=(15,5))
前回の記事で作ったおもちゃテスターでバックテストしてみます
09:30にLして09:55にドテンして10:00でSを決済します
class Tester(object):
def __init__(self, df):
self.I,_=df.index.values,[setattr(self,c[0],df[c].values)for c in df.columns]
def run(S):
P,T,V,r,(ob,os,cb,cs)=0,0,0,[],[(getattr(S,a))for a in['ob','os','cb','cs']]
for i in range(len(S.I)-1):
if(P==1and cb[i])or(P==-1and cs[i]):P=r.append([P,T,V,S.I[i+1],S.O[i+1]])
if not P:P,T,V=(1if ob[i]else-1if os[i]else None),S.I[i+1],S.O[i+1]
return DataFrame(r+([[P,T,V,S.I[-1],S.O[-1]]]if P else[]),None,'P ot op ct cp'.split())
class Test(Tester):
def __init__(self, df):
super(Test, self).__init__(df)
hour = df.index.hour
minute = df.index.minute
# サインの次の足の始値でエントリするので25分、50分でサインを出して
# 30分, 55分でエントリするようにします
self.ob = (hour==9) & (minute==25)
self.os = (hour==9) & (minute==50)
self.cb = self.os
self.cs = (hour==9) & (minute==55)
spread = 0.00
res = Test(df).run()
res = Series((((res['cp']-res['op'])*res['P']-spread).values),
index=pd.to_datetime(res['ct'],unit='ns'))
print(len(res))
print(res.sum())
res.cumsum().plot(figsize=(15,5))
ふむふむプラスです(´・ω・`)
とはいえこれはスプレッドを加味していない結果なので
上の例だと5270回分のスプレッドコストを引いてやらないといけないので
これだけじゃ微妙ですね
buy = Series((df['Open'][(df.index.hour==9)&(df.index.minute==55)].values) -
(df['Open'][(df.index.hour==9)&(df.index.minute==30)].values),
index = df.index[(df.index.hour==9)&(df.index.minute==55)])
sell = Series((df['Open'][(df.index.hour==9)&(df.index.minute==55)].values) -
(df['Open'][(df.index.hour==10)&(df.index.minute==0)].values),
index = df.index[(df.index.hour==10)&(df.index.minute==0)])
pd.concat([buy, sell]).sort_index().cumsum().plot(figsize=(15,5))
東京時間全体の値動きで見ると ↓ こんな感じ(´・ω・`)
ret[(ret.index.hour>=9) & (ret.index.hour<15)].cumsum().plot(figsize=(15,5))
クリスマスあたりにいくつか15:00の欠損値があったので
こんな感じで集計
tk_sell = pd.concat([df['Open'][(df.index.hour==9)&(df.index.minute==0)],
df['Open'][(df.index.hour==15)&(df.index.minute==0)]],
axis=1, keys=['entry', 'exit'])
tk_sell.index = pd.to_datetime(tk_sell.index.date)
tk_sell['entry'] = tk_sell['entry'].shift()
tk_sell.dropna(inplace=True)
tk_sell['profit'] = tk_sell['entry']-tk_sell['exit']
print(len(tk_sell))
print(tk_sell['profit'].sum())
tk_sell['profit'].cumsum().plot(figsize=(15,5))
class Test2(Tester):
def __init__(self, df):
super(Test2, self).__init__(df)
hour = df.index.hour
minute = df.index.minute
self.ob = (hour==9) & (minute==25)
self.os = (hour==9) & (minute==50)
self.cb = self.os
self.cs = ((hour>=14)&(minute>=55)) | ((hour<9)|(hour>15))
spread = 0.00
%time res = Test2(df).run()
res = Series((((res['cp']-res['op'])*res['P']-spread).values),
index=pd.to_datetime(res['ct'],unit='ns'))
print(len(res))
print(res.sum())
print(res.sum()/len(res))
res.cumsum().plot(figsize=(15,5))
10年くらいで12700pipsになりましたが
1トレードあたりの平均は2.4pipsでスプレッドを考えると
スプ狭めの業者でも1トレードあたり2pipsくらいでしょうか
まぁもうちょっと手を加えればもう少し良くなりそうですね
今回のものは仲値と東京時間の傾向を利用した戦略ですが、
こういうアノマリーを軸にするとインジケータを組み合わせてどうにかしたものよりは
賞味期限が長いかもしれませんね
東京時間に限らず各市場の時間の特徴というのはあるので
そういうのを組み合わせてやってみるのも面白いです
たとえばkuchartの市場別の時間帯の累積値ではっきり特徴があるもので組み合わせて
通貨ペアを選択してその市場の時間に合った方向のポジションをとるようにするとかね(´・ω・`)