直前のROCと現在のROC

少し紛らわしいが、1本前の足のROC現在の足のROCにどのような影響を与えるかを調べてみる。

足は5分足を使っている。現在の足のROCの計算期間は1本(5分)である。また、1本前の足のROCの計算期間は12本(60分)である。

直前のROCと現在のROCは負の比例

x軸、y軸ともにROCは標準化している。

1本前の足のROCと現在の足のROCは負の比例という関係にあるように見える。ただ若干、イレギュラーな部分もある。

サンプルプログラム

○以下のプログラムをSpyderの「IPythonコンソール」にコピー&ペーストして「Enter」キーを2回押す。

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
n = 6

x = np.empty(n)
y = np.empty(n)
plt.figure(figsize=(6, 20))
cnt = 0
for symbol in ['AUDUSD', 'EURUSD', 'GBPUSD', 'USDJPY', 'RANDOM']:
    cnt += 1
    plt.subplot(5, 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]
        mean0 = np.mean(roc0)
        std0 = np.std(roc0)
        roc0 = (roc0 - mean0) / std0
        for i in range(n):
            x[i] = i - 2.5
            period = fs.convert_minute2period(minute, timeframe)
            roc1  = fs.i_roc(symbol, timeframe, period, 1)[start:end]
            mean1 = np.mean(roc1)
            std1 = np.std(roc1)
            roc1 = (roc1 - mean1) / std1
            y[i] = np.mean(roc0[(roc1>=x[i]-0.5) & (roc1<x[i]+0.5)])
        plt.plot(x, y, label=str(year))
    plt.title('ROC1 and ROC0 (' + symbol + ')')
    plt.xlabel('ROC1')
    plt.ylabel('ROC0')
    plt.xlim(-2.5, 2.5)
    plt.ylim(-0.15, 0.15)
    plt.legend(loc='upper right')
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.tight_layout()
plt.savefig('roc1_and_roc0.png', dpi=150)
plt.show()

fs.remove_temp_folder()
(2017/02/22更新)

直前のROC計算期間と現在のROC

少し紛らわしいが、1本前の足のROCの計算期間現在の足のROCにどのような影響を与えるかを調べてみる。また、1本前の足のROCがプラスの場合とマイナスの場合とで分けて検証する。

足は5分足を使っている。現在の足のROCの計算期間は1本(5分)である。

計算期間が長くなるとROCは0に収束

x軸の計算期間の単位は分である。y軸のROCは標準化している。

1本前の足のROCがプラスの場合、1本前の足のROCの計算期間が長くなるにつれ、現在の足のROCはマイナスだが0に近づいていく傾向があるように見える。

1本前の足のROCがマイナスの場合、1本前の足のROCの計算期間が長くなるにつれ、現在の足のROCはプラスだが0に近づいていく傾向があるように見える。

各計算期間は互いに影響

だが、実際には各計算期間は互いに影響し合っている。例えば現在の足の終値が1本前の足の終値より高いとする。では2本前の足の終値と比べるとどうか。もし情報がないとすれば2本前の足の終値の期待値は1本前の足の終値と同じだろう。とすれば現在の足の終値は2本前の足の終値より高いだろう。

したがって、1本前の足のROCは計算期間に関わらず、プラスかマイナスかということでは同じ方向である可能性が高くなる。であるから、どちらかといえば相補的で、特定の計算期間のみの影響はグラフにあるよりは若干小さいものとなるだろう。

サンプルプログラム

○以下のプログラムをSpyderの「IPythonコンソール」にコピー&ペーストして「Enter」キーを2回押す。

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

fs.remove_temp_folder()

timeframe = 5
n = 12

