Ku-Chartの簡単な計算方法 (2017/07/31)

USDを含む5通貨モデルの計算式

例としてAUD、EUR、GBP、JPY、USDの5通貨モデルの計算式を以下に示す。

a = (log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)) / 5
Ku-AUD = log(AUDUSD) - a
Ku-EUR = log(EURUSD) - a
Ku-GBP = log(GBPUSD) - a
Ku-JPY = -log(USDJPY) - a
Ku-USD = -a

計算式の解説

なぜ、このような式になるのかを説明しておく。興味のない人は読み飛ばしていただいて構わない。

ドルストレートの通貨ペアのみを材料として使い、以下のように変形する。

AUDUSD = AUD / USD
EURUSD = EUR / USD
GBPUSD = AUD / USD
USDJPY = USD / JPY

AUD / USD = AUDUSD
EUR / USD = EURUSD
GBP / USD = GBPUSD
JPY / USD = 1 / USDJPY
USD / USD = 1

Ku-Chartは対数を使っているので、これを対数に変換し、以下のように変形する。

log(AUD/USD) = log(AUDUSD)
log(EUR/USD) = log(EURUSD)
log(GBP/USD) = log(GBPUSD)
log(JPY/USD) = log(1/USDJPY)
log(USD/USD) = log(1)

log(AUD) - log(USD) = log(AUDUSD)
log(EUR) - log(USD) = log(EURUSD)
log(GBP) - log(USD) = log(GBPUSD)
log(JPY) - log(USD) = log(1) - log(USDJPY)
log(USD) - log(USD) = log(1)

log(AUD) - log(USD) = log(AUDUSD)
log(EUR) - log(USD) = log(EURUSD)
log(GBP) - log(USD) = log(GBPUSD)
log(JPY) - log(USD) = 0 - log(USDJPY)
log(USD) - log(USD) = 0

log(AUD) - log(USD) = log(AUDUSD)
log(EUR) - log(USD) = log(EURUSD)
log(GBP) - log(USD) = log(GBPUSD)
log(JPY) - log(USD) = -log(USDJPY)
log(USD) - log(USD) = 0

log(AUD) = log(AUDUSD) + log(USD)
log(EUR) = log(EURUSD) + log(USD)
log(GBP) = log(GBPUSD) + log(USD)
log(JPY) = -log(USDJPY) + log(USD)
log(USD) = log(USD)

Ku-Chartは平均を減じて全体の合計が0になるようにしている。そこで先ず平均を求め、以下のように変形する。

mean = (log(AUD)+log(EUR)+log(GBP)+log(JPY)+log(USD)) / 5

mean = (log(AUDUSD)+log(USD)+log(EURUSD)+log(USD)+log(GBPUSD)+log(USD)-log(USDJPY)+log(USD)+log(USD)) / 5

mean = (log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)+5*log(USD)) / 5

mean = (log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)) / 5 + (5*log(USD)) / 5

mean = (log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)) / 5 + log(USD)

ここで「(log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)) / 5」を「a」としておくと以下のようになる。

mean = a + log(usd)

最後に平均を減じたものをKu-Powerとして、以下のように変形する。

Ku-AUD = log(AUD) - mean
Ku-EUR = log(EUR) - mean
Ku-GBP = log(GBP) - mean
Ku-JPY = log(JPY) - mean
Ku-USD = log(USD) - mean

Ku-AUD = log(AUD) - (a+log(USD))
Ku-EUR = log(EUR) - (a+log(USD))
Ku-GBP = log(GBP) - (a+log(USD))
Ku-JPY = log(JPY) - (a+log(USD))
Ku-USD = log(USD) - (a+log(USD))

Ku-AUD = log(AUD) - a - log(USD)
Ku-EUR = log(EUR) - a - log(USD)
Ku-GBP = log(GBP) - a - log(USD)
Ku-JPY = log(JPY) - a - log(USD)
Ku-USD = log(USD) - a - log(USD)

