TensorFlowノート (2017/04/02)

各見出しは参考にしたページである。データは為替データに差し替えている。コードでエラーになる部分は修正しているが、警告の場合は原則そのまま。

Getting Started With TensorFlow

https://www.tensorflow.org/get_started/get_started

import forex_system as fs
import numpy as np
import tensorflow as tf
from datetime import datetime

fs.remove_temp_folder()

W = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
y = tf.placeholder(tf.float32)
loss = tf.reduce_sum(tf.square(linear_model - y))
optimizer = tf.train.GradientDescentOptimizer(0.000001) # 学習率が高いとnan発生。
train = optimizer.minimize(loss)
start = datetime.strptime('2016.01.01 00:00', '%Y.%m.%d %H:%M')
end = datetime.strptime('2016.12.31 23:59', '%Y.%m.%d %H:%M')
x_train = np.array(fs.i_zscore('USDJPY', 5, 12, 'MODE_SMA', 1)[start:end])
y_train = np.array(fs.i_roc('USDJPY', 5, 1, 0)[start:end])
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
for i in range(1000):
    sess.run(train, {x:x_train, y:y_train})
curr_W, curr_b, curr_loss  = sess.run([W, b, loss], {x:x_train, y:y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))


W: [ -9.50196700e-05] b: [ -2.46166637e-05] loss: 162.686

MNIST For ML Beginners

https://www.tensorflow.org/get_started/mnist/beginners

import forex_system as fs
import numpy as np
import pandas as pd
import tensorflow as tf
from datetime import datetime

fs.remove_temp_folder()

x = tf.placeholder(tf.float32, [None, 10])
W = tf.Variable(tf.zeros([10, 2]))
b = tf.Variable(tf.zeros([2]))
y = tf.nn.softmax(tf.matmul(x, W) + b)
y_ = tf.placeholder(tf.float32, [None, 2])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),
                                              reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
start = datetime.strptime('2016.01.01 00:00', '%Y.%m.%d %H:%M')
end = datetime.strptime('2016.12.31 23:59', '%Y.%m.%d %H:%M')
x_train = fs.i_zscore('USDJPY', 5, 12, 'MODE_SMA', 1)[start:end]
for i in range(1, 10):
    x_train_temp = fs.i_zscore('USDJPY', 5, 12, 'MODE_SMA', 1 + i)[start:end]
    x_train = pd.concat([x_train, x_train_temp], axis=1)
x_train = np.array(x_train.values)
y_train_temp = fs.i_roc('USDJPY', 5, 1, 0)[start:end]
y_train_temp1 = y_train_temp.copy()
y_train_temp2 = y_train_temp.copy()
y_train_temp1[y_train_temp>=0.0] = 1
y_train_temp1[y_train_temp<0.0] = 0
y_train_temp2[y_train_temp>=0.0] = 0
y_train_temp2[y_train_temp<0.0] = 1
y_train = pd.concat([y_train_temp1, y_train_temp2], axis=1)
y_train = np.array(y_train.values)
size = len(x_train)
batch_size = 100
i = 0
while(True):
    if (i+1)*batch_size > size:
        break
    batch_xs, batch_ys = (x_train[i*batch_size:(i+1)*batch_size],
                          y_train[i*batch_size:(i+1)*batch_size])
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
    i += 1
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: x_train, y_: y_train}))


0.487841

Deep MNIST for Experts

https://www.tensorflow.org/get_started/mnist/pros

import forex_system as fs
import numpy as np
import pandas as pd
import tensorflow as tf
from datetime import datetime

fs.remove_temp_folder()

def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)
def conv2d(x, W):
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                          strides=[1, 2, 2, 1], padding='SAME')