x = np.empty(n)
y = np.empty(n)
plt.figure(figsize=(6, 20))
cnt = 0
for symbol in ['AUDUSD', 'EURUSD', 'GBPUSD', 'USDJPY', 'RANDOM']:
    cnt += 1
    plt.subplot(5, 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]
        mean0 = np.mean(roc0)
        std0 = np.std(roc0)
        roc0 = (roc0 - mean0) / std0
        for i in range(n):
            x[i] = (i + 1) * 5
            period = fs.convert_minute2period(x[i], timeframe)
            roc1  = fs.i_roc(symbol, timeframe, period, 1)[start:end]
            mean1 = np.mean(roc1)
            std1 = np.std(roc1)
            roc1 = (roc1 - mean1) / std1
            y[i] = np.mean(roc0[roc1>=0.0])
        plt.plot(x, y, label=str(year))
    plt.title('ROC1 Period and ROC0 (' + symbol + ', Plus)')
    plt.xlabel('ROC1 Period')
    plt.ylabel('ROC0')
    plt.xlim(5, 60)
    plt.ylim(-0.04, 0.04)
    plt.legend(loc='upper right')
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.tight_layout()
plt.savefig('roc1_period_and_roc0_plus.png', dpi=150)
plt.show()

x = np.empty(n)
y = np.empty(n)
plt.figure(figsize=(6, 20))
cnt = 0
for symbol in ['AUDUSD', 'EURUSD', 'GBPUSD', 'USDJPY', 'RANDOM']:
    cnt += 1
    plt.subplot(5, 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]
        mean0 = np.mean(roc0)
        std0 = np.std(roc0)
        roc0 = (roc0 - mean0) / std0
        for i in range(n):
            x[i] = (i + 1) * 5
            period = fs.convert_minute2period(x[i], timeframe)
            roc1  = fs.i_roc(symbol, timeframe, period, 1)[start:end]
            mean1 = np.mean(roc1)
            std1 = np.std(roc1)
            roc1 = (roc1 - mean1) / std1
            y[i] = np.mean(roc0[roc1<0.0])
        plt.plot(x, y, label=str(year))
    plt.title('ROC1 Period and ROC0 (' + symbol + ', Minus)')
    plt.xlabel('ROC1 Period')
    plt.ylabel('ROC0')
    plt.xlim(5, 60)
    plt.ylim(-0.04, 0.04)
    plt.legend(loc='lower right')
    plt.axhline(y=0.0, color='black', linestyle=':')
    plt.tight_layout()
plt.savefig('roc1_period_and_roc0_minus.png', dpi=150)
plt.show()

fs.remove_temp_folder()
(2017/02/22更新)

確率のイメージ

確率をイメージしたアニメーション画像を作ってみた。

初めはランダムに見えるが…

最初は散布図に点がランダムにプロットされているだけのように見える。だが、しばらくすると、FX業界では割と有名な画像になる。

試行を繰り返して初めて見えてくる

物理学では二重スリット実験という有名な実験がある。電子を飛ばして写真乾板に当てる。だが、途中を2本のスリットのある板で塞ぐ。普通はスリットの後のところだけにしか電子は当たらないと思うだろう。

ところが、板で邪魔されているところにも電子は当たるのである。初めは電子がランダムに当たっているように見える。だが、電子を飛ばし続けると、電子の到達確率に応じた濃淡が生まれるのである。

今回のアニメーション画像はこの二重スリット実験を参考に作ってみた。色はR(赤)、G(緑)、B(青)をそれぞれ0-255の数値にして表すことができる。今回は元画像からR、G、Bがすべて128未満のピクセルに目がけて点を打ち込んだ。

物事の本質というのはわずかな試行や事例でそう簡単に見い出せるものではない。試行を繰り返し、多くの事例を集めて初めて見えてくるものなのである。

サンプルプログラム

①適当なpngファイルを用意し、「image_of_probability.png」ファイルとして「~/py」フォルダーに保存する。

②以下のプログラムをSpyderの「IPython console」にコピー&ペーストして「Enter」キーを2回押す。

import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

def func(i, x, y, frames):
    size = len(x)
    rng = int(size / frames)
    start = i * rng
    end = start + rng - 1
    plt.scatter(x[start:end], y[start:end], c='dimgray', marker='.')
    plt.title('Image of Probability')
    plt.xlim(0, 1)
    plt.ylim(0, 1)

plt.style.use('dark_background')
fig = plt.figure()
max_size = 100000
frames = 60
interval = 1000

img = Image.open("image_of_probability.png")
width = img.width
height = img.height
adj = np.sqrt(width * height / max_size)
width = int(width / adj)
height = int(height / adj)
img = img.resize((width, height))
size = width * height
x = np.zeros(size)
y = np.zeros(size)
for i in range(height):
    for j in range(width):
        rgb = img.getpixel((j, i))
        if rgb[0] < 128 and rgb[1] < 128 and rgb[2] < 128:
            x[width*i+j] = j / width
            y[width*i+j] = 1 - (i / height)