Ku-AUD = log(AUD) - log(USD) - a
Ku-EUR = log(EUR) - log(USD) - a
Ku-GBP = log(GBP) - log(USD) - a
Ku-JPY = log(JPY) - log(USD) - a
Ku-USD = log(USD) - log(USD) - a

Ku-AUD = log(AUD/USD) - a
Ku-EUR = log(EUR/USD) - a
Ku-GBP = log(GBP/USD) - a
Ku-JPY = log(JPY/USD) - a
Ku-USD = log(USD/USD) - a

Ku-AUD = log(AUD/USD) - a
Ku-EUR = log(EUR/USD) - a
Ku-GBP = log(GBP/USD) - a
Ku-JPY = -log(USD/JPY) - a
Ku-USD = log(1) - a

Ku-AUD = log(AUD/USD) - a
Ku-EUR = log(EUR/USD) - a
Ku-GBP = log(GBP/USD) - a
Ku-JPY = -log(USD/JPY) - a
Ku-USD = 0 - a

Ku-AUD = log(AUDUSD) - a
Ku-EUR = log(EURUSD) - a
Ku-GBP = log(GBPUSD) - a
Ku-JPY = -log(USDJPY) - a
Ku-USD = -a

これで計算式が求められた。

USDを含まない4通貨モデルの計算式

ドルストレートを材料にする場合でもUSDを除くことはできる。

例としてAUD、EUR、GBP、JPYの4通貨モデルの計算式を以下に示す。

a = (log(AUDUSD) + log(EURUSD) + log(GBPUSD) - log(USDJPY)) / 4
Ku-AUD = log(AUDUSD) - a
Ku-EUR = log(EURUSD) - a
Ku-GBP = log(GBPUSD) - a
Ku-JPY = -log(USDJPY) - a

再び計算式の解説

やはり興味のない人は読み飛ばしていただいて構わない。

ドルストレートの通貨ペアのみを材料として使い、以下のように変形する。

AUDUSD = AUD / USD
EURUSD = EUR / USD
GBPUSD = AUD / USD
USDJPY = USD / JPY

AUD / USD = AUDUSD
EUR / USD = EURUSD
GBP / USD = GBPUSD
JPY / USD = 1 / USDJPY

対数に変換し、以下のように変形する。

log(AUD/USD) = log(AUDUSD)
log(EUR/USD) = log(EURUSD)
log(GBP/USD) = log(GBPUSD)
log(JPY/USD) = log(1/USDJPY)

log(AUD) - log(USD) = log(AUDUSD)
log(EUR) - log(USD) = log(EURUSD)
log(GBP) - log(USD) = log(GBPUSD)
log(JPY) - log(USD) = log(1) - log(USDJPY)
log(USD) - log(USD) = log(1)

log(AUD) - log(USD) = log(AUDUSD)
log(EUR) - log(USD) = log(EURUSD)
log(GBP) - log(USD) = log(GBPUSD)
log(JPY) - log(USD) = 0 - log(USDJPY)

log(AUD) - log(USD) = log(AUDUSD)
log(EUR) - log(USD) = log(EURUSD)
log(GBP) - log(USD) = log(GBPUSD)
log(JPY) - log(USD) = -log(USDJPY)

log(AUD) = log(AUDUSD) + log(USD)
log(EUR) = log(EURUSD) + log(USD)
log(GBP) = log(GBPUSD) + log(USD)
log(JPY) = -log(USDJPY) + log(USD)

平均を求め、以下のように変形する。

mean = (log(AUD)+log(EUR)+log(GBP)+log(JPY)) / 4

mean = (log(AUDUSD)+log(USD)+log(EURUSD)+log(USD)+log(GBPUSD)+log(USD)-log(USDJPY)+log(USD)) / 4

mean = (log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)+4*log(USD)) / 4

mean = (log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)) / 4 + (4*log(USD)) / 4

mean = (log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)) / 4 + log(USD)