sess = tf.InteractiveSession()
x = tf.placeholder(tf.float32, shape=[None, 10])
y_ = tf.placeholder(tf.float32, shape=[None, 2])
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
x_image = tf.reshape(x, [-1,10,1,1]) # or tf.reshape(x, [-1,1,10,1])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
W_fc1 = weight_variable([3 * 1 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 3*1*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
W_fc2 = weight_variable([1024, 2])
b_fc2 = bias_variable([2])
y_conv = tf.matmul(h_fc1_drop, W_fc2) + b_fc2
cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
sess.run(tf.global_variables_initializer())
start = datetime.strptime('2016.01.01 00:00', '%Y.%m.%d %H:%M')
end = datetime.strptime('2016.12.31 23:59', '%Y.%m.%d %H:%M')
x_train = fs.i_zscore('USDJPY', 5, 12, 'MODE_SMA', 1)[start:end]
for i in range(1, 10):
    x_train_temp = fs.i_zscore('USDJPY', 5, 12, 'MODE_SMA', 1 + i)[start:end]
    x_train = pd.concat([x_train, x_train_temp], axis=1)
x_train = np.array(x_train.values)
y_train_temp = fs.i_roc('USDJPY', 5, 1, 0)[start:end]
y_train_temp1 = y_train_temp.copy()
y_train_temp2 = y_train_temp.copy()
y_train_temp1[y_train_temp>=0.0] = 1
y_train_temp1[y_train_temp<0.0] = 0
y_train_temp2[y_train_temp>=0.0] = 0
y_train_temp2[y_train_temp<0.0] = 1
y_train = pd.concat([y_train_temp1, y_train_temp2], axis=1)
y_train = np.array(y_train.values)
size = len(x_train)
batch_size = 50
i = 0
while(True):
    if (i+1)*batch_size > size:
        break
    batch_xs, batch_ys = (x_train[i*batch_size:(i+1)*batch_size],
                          y_train[i*batch_size:(i+1)*batch_size])
    if i%100 == 0:
        train_accuracy = accuracy.eval(feed_dict={
            x:batch_xs, y_: batch_ys, keep_prob: 1.0})
        print("step %d, training accuracy %g"%(i, train_accuracy))
    train_step.run(feed_dict={x: batch_xs, y_: batch_ys, keep_prob: 0.5})
    i += 1
print("test accuracy %g"%accuracy.eval(feed_dict={
    x: x_train, y_: y_train, keep_prob: 1.0}))


step 0, training accuracy 0
step 100, training accuracy 0.56
step 200, training accuracy 0.52
step 300, training accuracy 0.54
step 400, training accuracy 0.44
step 500, training accuracy 0.54
step 600, training accuracy 0.62
step 700, training accuracy 0.44
step 800, training accuracy 0.44
step 900, training accuracy 0.6
step 1000, training accuracy 0.48
step 1100, training accuracy 0.54
step 1200, training accuracy 0.54
step 1300, training accuracy 0.62
step 1400, training accuracy 0.4
step 1500, training accuracy 0.6
test accuracy 0.523694

tf.contrib.learn Quickstart

https://www.tensorflow.org/get_started/tflearn

以下のコードを「~py/test.py」ファイルとして保存する。

import forex_system as fs
import numpy as np
import pandas as pd
import tensorflow as tf
from datetime import datetime

def main():
    def get_train_inputs():
        x = tf.constant(training_set[:, 0:10])
        y = tf.constant(training_set[:, 10])
        return x, y

    def get_test_inputs():
        x = tf.constant(test_set[:, 0:10])
        y = tf.constant(test_set[:, 10])
        return x, y

    def new_samples():
        return np.array(
          [[6.4, 3.2, 4.5, 1.5],
           [5.8, 3.1, 5.0, 1.7]], dtype=np.float32)
        predictions = list(classifier.predict(input_fn=new_samples))
        print(
            "New Samples, Class Predictions:    {}\n"
            .format(predictions))

    start = datetime.strptime('2016.01.01 00:00', '%Y.%m.%d %H:%M')
    end = datetime.strptime('2016.12.31 23:59', '%Y.%m.%d %H:%M')
    x = fs.i_zscore('USDJPY', 5, 12, 'MODE_SMA', 1)[start:end]
    for i in range(1, 10):
        x_temp = fs.i_zscore('USDJPY', 5, 12, 'MODE_SMA', 1 + i)[start:end]
        x = pd.concat([x, x_temp], axis=1)
    y = fs.i_roc('USDJPY', 5, 1, 0)[start:end]
    y_temp = y.copy()
    y[y_temp>=0.0] = 1
    y[y_temp<0.0] = 0
    xy = pd.concat([x, y], axis=1)
    xy = np.array(xy.values)
    size = len(xy)
    size_training = int(size * 0.8)
    training_set = xy[:size_training, :]
    test_set = xy[size_training:, :]
    feature_columns = [tf.contrib.layers.real_valued_column("", dimension=10)]
    classifier = tf.contrib.learn.DNNClassifier(feature_columns=feature_columns,
                                                hidden_units=[10, 20, 10],
                                                n_classes=2,
                                                model_dir="/tmp/test_model")
    classifier.fit(input_fn=get_train_inputs, steps=2000)
    accuracy_score = classifier.evaluate(input_fn=get_test_inputs,
                                         steps=1)["accuracy"]
    print("\nTest Accuracy: {0:f}\n".format(accuracy_score))

if __name__ == "__main__":
    main()

以下のコマンドを実行する。

%run ~/py/test.py


(略)
Test Accuracy: 0.530198

ハイブリッドトレードの試み

私が試行錯誤しながらやっているハイブリッドトレードをここで具体的に述べてみたい。もちろん試行錯誤であるから、決して最終形態ではないし、満足しているわけでもない。日々改善したいと考えている。

1日の方針を決める

先ずは毎朝、何を、買いから入るか、売りから入るか、様子見するかという1日の方針を決める。決める基準は極めて主観的で、相場の雰囲気である。

雰囲気的に方向は上でも下がることがあるし、下でも上がることがあって、これ自体はたいして当てにならない。ただ、雰囲気的に上の場合、下がってもたかが知れているが、上がったときはぐんと上がる、雰囲気的に下の場合、上がってもたかが知れているが、下がったときはぐんと下がることが多い気がする。

したがって、相場の雰囲気に従った場合、負けてもたかが知れている。しかし、逆らった場合、負けたときは大きくやられる。

また、相場が荒れていて、上がるにせよ、下がるにせよ大きく動きそうなときは休む。

私は経済ニュースとかあまり見ないので、相場の雰囲気を知るにあたって以下のブログを参考にしている。

酒匂塾長の『独り言』

http://www.gaitame.com/blog/sakoh/

小林芳彦のマーケットショット

http://kobayashiyoshihiko.blog88.fc2.com/

酒匂さんも小林さんも元プロの為替ディーラーで経験豊富であるから、その相場観というのは参考になる。特に小林さんのブログは毎日昼頃にその日の売買指針を書いているので重視している。

小林さんの相場観は記事のタイトルを見るだけで分かる。例えば「ドル円は買い、ユーロドルは売り」とあればドルが強いと判断しているのである。「ドル円、ユーロドルともに買い」とあればユーロが強く、円が弱いと判断しているのである。

また、「ドル円は買いだが、指値せず」とあれば、やや自信がないのである。

ただ、小林さんの具体的な売買水準には従わない。あくまでも売買の水準は自分のシステムに従う。

小林さんはTwitterでスキャルを実況していることもある。エントリーのシグナルが発生したとき、小林さんはどうしているか見てみるのもいいだろう。小林さんはスキャルのときは臨機応変に売り買いしており、定まった売買方向はない。

もし、小林さんがスキャルをやっていたら、少なくとも相場が急変するような危ない状況ではないだろう。そのときは売買方向にこだわらずにトレードしてもいい。ただし、あくまでもシステムのシグナルの範囲内で行う。

https://twitter.com/jfxkobayashi

酒匂さんと小林さんを参考にするのはお二人が特に優れていて他の人がダメだということではない。単なる好みである。

メールを確認する

私はシステムにシグナルをメールで知らせるようにしている。

エントリーシグナルが発生した場合、システムがどの通貨ペアを、どのレートで買いエントリー、または売りエントリーしたかがメールで知らされる。同様に、エグジットシグナルが発生した場合、システムがどの通貨ペアを、どのレートで買いエグジット、または売りエグジットしたかがメールで知らされる。

システムはこういうトレードをしている、ということを知らせているのである。エントリーの場合、売買の方向が小林さんの指針と異なるときはエントリーしない。同じであるときは以下の手順に移る。

経済スケジュールを確認する

先ず経済スケジュールを確認する。私はいつも

http://fx.minkabu.jp/indicators/calendar

で確認している。

だが、こういったサイトはあちこちにあるから、別にどこでもいい。これも好みである。

これからトレードしようという通貨ペアに影響を与えそうなイベントが1〜2時間以内にあるときはエントリーしない。

チャートを見る

次にチャートを見る。

日足で直近の高値、安値を確認し、レートがそこから10pips以内に近づいたときはエントリーしない。

ラウンドナンバー(100.00円、101.00円など)から10pips以内に近づいたときもエントリーしない。

それらを上抜いたり、下抜いたりしてから、エントリーのタイミングをはかる。

値動きを見る

そして、レートの変動を見る。

レートが1tickで数pipsも動くようなときはエントリーしない。1tickの変動が1pips未満になるまで待つ。

スプレッドを見る

最後にスプレッドを見る。

スプレッドが広がっているときはエントリーしない。単に損だということもあるが、何らかのニュースで市場が騒然となっている場合があるので、そういう相場には近寄らない。

追加的なエントリー条件①

これまでの手順によってエントリーできる状況にあると判断したら、2つの追加的なエントリー条件により、エントリーのタイミングをはかる。

第1は、システムより1pips有利なレートでエントリーすることである。

ここまでの手順を経る間に(凡そ数分)システムがエントリーしたレートからはいくらか離れてしまう。エントリーできないこともあるが、それは仕方ないとしてあきらめる。

追加的なエントリー条件②

第2は、エントリーシグナル発生の条件を満たしていたらエントリーすることである。システムがエントリーシグナルを送ってきたのだから条件を満たしているはずではないかと思われるかもしれない。ここでは新規のエントリーシグナルという意味である。

エントリーシグナルには新規のものと継続のものとがある。新規はエントリーシグナル発生の条件を満たしている場合であり、継続はエントリーシグナルが発生した後、エントリーシグナル発生の条件を必ずしも満たしてはいないが、エグジットシグナルがまだ発生していない場合である。

ちょっと分かりにくいかもしれない。例えばボリンジャーバンドを使って以下のようなトレードルールをもうけたとする。

終値が

  • -2σ以下で買いエントリー
  • 0以上で買いエグジット
  • +2σ以上で売りエントリー
  • 0以下で売りエグジット

ここで終値が-2σ以下となって買いエントリーのシグナルが発生したとする。ところが、システムからの通知にタイムラグがあったり、準備に手間取ったり、タイミングをはかったりで、新しい足が形成されて-2σの水準が変わってしまうことがある。

もし終値が新しい足では-1.5σの水準にあったとしよう。エグジットの条件は満たしていないので、システムは買いポジションを保有している。だが、買いエントリーの条件はすでに満たしていない。

このようなときのシグナルは新規ではなくて継続である。この場合、システムがポジションを持っているし、しかも1pips有利なレートだからといってエントリーはしない。再び終値が-2σ以下となるのを待ってエントリーする。

目をつぶって10数える

エントリーのタイミングをはかるときは、ワンタッチで新規注文を送信できる状態にしてから目をつぶって10数える。そして、追加的なエントリー条件を満たしていたら新規注文にタッチする。条件を満たしていなければ、また目をつぶって10数えるということを繰り返す。

目を開けてレートを追っていると、少しでも有利になるとつい飛びつきたくなる。だが、往々にして、しばらく待てばさらに有利なレートになるものである。だから目をつぶり、慌ててエントリーすることはしない。

もちろん、これによってエントリーのチャンスを失うこともある。システムトレード的には正しいやり方とは言えない。だが、ここでは勝つチャンスを逃さないことより負けるリスクを減らすことを重視する。

なかなかエントリーできず、レートがエントリー水準よりエグジット水準に近くなってしまったら、いったんエントリーをあきらめる。だが、しばらくしてもエグジットの通知がなく、チャートを見たら再びエントリー水準に近づいていたような場合、もう一度チャレンジする。

1pips以上の利益で利食い

エントリーしたらワンタッチで決済注文を送信できる状態にし、やはり目をつぶって10数える、ということをやる。そして1pips以上の利益が出たらエグジットする。1pips以上の利益が出なくても、エグジットのシグナルが発生したらエグジットする。

ポジションを持っている間はトレードに集中する。トレードから離れなければならないときは1pipsの利益でエグジットとなる指値決済注文を出しておく。しかし、長時間、トレードから離れることはしない。

また、含み損が出た場合は最大で何pipsだったか覚えておく。

利食ったら再エントリー

利食った後、システムがまだポジションを持っているなら再エントリーのタイミングをはかる。やはり目をつぶって10数える、ということをやる。

再エントリーに当たっては、上述の追加的なエントリー条件に加え、①利食ったレートよりスプレッド分有利なレートでエントリーする、②前のエントリーで最大の含み損が出たレートの1pips手前まで引きつけてからエントリーする、の2条件を新たにもうける。

再エントリーは何回やっても構わない。システムは負けているのに、自分は連戦連勝ということもよくある。失ったトレード機会の分はここで取り返す。

エグジットのシグナルが発生したら、もちろん再エントリーはあきらめる。

最後に

私のやっているトレードは大体こんな感じである。勝ったときの利益は1〜3pips程度なので、大きな負けがあれば、根こそぎ持って行かれるだろう。だが、エントリーに慎重なためか、単に運がよかったのか分からないが、今のところ、負けても1pips程度である(だが含み損では最大で20pips程度になったことがある)。

以上、システムだけで勝つことに難しさを感じた私なりの工夫である。もちろん、どんな相場でも勝てるシステムを作るのが理想ではある。しかし、理想にこだわってシステムのみで勝つことに固執するのであれば、安定して勝つ道は遠くなるだろう。

理想はそのまま保持しながらハイブリッドトレードを行い、安定して利益を上げながらシステムを改善し、最終的にシステムのみで勝てるようになれば、それでいいのではないだろうか。

(2017/03/27更新)

ハイブリッドトレードのすすめ

私はトレードスタイルの1つとして、ハイブリッドトレードを勧めたいと思う。

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

ハイブリッドトレードとは裁量トレードとシステムトレードを組み合わせたトレードである。現時点において、この用語は一部の人が用いているにすぎないようだ。裁量トレード、システムトレードに比べると一般的とは言えない。

裁量トレードはよく言えば臨機応変、悪く言えば感情的でルールがない。システムトレードはよく言えば理性的でルールがあり、悪く言えば融通がきかない。ハイブリッドトレードは双方のよいところを取り入れようという試みである。

私はトレーダー自身の研究によって作成したトレードルールに基づきつつ、一定の範囲内での裁量を許容するトレードと解している。裁量トレードとシステムトレードの両方を別々に行うことと解する人もいる。用語自体が一般的ではないから、多くの人に受け入れられている定義があるわけではない。

私のトレード遍歴

私がFXを始めた当初は裁量トレードであった。だが、まるで勝てなかった。

そこで、システムトレードに転向した。ようやく勝てるようにはなったが、安定して勝てるまでには至らなかった。

そして今、試行錯誤しながらハイブリッドトレードを行っている。断定的なことは言えないが、今のところ、安定して勝っているようである。

システムトレードが根底にあればこそ

ハイブリッドトレードがうまくいくかどうかはシステムトレードだけでもそれなりに勝てるということがカギである。例えば勝てないトレードルールを裁量の力で勝ちに転じる、というようなものはハイブリッドトレードではない。それほどの裁量トレードの才能があるなら、それ一本でやるべきだろう。

したがって、先ずはシステムトレードの研究が重要である。研究によって、それなりに勝てるトレードルールを見出すことができて初めてハイブリッドトレードが可能になる。もちろん、システムトレードだけで安定して勝てれば申し分ないが、それならシステムトレード一本でやるべきだろう。

専業でやりたい人にも有用

専業ではない私が言うのもおこがましいが、専業でやりたい人にもハイブリッドトレードは有用だと思う。

専業にも2つのスタイルがあるだろう。1つは裁量トレードであり、人によっては1日中、トレードにどっぷり浸っている。もう1つはシステムトレードであり、システムがちゃんと稼働しているか確認するくらいで、あとは自由に時間を使っている。

システムトレードにひいきした見方をすると、1日中、自分でトレードをするのであれば、普通に仕事しているのと変わらないではないかと思えなくもない。自営業者と雇われ労働者の違いはあるにしてもである。

専業トレーダーに憧れる人は雇われ労働者という境遇から逃れたいという気持ちもあるだろう。だが、労働そのものから解放されたい、自由に時間を使えるようになりたいという願望もあるのではないだろうか。

システム開発を除けば、自分で働かなくてもシステムが勝手に稼いでくれる。それはもちろん理想ではあるが、それが簡単にできることなら誰も苦労はしない。といって、自分でトレードするのでは自由に時間を使えるようにはならない。

そこで、ハイブリッドトレードである。ハイブリッドトレードでも勝てるトレードルールは必要である。だが、勝手に稼いでくれるシステムほど優れている必要はない。

システムにシグナルを出させてトレーダーに通知するようにする。トレーダーはそのシグナルに基づき、最終的には自分の判断でトレードを行う。通知がない限り、チャートを見る必要はないので、さほど時間は奪われない。

システムだけで勝つというのは理想ではあるが、ハードルは高い。あまりこれにこだわると専業への道は遠ざかるだけだろう。残念なことだが、時は人の成長を待ってはくれないのである。

裁量が下手なのだが…

裁量トレードが下手でシステムトレードに転向したという人も少なくないと思う。私もそうだった。中途半端なシステムに下手な裁量を加えたら、なおさら勝てないのではないかという疑問もあるだろう。

実にもっともな疑問である。確かにそのような場合もあることは否定できない。

ただ、裁量が下手な人はそもそもルールがなかったから勝てなかったのではないかと私は考えている。原理原則がないから感情的になり、負けてしまうのである。

だが、システムトレードの研究によって生まれたルールが今はある。研究は1日やそこらでできるものではないから、気付かないうちに経験も積んでいる。ルールを中心に据え、経験を活かせば、裁量は決してマイナスにはならないと私は考えている。

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

トレーダーは必ずしもシステムに従わないが、もちろん、好き勝手に無視していいわけではない。私はシステムに裁量を加えるに当たって、システムが持つポジションを持つことは許されるが、システムが持たないポジションを持つことは許されない、という大原則を設けている。

もう少し具体的には以下の4つの基本原則である。

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

悪い裁量トレードの例

悪い裁量トレードとして以下のような例がある。

  1. 他人の意見やその場の雰囲気に動かされ、根拠もないのにエントリーする。
  2. 含み損があると、プラ転するまでエグジットしない。つまり損切りしない。

エントリーする基準を自分で持っていないから、エグジットする基準もない。結局、でたらめにエントリーして勝つまで頑張る。運よくプラ転できればいいが、できないといつまでも含み損を抱え、下手をするとロスカットになる。

ロスカットが嫌で資金を追加し、さらに含み損を増やしてしまい、結局はロスカットになって、とんでもない大金を失うという話もよく聞く。自業自得とはいえ、ひどい話だ。

ハイブリッドトレードの基本原則の2と4はこれを避けるものである。

悪いシステムトレードの例

悪いシステムトレードとして以下のような例がある。

  1. 大きなイベントの予定など、エントリーを避けたほうがいい情報があるのに愚直にシグナルに従ってエントリーする。
  2. 相場が落ち着かず、利益が出てもなかなか伸びないとき、エグジットのシグナルがないからといって利食いしない。

イレギュラーな状況でシステムが過去の検証通りに機能しないことが予測されるのに、システムに逆らうことを恐れ、大数の法則を損なうとして無理にエントリーする。その結果、無駄なトレードをしてしまう。

エントリーしたはいいが、大きく上昇したと思ったら、急に下落するなど、相場が不安定なときがある。そういう場合、利益が出ていればもうけもので、さっさと利食って逃げたほうがいい。ところが、システムに従うことにこだわり、「損小利大」とか「損切りは早く、利食いは遅く」とかいった、よく知られてはいるが必ずしも根拠のない言葉に惑わされて利食わずに失敗したりもする。

ハイブリッドトレードの基本原則の1と3はこれを避けるものである。

最後に

私が考えるハイブリッドトレードとは大体このようなものである。もちろん、これに限ったことではないし、これが正しいなどというつもりは全くない。むしろ、ただの自己流である。

トレードのスタイルとして、裁量トレードか、それともシステムトレードか、という二者択一にとらわれている人が少なくないように思われる。そのためにトレードを無用に難しくしてしまっている。あまり固く考えず、もっと柔軟に双方を組み合わせる、というスタイルを試してみてはどうだろうか。

(2017/03/25更新)

相関係数とトレンド

相関係数とトレンドとの関係を考えてみる。

正相関ならトレンド的か?

時系列データにおいて、データの階差とその前のデータの階差とが正相関、つまり相関係数がプラスの場合、トレンド的と言えるだろうか。

また、逆にデータの階差とその前のデータの階差とが逆相関、つまり相関係数がマイナスの場合、平均回帰的と言えるだろうか。

この問いに対して何となく「そうだろう」と考えている人は少なくないのではないかと思われる。というか、私がそうだった(笑)。

ただ、共和分の時系列データは平均回帰的だが、必ずしも逆相関ではない。したがって、完全に対応しているわけではない。しかし、それでも対応しているケースが多いのではないかと私は考えていたのである。

y = sin(x)における相関係数

そういうケースが多いか少ないかということは置いておく。ここでは正相関であり、かつ平均回帰的であって、しかも、それが極端であるデータを作成してみる。これはいたって簡単で、「y = sin(x)」のデータを作成すればいいだけである。

先ず、データを作成して相関係数を見てみる。

In [1]:
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-360, 360, 1)
y = np.sin(x / 180 * np.pi)

diff = y[1:] - y[:-1]
diff0 = diff[1:]
diff1 = diff[:-1]
cor = np.corrcoef(diff1, diff0)[0, 1]
print('cor = ', cor)


cor =  0.999846842234


相関係数はほぼ1.0で、完全に近い正相関となっている。考えてみれば、これは当然である。sin(x)の向きはずっとプラスか、ずっとマイナスで、プラスからマイナス、またはマイナスからプラスに転じるのは頂点だけだからだ。

y = sin(x)のグラフ

では次に、同じデータを使ってグラフを作成して見てみる。

In [2]:
plt.plot(x, y, label='y = sin(x)')
plt.title('y = sin(x)')
plt.xlabel('x')
plt.ylabel('y')
plt.xticks([-360, -270, -180, -90, 0, 90, 180, 270, 360])
plt.legend(loc='upper right')
plt.axvline(x=0.0, color='black')
plt.axhline(y=0.0, color='black')
plt.tight_layout()
plt.savefig('sinx.png', dpi=150)
plt.show()



高校数学でよく見かけるグラフだが、改めて見ると完全に平均回帰的である。-1で買い、+1で売れば百戦百勝だ。

相関係数とトレンドは別物

ほぼ完全な正相関でありながら完全に平均回帰的であるデータを作成できるということを考えると、相関係数とトレンド(あるいは平均回帰)は全くの別物と見たほうがいいだろう。

(2017/03/20更新)

ランダムウォーク・データの作成 (2017/04/11)

ランダムウォークのデータを作成する。作成にあたってはUSDJPYのデータの日時を利用しているので、あらかじめ「ヒストリカルデータの加工」でデータを作成しておく必要がある。

import forex_system as fs
fs.get_randomwalk_data()

開始日と終了日はUSDJPYと同じになるので指定する必要はない。作成される足の種類もUSDJPYと同じである。

デフォルトの設定では1分足の単位で平均=0.0、標準偏差=0.01 / sqrt(1440)、歪度=0.0の正規分布に従うランダムウォークのデータが作成される。日足での標準偏差が0.01(1%)となるイメージである。

デフォルトとは違う設定で作成したい場合は以下のようにする。

import forex_system as fs
fs.get_randomwalk_data(mean=-0.00001, std=0.0005, skew=1.0)

この場合、平均=-0.00001、標準偏差=0.0005、歪度=1.0の非正規分布に従うランダムウォークのデータが作成される。歪度が0ではないのでランダムウォークと呼ぶのは正しくないかもしれないが、ここではランダムウォークとして扱う。