イベントとディレクション (2017/08/06)

イベントの発生がディレクションにどのような影響を与えるかを調べてみる。

ここでは急騰、または急落が起きた時にイベントが発生したと考えることにする。イベントが発生した後の24時間でディレクションが上か下かを見てみる。

調べる前では①イベントの発生がトレンドを生んで急騰なら上、急落なら下、あるいは②反動で急騰なら下、急落なら上、のどちらかだろうかと予測していた。だが、いずれでもなかったようである。

検証

それでは検証してみる。

①この記事で使うライブラリをインポートする。

import forex_system as fs
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime

②設定を読み込む。

fs.remove_folder('temp')

timeframe = 5
start = datetime.strptime('2014.01.01 00:00', '%Y.%m.%d %H:%M')
end = datetime.strptime('2016.12.31 23:59', '%Y.%m.%d %H:%M')
n = 288
threshold = 2.0

ここでは5分足を使用し、期間は2014年初から2016年末までである。

③検証を実行し、グラフを表示する。

time = np.arange(n)
up = np.zeros(n)
down = np.zeros(n)
event = np.zeros([n, 3])
plt.figure(figsize=(6, 12))
cnt = 0
for symbol in ['EURJPY', 'EURUSD', 'USDJPY']:
    plt.subplot(3, 1, cnt+1)
    roc = fs.i_roc(symbol, timeframe, 1, 0)[start:end]
    mean = roc.rolling(window=n).mean()
    std = roc.rolling(window=n).std()
    z = (roc-mean) / std
    for i in range(n):
        up[i] = (roc-roc.mean())[z.shift(1+i)>=threshold].mean()
        down[i] = (roc-roc.mean())[z.shift(1+i)<=-threshold].mean()
    up = np.cumsum(up)
    down = np.cumsum(down)
    plt.plot(time, up, label='up')
    plt.plot(time, down, label='down')
    plt.title('Event and Direction (' + symbol + ')')
    plt.xlabel('Hour')
    plt.ylabel('Cumulative ROC')
    plt.legend()
    plt.xlim(0, 288)
    plt.ylim(-0.03, 0.01)
    plt.xticks([0, 48, 96, 144, 192, 240, 288], [0, 4, 8, 12, 16, 20, 24])
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.tight_layout()
    cnt += 1
plt.savefig('event_and_direction.png', dpi=150)
plt.show()

fs.remove_folder('temp')

通貨ペアはEURJPY、EURUSD、USDJPYを使用した。ROCを直近24時間の平均と標準偏差で正規化し、+2.0以上で急騰、-2.0以下で急落と見なすことにした。また、ROCの全期間の平均を減じてトレンドを除去している。

グラフを見ると、当初の予想とは違い、いずれの通貨ペアでも急騰、急落を問わずイベント発生後の24時間では下落の傾向があるように見える。

解釈

なぜこのような結果になるのか分からないが、ポジションの偏りが関係しているのだろうかと想像している。

ポジションは数カ月、または数年に渡ってロング、またはショートに偏った状態が継続することがよくある。これはスワップ狙いの長期保有者や中長期的な観点から売買を行うヘッジファンドなどの存在によるのだろう。

中長期的な保有者にすれば、急騰、または急落といったボラティリティの拡大はリスクの拡大となる。そしてリスクの拡大はポジションの解消につながるだろう。

したがって、ポジションがロングに偏っている場合、ポジションの解消は売りとなり、下落する傾向を持つ。逆にポジションがショートに偏っている場合、ポジションの解消は買いとなり、上昇する傾向を持つ、というわけである。

もちろん、これは単なる想像であって何の根拠もない。もっと厳密な検証が必要だ。

仲値とリターン

仲値がリターンにどのような影響を与えるかを調べてみる。仲値の時間は午前10時ごろとか、午前9時55分とか言われる。ここでは午前9時55分とする。

仲値のドル買いはあるのか

「仲値のドル買い」ということがよく言われるが、実際にそのようなことはあるのか。もし、あるとしたら仲値に向けてUSDJPYは上昇し、仲値通過後は横ばい、もしくは下落する傾向を持つだろう。

また、仲値のドル買いはゴトー日でより顕著だとされる。そこで、ゴトー日だけを対象とした検証も行ってみた。

足の種類は1分足である。リターンは計算期間1本(1分)のROCで計算した。また、標準化してある。

これを元に日本時間で午前9時0分から午前11時0分までの2時間の累積和を求めてレートとした。そして、全体から仲値の午前9時55分のレートを減じて、仲値でのレートを0にし、これを基準値とした。

なお、元のデータには夏時間が含まれている。そこで、大雑把に3月から10月までを夏時間と見なして調整している。

In [1]:
import forex_system as fs
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime

fs.remove_temp_folder()

timeframe = 1
size = 120

x = np.empty(size)
y = np.empty(size)
plt.figure(figsize=(6, 32))
cnt = 0
for symbol in ['USDJPY', 'RANDOM']:
    plt.subplot(8, 1, cnt+1)
    for year in [2012, 2013, 2014, 2015, 2016]:
        start = datetime.strptime(str(year) + '.01.01 00:00',
                                  '%Y.%m.%d %H:%M')
        end = datetime.strptime(str(year) + '.12.31 23:59',
                                '%Y.%m.%d %H:%M')
        roc0 = fs.i_roc(symbol, timeframe, 1, 0)[start:end]
        temp = (roc0 - np.mean(roc0)) / np.std(roc0)
        index = roc0.index
        for i in range(2):
            for j in range(60):
                x[i*60+j] = i * 60 + j - 55
                y[i*60+j] = np.mean(temp[(((fs.time_month(index)<3) |
                                           (fs.time_month(index)>=11)) &
                                           (fs.time_hour(index)==2+i) &
                                           (fs.time_minute(index)==0+j)) |
                                          ((fs.time_month(index)>=3) &
                                           (fs.time_month(index)<11) &
                                           (fs.time_hour(index)==3+i) &
                                           (fs.time_minute(index)==0+j))])
        y = np.cumsum(y)
        y -= y[55]
        plt.plot(x, y, label=str(year))
    plt.title('Nakane and Return (' + symbol + ')')
    plt.xlabel('Minute (9:55=0)')
    plt.ylabel('Rate (9:55=0.0)')
    plt.xlim(-55, 60)
    plt.ylim(-3, 2)
    plt.legend(loc='upper right')
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.axvline(x=0, color='black', linestyle=':')
    plt.tight_layout()

    x = np.empty(size)
    y = np.empty(size)
    plt.subplot(8, 1, cnt+2)
    for year in [2012, 2013, 2014, 2015, 2016]:
        start = datetime.strptime(str(year) + '.01.01 00:00',
                                  '%Y.%m.%d %H:%M')
        end = datetime.strptime(str(year) + '.12.31 23:59',
                                '%Y.%m.%d %H:%M')
        roc0 = fs.i_roc(symbol, timeframe, 1, 0)[start:end]
        temp = (roc0 - np.mean(roc0)) / np.std(roc0)
        index = roc0.index
        for i in range(2):
            for j in range(60):
                x[i*60+j] = i * 60 + j - 55
                y[i*60+j] = np.mean(temp[(((fs.time_month(index)<3) |
                                           (fs.time_month(index)>=11)) &
                                           (fs.time_day(index)%5==0) &
                                           (fs.time_hour(index)==2+i) &
                                           (fs.time_minute(index)==0+j)) |
                                          ((fs.time_month(index)>=3) &
                                           (fs.time_month(index)<11) &
                                           (fs.time_day(index)%5==0) &
                                           (fs.time_hour(index)==3+i) &
                                           (fs.time_minute(index)==0+j))])
        y = np.cumsum(y)
        y -= y[55]
        plt.plot(x, y, label=str(year))
    plt.title('Nakane and Return (' + symbol + ', Gotobi)')
    plt.xlabel('Minute (9:55=0)')
    plt.ylabel('Rate (9:55=0.0)')
    plt.xlim(-55, 60)
    plt.ylim(-3, 2)
    plt.legend(loc='upper right')
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.axvline(x=0, color='black', linestyle=':')
    plt.tight_layout()

    start = datetime.strptime('2012.01.01 00:00', '%Y.%m.%d %H:%M')
    end = datetime.strptime('2016.12.31 23:59', '%Y.%m.%d %H:%M')
    roc0 = fs.i_roc(symbol, timeframe, 1, 0)[start:end]
    index = roc0.index

    sell_entry = ((((fs.time_month(index)<3) |
                    (fs.time_month(index)>=11)) &
                    (fs.time_hour(index)==2) &
                    (fs.time_minute(index)==55)) |
                   ((fs.time_month(index)>=3) &
                    (fs.time_month(index)<11) &
                    (fs.time_hour(index)==3) &
                    (fs.time_minute(index)==55)))
    sell_exit = sell_entry.shift(60) == True
    sell_exit = sell_exit.fillna(0)
    buy_entry = sell_entry * 0
    buy_exit = sell_entry * 0

    trading_rules = (symbol, timeframe, buy_entry, buy_exit, sell_entry,
                     sell_exit, 0.1, 0, 0)
    signal, lots = fs.calc_signal(trading_rules)
    ret = fs.calc_ret(symbol, timeframe, signal, 0.4, 2, start, end)
    plt.subplot(8, 1, cnt+3)
    plt.plot(ret.cumsum())
    plt.title('Nakane and Return (' + symbol + ')')
    plt.xlabel('Date')
    plt.ylabel('Cumulative Return')
    plt.ylim(-0.025, 0.2)
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.tight_layout()

    sell_entry = ((((fs.time_month(index)<3) |
                    (fs.time_month(index)>=11)) &
                    (fs.time_day(index)%5==0) &
                    (fs.time_hour(index)==2) &
                    (fs.time_minute(index)==55)) |
                   ((fs.time_month(index)>=3) &
                    (fs.time_month(index)<11) &
                    (fs.time_day(index)%5==0) &
                    (fs.time_hour(index)==3) &
                    (fs.time_minute(index)==55)))
    sell_exit = sell_entry.shift(60) == True
    buy_entry = sell_entry * 0
    buy_exit = sell_entry * 0
    trading_rules = (symbol, timeframe, buy_entry, buy_exit, sell_entry,
                     sell_exit, 0.1, 0, 0)
    signal, lots = fs.calc_signal(trading_rules)
    ret = fs.calc_ret(symbol, timeframe, signal, 0.4, 2, start, end)
    plt.subplot(8, 1, cnt+4)
    plt.plot(ret.cumsum())
    plt.title('Nakane and Return (' + symbol + ', Gotobi)')
    plt.xlabel('Date')
    plt.ylabel('Cumulative Return')
    plt.ylim(-0.025, 0.2)
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.tight_layout()
    cnt = 4