ここで「(log(AUDUSD)+log(EURUSD)+log(GBPUSD)-log(USDJPY)) / 4」を「a」としておくと以下のようになる。

mean = a + log(usd)

平均を減じたものをKu-Powerとして、以下のように変形する。

Ku-AUD = log(AUD) - mean
Ku-EUR = log(EUR) - mean
Ku-GBP = log(GBP) - mean
Ku-JPY = log(JPY) - mean

Ku-AUD = log(AUD) - (a+log(USD))
Ku-EUR = log(EUR) - (a+log(USD))
Ku-GBP = log(GBP) - (a+log(USD))
Ku-JPY = log(JPY) - (a+log(USD))

Ku-AUD = log(AUD) - a - log(USD)
Ku-EUR = log(EUR) - a - log(USD)
Ku-GBP = log(GBP) - a - log(USD)
Ku-JPY = log(JPY) - a - log(USD)

Ku-AUD = log(AUD) - log(USD) - a
Ku-EUR = log(EUR) - log(USD) - a
Ku-GBP = log(GBP) - log(USD) - a
Ku-JPY = log(JPY) - log(USD) - a

Ku-AUD = log(AUD/USD) - a
Ku-EUR = log(EUR/USD) - a
Ku-GBP = log(GBP/USD) - a
Ku-JPY = log(JPY/USD) - a

Ku-AUD = log(AUD/USD) - a
Ku-EUR = log(EUR/USD) - a
Ku-GBP = log(GBP/USD) - a
Ku-JPY = -log(USD/JPY) - a

Ku-AUD = log(AUD/USD) - a
Ku-EUR = log(EUR/USD) - a
Ku-GBP = log(GBP/USD) - a
Ku-JPY = -log(USD/JPY) - a

Ku-AUD = log(AUDUSD) - a
Ku-EUR = log(EURUSD) - a
Ku-GBP = log(GBPUSD) - a
Ku-JPY = -log(USDJPY) - a

これで計算式が求められた。

要するに、USDを含めた5通貨モデルでは5で除していたところを4で除するように変更するだけである。

まとめ

上記の計算式を用いれば、ドルストレートを材料にして任意の組み合わせのKu-Chartを作成できる。もちろん、他のドルストレートを追加して5より大きいモデルを作成することもできる。

また、同様のやり方でクロス円、ユーロクロスなどを使ってKu-Chartを計算することもできる。ただし、「EURUSD」と「EURJPY / USDJPY」が必ずしも一致しないように非常にわずかな誤差はありうる。

ハイブリッドトレードの試み (2017/07/29)

ハイブリッドトレードとは

ここではハイブリッドトレードを裁量トレードとシステムトレードを組み合わせたものとしておく。もう少し具体的には、システムによるシグナルをトレーダーが裁量で取捨選択するようなトレードである。

ハイブリッドトレードの基本原則

私が考えるハイブリッドトレードには以下の4つの基本原則がある。

  1. システムがエントリーのシグナルを点灯させてもエントリーしなくていい。
  2. システムがエントリーのシグナルを点灯させていなければエントリーしてはならない。
  3. システムがエグジットのシグナルを点灯させていなくてもエグジットしていい。
  4. システムがエグジットのシグナルを点灯させたら必ずエグジットする。

これをまとめると、システムが持つポジションを持つことは許されるが、システムが持たないポジションを持つことは許されない、ということである。

エントリー選択の原則

  1. 経済指標発表の1時間半前から30分後まではエントリーしない。
  2. 要人発言予定の1時間半前から3時間後まではエントリーしない。
  3. 経済指標、または要人発言によって相場が大きく動いたとき、動いた方向にはエントリーしない。
  4. サポート手前では買わず、レジスタンス手前では売らない。ブレイクしてからエントリーする。
  5. 日足始値より上では買わず、下では売らない。
  6. 月曜日は金曜日終値より上では買わず、下では売らない。