xy = np.c_[x, y]
np.random.shuffle(xy)
x = xy[:, 0]
y = xy[:, 1]

ani = animation.FuncAnimation(fig, func, fargs=(x, y, frames), frames=frames,
                              interval=interval)
plt.show()
ani.save('image_of_probability.gif', writer='imagemagick')

少し待つ(私の環境では15秒くらい)。設定によっては何も描画されていないウィンドウが表示されるが気にしない。終了すると「~/py」フォルダーに「image_of_probability.gif」ファイルが生成する。

(2017/02/19更新)

負ける売買ルールは存在しない

あえて極論を述べるならば、負ける売買ルールなどというものは存在しない。なぜならば、売買を逆にすれば、すぐ勝つ売買ルールに変換できるからだ。

勝てないトレーダーは負けることもできない。では、なぜ世間には「勝てない」とぼやくトレーダーが大勢いるのか?

コイントスでも2人に1人は負ける

先ず、コイントスで売買を決めるような勝つことも負けることもできない売買ルールでも2人に1人は負けるからである。逆に言えば、2人に1人は勝つのだ。

世の中にはコイントスと変わらない無意味な売買ルールでトレードする人もいるだろう。偶然、勝ったからといって、「こうすれば勝てる」と喜ぶのは間違いだ。同様に、偶然、負けたからといって、「こうすれば負ける」と反省するのも間違いなのである。

単にコストを支払っただけ

次に、支払ったコストを負けだと思い込んでいる人がいるからだ。すでに述べたように無意味な売買ルールでは勝つことも負けることもできない。だが、これはコストを考慮しなかった場合である。コストを支払えば負ける確率が勝つ確率より高くなる。それだけのことだ。

例えば、ある価格で買ったとする。そして、価格が+10.0、または-10.0で決済する。上昇する確率と下落する確率が同じと仮定すると、コストを考慮しない場合、

期待利益 = 10.0 * 0.5 - 10.0 * 0.5 = 0.0

となる。ここでコストを1.0として考慮したとする。すると、

期待利益 = 10.0 * 0.5 - 10.0 * 0.5 - 1.0 = -1.0

となって、負けとなる。コストを考慮した上で勝つには例えば

期待利益 = 10.0 * 0.55 - 10.0 * 0.45 - 1.0 = 5.5 - 4.5 - 1.0 = 0.0

のように勝率を55%より大きくしなければならない。

ここでトレーダーがたくさん儲けたいので、トレードの回数を増やしたとする。例えば価格が+5.0、または-5.0で決済してトレードの回転を速めるのである。負けたときの金額も小さくなるので、リスクが下がったような気もする。だが、この条件で勝つには

期待利益 = 5.0 * 0.6 - 5.0 * 0.4 - 1.0 = 3.0 - 2.0 - 1.0 = 0.0

のように勝率を60%より大きくしなければならない。

トレーダーがさらに価格が+2.5、または-2.5で決済してトレードの回転を速めたとする。すると

期待利益 = 2.5 * 0.7 - 2.5 * 0.3 - 1.0 = 1.75 - 0.75 - 1.0 = 0.0

のように勝率を70%より大きくしなければならない。

このように、売買ルールとは関係なく、単に狙う値幅を小さくしてトレードの回転を速めるだけで、勝つためのハードルはどんどん高くなるのである。

売買を逆にして勝つには

少し脱線する。実を言うと、負ける売買ルールでも売買を逆にすれば勝てる、というのもコストを考慮しなかった場合である。コストを考慮した場合、負けにはコスト分も含まれる。したがって、本当の負けは実際より小さい。売買を逆にした場合、マイナスがそのままプラスになるわけではないのである。

プラスになるのは本当の負けの部分だけだ。そしてプラスになった分からさらにコストを減じる。それでもプラスが残った場合のみ、「売買を逆にすれば勝てる」のである。

つまり、

-(コスト込みの損益 + コスト) - コスト > 0
-(コスト込みの損益) - コスト - コスト > 0
-(コスト込みの損益) - コスト * 2 > 0
-(コスト込みの損益) > コスト * 2
コスト込みの損益 < -(コスト * 2)