plt.savefig('nakane_and_return.png', dpi=150)
plt.show()

fs.remove_temp_folder()


グラフを見る限り、USDJPYが仲値に向けて上昇する傾向があるようには見えない。ゴトー日でさえ、これといった傾向は見られない。

むしろ仲値通過後に下落する傾向があるように見える。ゴトー日に限るとデータが少なくなるのでやや不安定にはなる。だが、仲値通過後の下落ということでは、ゴトー日であるかないかはあまり影響がないように見える。

仲値後のドル売りが有効か

今回、簡単なバックテストも行ってみた。仲値でUSDJPYを売り、1時間後に決済というものである。スプレッドは0.4pipsとした。

グラフを見ると、一応右肩上がりの曲線を描いている。仲値のドル買いということがよく言われるが、むしろ仲値後のドル売りのほうが有効なように思われる。

(2017/03/13更新)

Zスコアとリターン

1本前の足のZスコアが現在の足のリターンにどのような影響を与えるかを調べてみる。

足は5分足を使っている。現在の足のリターンは計算期間1本(5分)のROCとして計算する。ただし、標準化してある。また、1本前の足のZスコアの計算期間は12本(60分)で固定である。

直前のZスコアと現在のリターンは負の比例

In [1]:
import forex_system as fs
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime

fs.remove_temp_folder()

timeframe = 5
minute = 60
size = 6

x = np.empty(size)
y = np.empty(size)
plt.figure(figsize=(6, 44))
cnt = 0
for symbol in ['AUDJPY', 'AUDUSD', 'EURAUD', 'EURGBP', 'EURJPY', 'EURUSD',
               'GBPAUD', 'GBPJPY', 'GBPUSD', 'USDJPY', 'RANDOM']:
    cnt += 1
    plt.subplot(11, 1, cnt)
    for year in [2012, 2013, 2014, 2015, 2016]:
        start = datetime.strptime(str(year) + '.01.01 00:00',
                                  '%Y.%m.%d %H:%M')
        end = datetime.strptime(str(year) + '.12.31 23:59',
                                '%Y.%m.%d %H:%M')
        roc0 = fs.i_roc(symbol, timeframe, 1, 0)[start:end]
        for i in range(size):
            x[i] = i - 2.5
            period = fs.convert_minute2period(minute, timeframe)
            zscore1  = fs.i_zscore(symbol, timeframe, period, 'MODE_SMA',
                                   1)[start:end]
            y[i] = np.mean(roc0[(zscore1>=x[i]-0.5) & (zscore1<x[i]+0.5)])
        mean = np.mean(y)
        std = np.std(y)
        y = (y - mean) / std
        plt.plot(x, y, label=str(year))
    plt.title('Z-Score and Return (' + symbol + ')')
    plt.xlabel('Z-Score')
    plt.ylabel('Standardized Return')
    plt.xlim(-2.5, 2.5)
    plt.ylim(-2.5, 2.5)
    plt.legend(loc='upper right')
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.tight_layout()
plt.savefig('zscore_and_return.png', dpi=150)
plt.show()

fs.remove_temp_folder()


1本前の足のZスコアと現在の足のリターンは負の比例という関係にあるように見える。

(2017/03/13更新)