私は経済指標発表、要人発言を「DailyFX」というスマートフォンアプリで確認している。通貨ペアと直接関係のないイベントは基本的に考慮しない。例えば、ドル円なら米国と日本のイベントのみ注意する。

以上は私の試行錯誤によるものであって、今後も変わりうる。

エグジット選択の原則

  1. エグジットのシグナルが来たら、ポジションの損益の大小に関わらず、即座にエグジットする。
  2. 経済指標発表、要人発言予定が近づいてもエグジットのシグナルがない場合、ポジションの損益の大小に関わらず、5分前までにはエグジットする。
  3. ポジションの損益がプラスでエグジットに近づいてから相場が反転して利益が縮小した場合、マイナスになる直前にエグジットする。
  4. ポジションの損益がプラスのとき、チャートを見てエグジットの条件を満たしていると分った場合、エグジットのシグナルを待たずにポジションの半分、または全部をエグジットしてもいい。

これも私の試行錯誤によるものであって、今後も変わりうる。

勝率とペイオフレシオ (2017/07/08)

勝率とペイオフレシオの関係がどのようであるかを調べてみる。

勝率の高い戦略が優れているとは限らない。ペイオフレシオが低ければ勝率が高くても負ける戦略となる場合がある。

逆に、ペイオフレシオの高い戦略が優れているとは限らない。勝率が低ければペイオフレシオが高くても負ける戦略となる場合がある。

要するにバランスが重要だ。それを考慮せずに「損小利大」はよいとか、「損大利小」はだめとか言っても無意味である。

さて、私は勝率が高ければペイオフレシオは低く、勝率が低ければペイオフレシオは高い、つまり、トレードオフの関係にあると考えている。勝率もペイオフレシオも高いというのが理想ではある。だが、そう簡単に実現できることではない。

もし、勝率とペイオフレシオがトレードオフの関係にあるとすれば、

平均利益 / 平均損失 = 負け数 / 勝ち数

という関係を想定することができるだろう。これを整理すると、

ペイオフレシオ = 負け数 / 勝ち数
ペイオフレシオ = (負け数 / (勝ち数+負け数)) / (勝ち数 / (勝ち数+負け数))
ペイオフレシオ = (1 - 勝率) / 勝率
ペイオフレシオ * 勝率 = 1 - 勝率
ペイオフレシオ * 勝率 + 勝率 = 1
(ペイオフレシオ + 1) * 勝率 = 1
勝率 = 1 / (ペイオフレシオ + 1)

となる。

すると、

勝率 = 傾き * (1 / (ペイオフレシオ + 1)) + 切片

というモデルを想定することができる。特に理由がなければ、傾きは1、切片は0になると考えられる。

では上のモデルをランダムウォークのデータを使って検証してみる。

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

import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit

②ペイオフレシオごとの勝率を求める。

n = 1000
max_iter = 10000
wp_long = np.empty(9)
wp_short = np.empty(9)
payoff_ratio_long = np.empty(9)
payoff_ratio_short = np.empty(9)

for i in range(9):
    profit = i + 1
    loss = 9 - i
    win_long = 0
    lose_long = 0
    win_short = 0
    lose_short = 0
    for j in range(max_iter):
        rnd = np.random.randn(n) * 0.01
        close = np.cumsum(rnd) + np.log(100)
        close = np.exp(close)
        count = 0
        for k in range(n):
            if count < k:
                count = k
            if close[k] >= 100 + profit:
                win_long += 1
                lose_short += 1
                break
            if close[k] <= 100 - loss:
                lose_long += 1
                win_short += 1
                break
    wp_long[i] = win_long / (win_long + lose_long)
    wp_short[i] = win_short / (win_short + lose_short)
    payoff_ratio_long[i] = profit / loss
    payoff_ratio_short[i] = loss / profit

先ず、ペイオフレシオを1:9、2:8、3:7、4:6、5:5、6:4、7:3、8:2、9:1で場合分けする。次にランダムウォークのデータを作り、それぞれのペイオフレシオでの勝敗をカウントするシミュレーションを1万回行って勝率を求める。

