2018.04.11

​ 狙え一攫千金!-機械学習でビットコイン暴落相場を生き抜く-


お金が欲しいですか?

私は欲しいです。

お金があれば、食いっぱぐれる心配なく時間を過ごせますよね。

お金の制約がないのなら、仕事をしてもいいし、しなくてもいいし、自由。

自由のあまり時間を持て余し、かえって何をして時間を過ごしたらいいかわからない事を心配しますか?

そんな人にオススメが、子供向けおもちゃの定番の、あのカラフルなブロック遊具。子供がいるとおもちゃに触れる機会が増えますが、息子が喜ぶので近所のおもちゃ屋さんに行った時はそういったブロックで一緒に遊んであげています(訳: 子供そっちのけで遊んでいる)。実際に最近はこんな家を作ったり、
こんな小屋を作ったりしました。
  これは子供の遊びレベルですが、アイディア次第でなんでも作れるわけですから、大人がやれば手軽ながらも創造性が試される非常にやりがいのある創作活動になります。

ちょっと探せばこれとか、これとか完全に遊びの域を超えた作品がゴロゴロ見つかります。

お金が10億円ぐらいあれば、資産運用して食べていく収入を確保し、自宅の敷地にちょっとしたスタジオを建て、そういった創作に明け暮れることなど簡単です。どでかい作品を作れるようにブロックをまとめて買い、等身大の人物像、大きな建造物、乗り物、なんでも作れる。あまりにも大きいスケールの作品が作りたくなったら、自分でちまちま作るのは面倒なので、3Dプリンターの技術を流用して自動ブロック組み立て装置を作ればいい。ブロックの分類、整理に嫌気がさしたら、ベルトコンベヤーに流したブロックをディープラーニングで画像認識をしつつ、自動仕分する装置を開発しちゃう。そんな開発工程や作品制作過程を全部ビデオにとり、面白く編集すれば動画サイトの人気者になれる。

ところが、そもそも日本のしがないサラリーマンの平均程度の収入では、コツコツ貯金を続けたところで、

10億円なんて


いつまで経っても、


未来永劫、


永遠に、


貯まりやしないっ!!!


人生は短い。私は悲しい。


一方、世の中には投資というものがあります。投資といえば、昨年盛り上がったのがビットコインでしたが、今年に入ってドーンと価格が落ちましたね。

前回も言いましたが、相場はいつ暴落するかわからないのが怖いのです。もっと言えば、グーンと時間をかけて上がったものは必ず一瞬でドーンと落ちる事が定められているといっても言い過ぎではないのです。なぜか?私はこのグーン、ドーンこそが、相場を通してプロが儲けるメカニズムの根本であり、ひいてはマーケットの存在を支える原理の一つではないかと思います。値段が上がっている時は皆嬉しく、世界のあちこちのの浮かれた人からどんどんマーケットにお金が集まります。しかしいざ価格急落時には、原始的な取引手法を用いる素人は損を押し付けられ、プロは逃げ切り美味しい思いをし、業者はそれを横目にコツコツ手数料をかせぐ。そんな事が人類の歴史上いったい何回繰り返されてきたのでしょうか。これらの3つのうち一つでも欠けた金融のマーケットはないは言い過ぎでしょうか。

そうだとすれば、金融のマーケットを生き抜くためにはプロでなくてはいけません。プロと言っても金融マンとして給料をもらうという意味ではかならずしもなく、自分の力量で勝てるマーケットを選び、相場の上がり下がりに一喜一憂する事なく堅実に勝ちを積み重ねる。そしてそんなプロとしてマーケットに参加し、かつブロック創作の時間を十分に確保するにはスクリーンに張り付いている時間はないのです。そうなると、取引プログラムを作ってあとはコンピューター任せにするしかないのです。

前回はそんな動機からガウス過程という機械学習アルゴリズムを用いて改良ボリンジャーバンドを提案しました。普通のボリンジャーバンドでは独立に調節できない要素を別々に調節する事が可能で、かつあらゆる確率分布を用いたモデルを作る事が可能な、そういった方面のオタクにはたまらないものです。例えていうならば、今回はそこから一歩先を進み、実際に取引のシミュレーションをしてみたいと思います。

このプロジェクトの計画は次の通りです。

  1. 普通のボリンジャーバンドを使って取引シミュレーション
  2. ボリンジャーバンドに特徴量エンジニアリングの考えを導入してパワーアップ取引シミュレーション
  3. ガウス過程ボリンジャーバンドによるさらにパワーアップした取引シミュレーション
  4. 実際に取引してみる

(1),(2),(3) とそれぞれの性能を比較した後に、(4)で実践投入というわけです。ワクワクしますね。というわけで今回は(1)をやって見ます。方法は至ってシンプルです。

まず、MACDと呼ばれる指標を用いて今のトレンドが上がっているのか下がっているのかをチェックします。上がっている場合、プライスがボリンジャーバンドを上に突き抜けたところで1Bitcoinを買いエントリーします。どの程度突き抜けたらエントリーするかの閾値はあらかじめ設定したものに従います。