である。コスト込みの損益がコストの2倍より大きな負けでないと「売買を逆にすれば勝てる」にはならない。

反省するのはいいことだが…

本題に戻る。反省するのはいいことだ。しかし、本当に負けたのか、無意味にトレードを重ねてコストを支払っただけなのではないか、ということも考えるべきだ。さもないと、せっかくの反省も見当違いなものになる。

(2017/02/18更新)

ラウンドナンバーとボラティリティ

価格がラウンドナンバーを上抜き、または下抜きしたとき、ボラティリティがどうなるかを検証してみる。

100pipsの単位が更新されたとき、ラウンドナンバーを上抜き、または下抜きしたと見なすこととする。例えばUSDJPYなら100円未満から100円以上になったときに上抜きと見なすといった具合である。

ボラティリティを計る指標としてはTrue Rangeを用いた。先ず10pipsの単位で10pipsごとにラインを10本設け、それを上抜き、または下抜きした場合のTrue Rangeを求める。次にその平均を取ってベンチマークとする。そして、それぞれのTrue Rangeを平均で除した。つまりベンチマーク=1.0である。

10pipsの単位が0のライン、すなわちラウンドナンバーが他のラインと差があるかどうかを見てみる。使用した足の種類は5分足である。

ラウンドナンバーでボラティリティはやや拡大

検証結果によると、価格がラウンドナンバーを上抜き、または下抜きしたとき、ボラティリティはやや拡大する傾向があるように見える(Decimalが0.0のところ)。

ボラティリティはやや拡大しているとはいうものの、それほど明瞭ではない。ラウンドナンバーはしばらく更新されていないといった条件がないと、大した意味を持たないのかもしれない。USDJPYはいくらか明瞭な感じがする。

サンプルプログラム

○以下のコマンドを「IPython console」にコピー&ペーストして「Enter」キーを2回押す。

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

def get_one(data):
    temp = data.copy()
    temp = np.floor(temp)
    ret = temp % 10
    ret = ret.astype(int)
    return ret

def get_hundredth(data):
    temp = data.copy()
    temp *= 100
    temp = np.floor(temp)
    ret = temp % 10
    ret = ret.astype(int)
    return ret

fs.remove_temp_folder()

timeframe = 5
n = 10
x = np.empty(n)
y = np.empty(n)
plt.figure(figsize=(6, 20))
cnt = 0
for symbol in ['AUDUSD', 'EURUSD', 'GBPUSD', 'USDJPY', 'RANDOM']:
    cnt += 1
    plt.subplot(5, 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')
        ret = fs.i_trange(symbol, timeframe, 0)[start:end]
        high0 = fs.i_high(symbol, timeframe, 0)[start:end]
        high1 = fs.i_high(symbol, timeframe, 1)[start:end]
        low0 = fs.i_low(symbol, timeframe, 0)[start:end]
        low1 = fs.i_low(symbol, timeframe, 1)[start:end]
        for i in range(n):
            if symbol == 'USDJPY' or symbol == 'RANDOM':
                n_h0 = get_one(high0+0.1*i)
                n_h1 = get_one(high1+0.1*i)
                n_l0 = get_one(low0+0.1*i)
                n_l1 = get_one(low1+0.1*i)
            else:
                n_h0 = get_hundredth(high0+0.001*i)
                n_h1 = get_hundredth(high1+0.001*i)
                n_l0 = get_hundredth(low0+0.001*i)
                n_l1 = get_hundredth(low1+0.001*i)
            x[i] = 0.1 * i
            y[i] = np.mean(ret[(n_h0!=n_h1) | (n_l0!=n_l1)])
        benchmark = np.mean(y)
        y /= benchmark
        plt.plot(x, y, label=str(year))
    plt.title('Round Number and Volatility (' + symbol + ')')
    plt.xlabel('Decimal (100pips=1.0)')
    plt.ylabel('True Range (Benchmark=1.0)')
    plt.xlim(0.0, 0.9)
    plt.ylim(0.8, 1.2)
    plt.legend()
    plt.axhline(y=1.0, color='black', linestyle=':')
    plt.tight_layout()
plt.savefig('round_number_and_volatility.png', dpi=150)
plt.show()

fs.remove_temp_folder()
(2017/02/17更新)