検証は買いの場合と売りの場合の2つのパターンで行った。同じ値幅での上昇確率は下落確率よりわずかに高く、買いが売りよりわずかに有利だと考えられるからである。これについては以下を参照。

https://storage.googleapis.com/imoz-jp/slides/160321_trading.pdf(p19-22)

③グラフを表示する。

plt.plot(payoff_ratio_long, wp_long, label='wp_long')
plt.plot(payoff_ratio_short, wp_short, label='wp_short')
plt.xlabel('Payoff Ratio')
plt.ylabel('Winning Percentage')
plt.xlim(0, 9)
plt.ylim(0, 1)
plt.legend(loc="upper right")
plt.savefig('wp_por.png', format='png', dpi=150)
plt.show()

わずかに買いの勝率が売りの勝率より高いことが分かる。

④モデルを作成する。

def model(payoff_ratio, a, b):
    return a * (1 / (1 + payoff_ratio)) + b

⑤モデルの傾きと切片を求める。

popt, pcov = curve_fit(model, payoff_ratio_long, wp_long)
slope_long = popt[0]
intercept_long = popt[1]
popt, pcov = curve_fit(model, payoff_ratio_short, wp_short)
slope_short = popt[0]
intercept_short = popt[1]

⑥モデルを表示する。

print('Long:')
print(
      '\t Winning Percentage = ', slope_long, ' * (1 / (Payoff Ratio + 1)) + ',
      intercept_long)
print('Short:')
print(
      '\t Winning Percentage = ', slope_short,
      ' * (1 / (Payoff Ratio + 1)) + ', intercept_short)

Long:
         Winning Percentage =  0.887583333429  * (1 / (Payoff Ratio + 1)) +  0.0613638886528
Short:
         Winning Percentage =  0.887583333879  * (1 / (Payoff Ratio + 1)) +  0.0510527775029

当初、期待していた「傾きが1、切片が0」となる結果とは少し違う。誤差とするにはやや大きすぎるように思う。だが、なぜこうなるかは分からない。

とりあえず目安としては買いと売りを分けずに

勝率 = 0.9 * (1 / (ペイオフレシオ + 1)) + 0.05

くらいに考えておけばいいだろうか。

これはランダムウォークで予測される勝率である。したがって、これより大きな勝率でなければランダムウォークに勝っていないことになる。

Ubuntuのトラブル (2017/07/07)

私の環境で時々起きるUbuntuのトラブルとその解決法を備忘録として残す。

「システムプログラムの問題が見つかりました」

Ubuntuを起動すると、「システムプログラムの問題が見つかりました」と表示されることがある。一度、表示されると、以降、起動するたびに表示されるようになるので鬱陶しい。

クラッシュが発生したときに生成されるcrashファイルが原因のようである。これを削除すれば、以降、表示されなくなる。

①以下のコマンドを端末に入力して「Enter」キーを押す。

$ ls /var/crash

crashファイルの名前が表示される。一応、何がクラッシュしたのか確認しておく。

②以下のコマンドを端末に入力して「Enter」キーを押す。