エントリー後はMACD を時間ごとにチェックし、プライス上昇のトレンドを検知した時点において売りでエグジットします。
このような戦略をベースに各種パラメーターを最適化し、損益が最も良い物を見つけます。

実行したPythobnコードは以下です。
# coding: utf-8
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import scipy as sp
from scipy.optimize import minimize

def sma(array, window_size):
    output = np.convolve(array, np.ones((window_size,))/window_size, mode="valid")
    padding = np.zeros([window_size - 1,])
    padding[:] = np.nan
    output = np.append(padding, output)
    return output

def ema(x, span):
    return x.ewm(span=span).mean()

def std(price, span):
    return pd.stats.moments.rolling_std(price,span)

def get_bb_df(df_input, span):
    df = df_input.copy()
    df["mid"] = (df["ask"] + df["bid"]) / 2.
    df["sma"] = sma(df.mid,span)
    df["std"] =  std(df.mid,span)
    df["ema_short"] = ema(df.mid,span)
    df["ema_long"] = ema(df.mid,int(span*26/12))
    df["macd"] =    df["ema_short"]    - df["ema_long"]     
    df["signal"] =    sma(df.macd,span)
    df["timestamp"] = pd.to_datetime(df["timestamp"], format='%Y-%m-%d_%H:%M:%S')
    return df


def plot(df_bb):
    plt.figure(figsize=[8,7])
    plt.subplot(2,1,1)
    plt.plot(df_bb.timestamp, df_bb.mid)
    plt.plot(df_bb.timestamp, df_bb.sma)
    plt.plot(df_bb.timestamp, 2* df_bb["std"] +df_bb["sma"] )
    plt.plot(df_bb.timestamp, -2* df_bb["std"] +df_bb.sma )
    plt.grid()
    plt.subplot(2,1,2)
    plt.plot(df_bb.timestamp, df_bb.mid)
    plt.plot(df_bb.timestamp, df_bb.buy, "bo")
    plt.plot(df_bb.timestamp, df_bb.sell, "ro")
    plt.grid()
    plt.show()

def settle(pos, pl, purchase_price, row, df_bb):
    pos = 0
    pl += row[1].bid - purchase_price
    df_bb["sell"][row[0]] = row[1].bid
    print "sell at", row[1]["timestamp"], "for", str(row[1].bid)
    return pos, pl

def trade( buy_thresh ,sell_thresh ,cutloss_thresh ,wait_thresh, df_bb):
    pos = 0
    pl = 0
    df_bb["buy"] = np.zeros(len(df_bb)) * np.nan
    df_bb["sell"] = np.zeros(len(df_bb)) * np.nan
    for row in df_bb.iterrows():
        (row[1].mid - row[1].sma)/ row[1]["std"]
        if  buy_thresh < (row[1].mid - row[1].sma)/ (row[1]["std"] +
        0.0000000000000001) \
                and pos == 0 \
                and row[1].macd > 0:
            pos = 1
            purchase_price = row[1].ask
            buy_index = row[0]
            
            print "buy at", row[1]["timestamp"], "for", str(purchase_price)
            df_bb["buy"][row[0]] = purchase_price
        elif pos==1 and \
                cutloss_thresh > row[1].macd:
            print "cut loss"
            pos, pl = settle(pos, pl, purchase_price, row, df_bb)
        elif pos==1 and sell_thresh < row[1].macd - row[1].signal \
                and row[0] - buy_index > wait_thresh:
            pos, pl = settle(pos, pl, purchase_price, row, df_bb)
    if pos == 1:
        pos, pl = settle(pos, pl, purchase_price, row, df_bb)
    print "final pl =", pl 
    return pl

span = 10000
skip = 10
buy_thresh = 2
sell_thresh = 1
cutloss_thresh = -10
wait_thresh = 12000


df = pd.read_csv("20180215-0220-clean.csv")
df = df.iloc[0:-1:skip]
print "df length", len(df)
df_bb = get_bb_df(df,span)

def optimise_trading(x):
    return -1 * trade(x[0],x[1],x[2], x[3], df_bb)
result = minimize(optimise_trading,[ buy_thresh ,sell_thresh ,cutloss_thresh
                                    ,wait_thresh], method="powell")
print "optimisation result", result
plot(df_bb)


結果が以下のグラフです。


上のグラフにボリンジャーバンドが描いてあり、下に取引のタイミング(青:買い 赤:売り)が示してあります。
今回のシミュレーションの結果、最適化したPLはなんと63,998円となりました。1ビットコイン大体100万円として一日で6%の利益がついた事になります。本当にこれだけ儲かったらすごいですね。

次回はこれを機械学習の発想をもってパワーアップさせます、一体どうなるんでしょうか?乞うご期待!

最後に

次世代システム研究室では、ビッグデータ解析プラットホームの設計・開発を行うアーキテクトとデータサイエンティストを募集しています。興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧からご応募をお願いします。

一緒に勉強しながら楽しく働きたい方のご応募をお待ちしております。