$ sudo rm /var/crash/*

③「[sudo] **** のパスワード:」でパスワードを入力して「Enter」キーを押す。

crashファイルが削除される。

「ファイル“****”を開く際にエラーが発生しました。」

Windowsで作成したテキストファイルをテキストエディターで開こうとすると、「ファイル“****”を開く際にエラーが発生しました。」と表示が出て、開けない場合がある。

「エンコーディング」は「現在のロケール (UTF-8)」となっている。「再試行」ボタンをクリックしても、やはり「ファイル“****”を開く際にエラーが発生しました。」と表示が出て、開けない。

Windowsで作成したテキストファイルはshift-JISで書かれていると思う。そこで、テキストエディターで「エンコーディング」を「日本語 (SHIFT_JIS)」に変更して「再試行」ボタンをクリックしてみる。だが、今度は「ファイル“****”を開けませんでした。」と表示は変わるものの、やはり開けない。

原因ははっきりしないが、テキストエディターで読めるようにするにはとりあえず文字コードをUTF-8に変換するのが手っ取り早い。

例として「ホーム」フォルダーに「file_shift-jis.txt」ファイルがあるとして、これをUTF-8に変換して「file_utf-8.txt」ファイルとする手順を説明する。

○端末に以下のコマンドを入力して「Enter」キーを押す。

$ nkf -w ~/file_shift-jis.txt > ~/file_utf-8.txt

「file_shift-jis.txt」ファイルはそのまま残り、「file_utf-8.txt」ファイルが新たに作成される。「file_utf-8.txt」ファイルをテキストエディターで開くと、無事にファイルの内容を見ることができる。

的中率とシャープレシオ (2017/07/06)

的中率とシャープレシオとの間にどのような関係があるかをシミュレーションによって調べてみる。

単純化のため、ここでいくつかの仮定を置く。

先ず、ボラティリティは1.0で固定とする。固定でさえあれば、実際にはどの数値でも結果は変わらない。

次に1年当たりのトレード数を260回とする。これは数値を変えると結果も変わるので動かせない。この数値は1年当たりの営業日が260日であることに基づく。イメージとしては毎日、上がるか下がるかを予測して売買し、1日の損益の絶対値は常に一定、と考えればいい。

最後にコストは考慮していない。

それではシミュレーションを始める。

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

import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit

②的中率とそれに対応したシャープレシオを計算する。

start = 50
end = 105
step = 5
n = int((end - start) / step)
accuracy = np.array(range(start, end, step)) / 100
sharpe_ratio = np.empty(n)
volatility = 1.0
trades = 260
for i in range(n):
    ret = ((volatility*accuracy[i]) - (volatility*(1.0-accuracy[i]))) * trades
    risk = volatility * np.sqrt(trades)
    sharpe_ratio[i] = ret / risk

的中率は50-100%の範囲で5%刻みとする。

③グラフを表示する。

plt.plot(accuracy, sharpe_ratio)
plt.xlabel('Accuracy')
plt.ylabel('Sharpe ratio')
plt.xlim(0.5, 1.0)
plt.savefig('sharpe_ratio_accuracy.png', dpi=150)
plt.show()

グラフを見ると、的中率とシャープレシオは比例していることが分かる。

④的中率とシャープレシオの関係を示すモデルを作成する。

def model(accuracy, slope, intercept):
    return slope * accuracy + intercept

上のグラフから以下のような関係を想定している。

シャープレシオ = 傾き * 的中率 + 切片

⑤モデルの傾き、切片を求める。

popt, pcov = curve_fit(model, accuracy, sharpe_ratio)
slope = popt[0]
intercept = popt[1]
print('Sharp Ratio = ', slope, ' * Accuracy + ', intercept)

Sharp Ratio =  32.2490309932  * Accuracy +  -16.1245154966

求められた傾き、切片によると、的中率が5%上昇するだけでシャープレシオは約1.61上昇するということが分かる。的中率で見ると、5%くらい大した違いではないように思うかもしれない。だが、これは大変な改善なのである。

もし的中率が70%であったら、

シャープレシオ = 32.2490309932 * 0.7 + (-16.1245154966) = 6.4498061986399975

となる。

シャープレシオが3.0以上なら、それは素晴らしい戦略だろう。6.0を超えるとなると、もはや尋常ではない。言い換えれば、的中率が70%に達するというのは尋常ではないのである。

機械学習、またはディープラーニングで株価予測的中率が○○%になった、というような話をよく聞く。だが、実際に尋常ではない素晴らしい成果が得られたのか、それとも何らかの間違いを犯していたり、単なる誇大広告であったりしないか、しっかりと吟味する必要がある。