やっていくログ

にんげんをやっていきましょう

Windows への MinGW を利用した C/C++ 環境構築

以下の記事を参考にする。

lyncs.hateblo.jp

webkaru.net

 

ただし、上記記事の MinGW インストールボタンが現在は見当たらないので、以下のリンクからインストーラを入手して行う。

Downloading File /68260/mingw-get-setup.exe - MinGW - Minimalist GNU for Windows - OSDN

VSCode で TeX を使う準備 (Windows)

はじめに

VSCode上でTeXを使えるようにするまでの流れのメモ。

Windows環境。

 

1. TeX自体の準備

Microsoft Windows - TeX Wiki を参考に。

 

TeX Live のインストール

TeX Live/Windows - TeX Wiki に詳述されている。Installing TeX Live over the Internet - TeX Users Group から install-tl-windows.exe を入手し、インストールを行う。

…行うのだが、学科から貸与されているPCでやってみたら10時間以上かかった(!?)。

 

f:id:calpeace:20190325172518p:plain

 

2. VSCode側の準備

Visual Studio Code/LaTeX - TeX Wiki を参考に。

 

LaTeX Workshop のインストール

VSCode拡張機能から LaTeX Workshop を検索しインストールする。

 

・settings.json の編集

上記リンクに紹介されている settings.json の編集例だとうまくいかなかったので、次を参考にした。最速で最小構成のLaTeX環境をVSCodeに構築する - Qiita

生成される pdf を確認しながら編集できる。

また、ビルド時に生成される中間ファイルを自動的に消去するには、設定の Latex-workshop > Latex > Auto Clean を onBulit にしたうえで(こうするとビルドの成否にかかわらず自動でクリーニングされる)、以下のようにファイル形式を setting.json 内に書き込む。

"latex-workshop.latex.clean.fileTypes": [
"*.aux", "*.bbl", "*.blg","*.idx","*.ind", "*.lof", "*.lot", "*.out", "*.toc", "*.acn", "*.acr", "*.alg", "*.glg", "*.glo", "*.gls", "*.ist", "*.fls", "*.log", "*.fdb_latexmk", "*.synctex.gz", "_minted*", "*.nav", "*.snm", "*.vrb"
]

f:id:calpeace:20190326034535p:plain

 

「Python機械学習プログラミング 達人データサイエンティストによる理論と実践」を読んだ [読書ログ]

・書名

Python機械学習プログラミング 達人データサイエンティストによる理論と実践」(インプレス/Sebastian Raschka 著/株式会社クイープ 訳/福島 真太朗 監訳)

book.impress.co.jp

 

・動機/経緯

機械学習の"き"の字も知らないのはまずいだろうということで、衝動買いした一冊(中古で買ったらあとで新版があることに気づいた(初版と第2版の違いについては後述))。

しばらく積みっぱなしにしていたが、春休みを得たので少しずつ読み進め、ひとまず最後まで到達した。

 

・読者(わたし)のスペック(読前)

機械学習は全く知らない

Pythonを触ったことがある。Jupyter Notebookも使ったことがある。

・大学初年度程度の微積分、線形代数、最適化手法の知識(おきもち程度)

 

・読み方

本書にあげられているコードは、すべて筆者のgithub(GitHub - rasbt/python-machine-learning-book: The "Python Machine Learning (1st edition)" book code repository and info resource)から入手できる。ipynb形式なので、Jupyter Notebook上ですぐに実行できる。最初はコードを手打ちで写経していたが、これの存在に気づいてからはここからコードを入手して手元で動かしながら読み進めた。

以下は訳者の方の読み方ガイド。読み進める順番、必要な知識、読了後に読むとよい他書籍などが紹介されている。

thinkit.co.jp

 

・内容

章立ては以下のようになっている。新版では、13章以降が増強され、初版では概要を述べるにとどめられていたCNNやRNNについて実装まで紹介されている。また、それ以外の章についても増補されているため、今から買うなら新版(第2版)がよいと思う。とはいえ、初版でもそれぞれの手法についてよくまとまっている。

 

・第1章 「データから学習する能力」をコンピュータに与える

・第2章 分類問題 -- 機械学習アルゴリズムのトレーニン

・第3章 分類問題 -- 機械学習ライブラリscikit-learnの活用

・第4章 データ前処理 -- よりよいトレーニングセットの構築

・第5章 次元削減でデータを圧縮する

・第6章 モデル評価とハイパーパラメータのチューニングのベストプラクティス

・第7章 アンサンブル学習 -- 異なるモデルの組み合わせ

・第8章 機械学習の適用1 -- 感情分析

・第9章 機械学習の適用2 -- Webアプリケーション

・第10章 回帰分析 -- 連続値をとる目的変数の予測

・第11章 クラスタ分析 -- ラベルなしデータの分析

・第12章 ニューラルネットワーク -- 画像認識トレーニン

・第13章 ニューラルネットワーク -- 数値計算ライブラリTheanoによるトレーニングの並列化

 

・感想

・理論と実践とはいうものの、実践がメイン

各章では、まず理論や定義を述べてから実装や実践例が紹介されていく。ただ、読みやすさのためか、理論といってもイチから導出していくわけではなく、「このような考え方があります。このような変形が成り立ち、最終的にうれしい結果が得られるので、これを使っていきましょう」といった流れ(伝わるのか…?)。また、数式に頼らずに、手法の気持ちを説明しているところもあり、個人的には結構わかりやすかった。

理論をイチからやりたいなら、他の書籍を読む必要がある。ただ、モリモリ読み進めるには、理論と実装の配分はこれくらいがちょうどよいと思う。

機械学習における基本的な手法を概観できる

知識ゼロから始めたが、ひと通り読み通すことで、どんな手法があるのか概観できた。コードも前述のように提供されているので、手元で動かして「すっごーい!」と思いつつモリモリ読み進めることができる。

コードを隅から隅まで理解しようとしながら進めるより、とりあえず先へ進んで読み終えてしまったあとに、必要に応じて立ち戻れる本というような気がした。

・実際に使えるようになるには

ひと通り読み終えて記事を書いているが、実際に機械学習を応用していくには、自前のデータに手法を適用してみたり、あるいはKaggleに参加してみたりする必要がありそう。現状では本に従って「機械学習ベーシックツアー」に参加しただけなので…。

そうした他の問題に手法を適用するにあたって、辞書的に利用できる本でもあると思う。

・総括

初手で読む本にしては重いかなと思ったが、むしろ一気にさまざまな手法を見せてくれたので、お気持ちをつかむのにとてもよかった。

機械学習ガチ勢はすごいんだなぁという気持ちがますます強まった。

情報系ではないので、研究室で使うのかは微妙なところだが、時間をとって他の機械学習本も読んでいきたい。

動画編集ソフトAviUtlの導入メモ

ちょっとしたスライドショーを作るために導入。そのとき参照したサイトをメモ。

細部をいじれば高度な編集も可能らしい。また素材や解説もたくさんヒットする。

 

とりあえず導入と設定。すべて以下に従っておけばOK

aviutl.info

 

映像の裏で音楽を流したいとき、音楽ファイルをタイムラインに載せているのに無音になることがある。その時は以下の内容を確認する。

learth.seesaa.net

 

無料でそれっぽい動画を作れるのでありがたい。

pythonの並行処理のおべんきょうの参考

参考として先人の記事のリンクを貼る

動かし方
qiita.com

qiita.com

注意すべき点
qiita.com

並行処理関連の公式ドキュメント
docs.python.jp


試しに、5秒ごとに目的の動作を行わせる

import datetime
import time
import threading
import queue


def func1(event):
    while(1):
        event.wait()
        print('hoge')
        event.clear()
    
    
def func2(event):
    while(1):
        event.wait()
        print('fuga')
        event.clear()
    
        
def timer(event):
    while(1):
        time.sleep(1)
        now=datetime.datetime.now()
        print(now)       
        if now.second%5==0:
            event.set()           


if __name__ == "__main__":
    event = threading.Event()
    t1 = threading.Thread(target=func1, args=(event,))
    t2 = threading.Thread(target=func2, args=(event,))
    t3 = threading.Thread(target=timer, args=(event,))
    t1.start()
    t2.start()
    t3.start()

結果、5秒に1回 hoge fuga する

2019-02-26 00:07:32.680651
2019-02-26 00:07:33.700176
2019-02-26 00:07:34.703568
2019-02-26 00:07:35.704306
hogefuga
2019-02-26 00:07:36.713224
2019-02-26 00:07:37.718298
2019-02-26 00:07:38.732420
2019-02-26 00:07:39.739030
2019-02-26 00:07:40.753466
fugahoge
2019-02-26 00:07:41.767390
2019-02-26 00:07:42.777210
2019-02-26 00:07:43.786152
2019-02-26 00:07:44.799364
2019-02-26 00:07:45.815294
hogefuga
2019-02-26 00:07:46.828104
2019-02-26 00:07:47.832805
2019-02-26 00:07:48.848034
2019-02-26 00:07:49.858399
2019-02-26 00:07:50.863243
hogefuga
2019-02-26 00:07:51.865927
2019-02-26 00:07:52.879863
2019-02-26 00:07:53.895192
2019-02-26 00:07:54.898684
2019-02-26 00:07:55.899330
fugahoge
…

以後適宜追記

ZOZOの前澤社長がどのように100人抽選したかに関する一考察(1/8 16時更新)

※1/8 16時 表記の修正/1.2節補足/1.4節の追加/おわりに補足

 

 

はじめに

ZOZOの前澤社長の以下のツイートが年明け早々TLに溢れました。

1/8に当選者へのDMが送られたようですが、もしマトモに抽選したとしたら、どのようにこれだけ膨大な数の参加者から抽選したのでしょうか?

 

時間制約について

以下のツイートから、締め切りから抽選まで9時間以内に終えたことがわかります。

  

1. 選別せずに抽選した場合

該当のツイートをRTした人を列挙し乱数とかで抽選すれば公平そうです。ただこれだけ膨大になるとRTした人をどうやって抽出したのかが気になるところです。まずはRTした人を選別せずに抽選した場合について、以下のような仮説を検証していきます。

1.1 該当ツイートをRTした人のリストを直接入手した?

だれがRTしたかわかればそれが一番楽ですが、公式アプリやWebクライアントだと100人程度が表示限界のようです。そこでTwitterapiを使って入手できないかと考えます。しかし、apiでも直近100ユーザー分のidしか取得できないようです。*1

1.2 フォロワーのリストを入手してから該当ツイートをRTしているか調べる?

 1/8 12時時点で616万フォロワーですので、フォロワーの全貌を把握するのは難儀かと思いますが、一応このような手法も考えられます。フォロワーを取得するapiが存在し、1回のリクエストで5000 ids入手できます。*2 リミットは 15 times/15 minですので、5000 ids/min入手できます。これだとフォロワー全部取得するまで 1232 min = 20.5 h かかるので、時間制限に引っ掛かります。ここから各ユーザーのタイムラインを取得して該当ツイートが含まれているか(RTしたツイートが含まれている)調べることになるので、さらに時間がかかります。

フォロワーの取得を応募開始から随時行っていたとしたら、猶予が2日くらいに伸びます。その場合、フォロワーそれぞれについて、該当ツイートをRTしているか確かめます。あるユーザーのツイートを得るapiでは、リミットが900 times/15 minなので、60 times/minの頻度で確認できます。*3 この場合全フォロワーについて直近のタイムラインに該当ツイートのRTが含まれているか確かめることになります。しかし全フォロワーを終えるのに102,666 min = 71.2 dayかかります。また、1回のリクエストでは直近200ツイートまでしか取得できないので、ヘビーユーザーも除外されます。

1.3 ツイートを検索する?

[Twitter API] リツイートを100件より多く取得する方法 – プログラミング生放送

上記サイトにて紹介されていた方法では、1.1で述べた100ユーザー制限を突破できます。結果からidを抽出すればRTしたユーザーのリストが作れます。1回の検索で100件取り出せ、リミットは180 times/15 minですので、1200 ids/min入手できます。1/8 12時時点で該当ツイートのRT数は564万ですので、これだとRTしたユーザーをすべて取得するのに 4700 min = 78.3 h かかり、時間制限に引っ掛かります。

1.4 ユーザーidを乱数で生成し、そのユーザーがフォロワーかつ該当ツイートをRTしているか調べる

学科民をはじめとする方々から上記の意見をいただいたので追記します。

1.3までは、あてはまるユーザーを探しにいくという発想でしたが、逆にユーザーをランダムに選んでそのユーザーが当てはまっているか調べるという発想です。2018年10月時点でTwitterのアクティブユーザー総数は3億2600万、うち日本のユーザーは4500万。*4 また、1/8時点で前澤社長のフォロワー数は約600万です。したがって、全ユーザーの1.8%が前澤社長のフォロワーということになります(!?)。また、該当ツイートのRT数が1/8 12時時点で564万であり、仮にすべてフォロワーによるRTとすれば、この564万ユーザーを引き当てられればよいということになります。

ただ、これは現時点で生きているアカウントの総数であり、今までに数多くのアカウントが消えているため、もしランダムにidを指定しても生きているアカウントにヒットするかはわかりません。また、Twitterのユーザーidの生成規則を調べてみたのですが、明快な答えが得られずじまいでした。例えばTwitterのオフィシャルアカウント(@Twitter)のユーザーidは783214、自分のアカウント(2012/8作成)のユーザーidは9桁、最近作成されたアカウントだとユーザーidが10桁になっているようです。9桁対応でidを生成するのであれば条件に適合するユーザーへのヒット率は0.56%ですが、10桁対応するとヒット率が0.056%に落ちます。

生成されたidのアカウントがフォロワーかつ該当ツイートRT済みであることを確認するためには、手作業だと面倒なのでやはりapiに頼ることになります。まず社長をフォローしているか確かめます。あるユーザーのフォローリストを得るapiでは、リミットが15 times/15 minなので、1分に1ユーザーしかチェックできません。*5 RTしているか調べるのは、1.2節で述べたのと同様のapiを用います。

有効な100人を得るために、その100倍以上のidを生成して確かめなければいけないので、apiでやるには意外と時間がかかりそうです。もしこの手法を採用するなら、id生成した後は社員がやるのかもしれません。

 

2. リプライを送った人に限定して抽選した場合

 どうも1の手法だと時間制限に引っ掛かるっぽいので、リプライした人限定なのかもしれません。該当ツイートにリプライしたユーザーを列挙する手法について考えます。

ところが、「あるツイートに対するリプライ」を拾ってくるapiがないらしい。あるのは「あるユーザーに対するリプライ」を拾ってくるapiのみ。*6

該当ツイートについているリプライ数は39万、また該当ツイート以降のツイートについているリプライ数は、足し合わせても10万程度という感じです。したがって約50万のリプライのデータからidを抽出すればよいことになります。1回のリクエストで200件のリプライが取得でき、リミットは75 times/15 minですので、1000 replys/min入手できます。50万リプとして全所要時間は 500 min = 8.3 hですので、時間制限に引っ掛かりません。

リプしてきた人を重複を取りのぞいて100人抽選し、その人が当該ツイートをRTしていなかったり、フォロワーでなかったりしたら、追加で抽選していく感じになるかと思います。

 

おわりに

ちょっと検索してみると、実際に当選したのは具体的な目標を語ったリプを送った人が多いようです。届くDMにも、目標を応援している旨のメッセージが書かれているようです。最初は完全にランダムでやるつもりが、予想外に伸びてしまったため、急遽リプを送った人から選ぶ形に変えたのかもしれません。

また、Rate Limiting — Twitter Developersを見ると、

Standard API endpoints only, does not apply to premium APIs

 と書いてあります。Twitter Developersに課金すれば、ここまで述べてきたしょうもないリミットを回避することができるわけです。金は正義っぽい。

この企画に便乗してバラマキ企画をしている方で、本当にばらまく意思があって、課金もしたくない方は、上記の手法からお選びください(いるのか?)。

 

BitmexRektを題材に Tweetの取得・可視化・BTC取引botの話

この記事は eeic Advent calender 2018 その2 の第5日目の記事になっています。

4日目 EEIC走馬灯(落第学生三番煎じver) - acryloshobonileのブログ
6日目 eeic走馬灯(デバイス系かつ怠惰学生ver.)前編 - 自由帳

先輩方の走馬灯の間にお邪魔してすみませんというお気持ち…。
(強電系走馬灯、来年以降書いてみたい)

0. はじめに

電気電子工学科 B3 の者です。プログラミングは学科に入ってから始めました。普段は電力系の授業を受けたり実験をしたりしています。今回のコレはおべんきょうのための個人的な試みですが、アドベントカレンダーその2が空いてそうだったので記事としてまとめ、投稿させていただきます。
バックテストまでの全体のコードはGitLabにあげておきます。メインの処理は ipynb ファイルに記述しています。上手くないのでデータ保持の形式まわりがアレですが…。

1. BitmexRektについて

BitMEXとは、仮想通貨のレバレッジ取引を行う取引所です。Bitcoin をはじめいくつかの通貨が扱われており、取引量は世界最大級です。
一般にレバレッジ取引においては、ロスカットと呼ばれる自動精算システムがあります。(証拠金維持率)=100×(総資産評価額)/(必要証拠金) と定義し、証拠金維持率が一定の水準を下回ると、ロスカットが行われます。BitMEX では、ポジションが逆行して証拠金維持率が0%になるとロスカットされます。
BitmexRektとは、BitMEX において行われるロスカットを監視し、ツイートする bot のことです(図1)。ロスカットは一方的で大きな値動きがあるときに発生しやすいため、ロスカット発生情報は取引の参考とされています。
今回はこの BitmexRekt のツイートを取得し、得たデータをいじっていきます。

f:id:calpeace:20181213172254p:plain
図1 BitmexRektのツイート例

2. Twitterapiを使うために

2018年7月ごろに Twitterapi 制限が厳格化され、api を使うには Developer account としての登録が必要になりました。ここ で述べていますが、英作文をしなきゃいけないのでちょっと面倒です。アカウントを登録したら、app 登録を行って、api key など4種類取得します。

3. ツイートの取得

処理をpython-twitterというライブラリにすべてお任せします。
GetUserTimeline という関数を使うと、あるユーザーのツイートを取得することができるようなので、それを使います。
ツイートには id が振られており、それをもとに取得するツイートの範囲を指定することもできます。引数 max_id を使うと、そのid以前のツイートのみ取得することができます。
その他の機能については公式のドキュメントを参照してください。

今回は XBT/USD という Bitcoin 無期限取引のペアのみ抽出することとします。
Liquidated long は買い注文が清算されたことを表し、価格の下落が起きていることを示唆します。
Liquidated short は売り注文が清算されたことを表し、価格の上昇が起きていることを示唆します。
ロスカットが発生した時刻、方向、枚数を1セットのデータとして保存します。ここで方向については、買い注文の清算を-、売り注文の清算を+と定めます。
実際のコードは以下のように適当に。1サイクルで200ツイートが取得上限です。とりあえず600ツイート手に入れます。各種 key は予め読み込んでおきました。

api = twitter.Api(consumer_key=CONSUMER_KEY,
                  consumer_secret=CONSUMER_SECRET,
                  access_token_key=ACCESS_TOKEN_KEY,
                  access_token_secret=ACCESS_TOKEN_SECRET)
liquidated_list=[]
last_id=0

for i in range(3):
    if i==0:
        tweets = api.GetUserTimeline(screen_name="BitmexRekt",count=200)
    else:
        tweets = api.GetUserTimeline(screen_name="BitmexRekt",max_id=last_id-1,count=200)

    for tweet in tweets:
        word_list=tweet.text.split()
        if 'XBTUSD:' in word_list:
            if word_list[1]=='long':
                amount=(-1)*int(word_list[5].replace(",",""))
                at_price=float(word_list[7])
                liquidated_list.append([tweet.created_at,amount,at_price])
            elif word_list[1]=='short':
                amount=int(word_list[5].replace(",",""))
                at_price=float(word_list[7])
                liquidated_list.append([tweet.created_at,amount,at_price])
        last_id=tweet.id

#以下は word_list の format
#Liquidated short on XBTUSD: Buy 11,305 @ 3823.5

こうするとこんな感じのデータが格納されます。時刻、清算枚数、清算価格の順になっています。

 ['Thu Dec 13 09:04:55 +0000 2018', 47757, 3397.5],
 ['Thu Dec 13 09:04:50 +0000 2018', 83828, 3393.5],
 ['Thu Dec 13 09:04:44 +0000 2018', 43445, 3387.0],
 ['Thu Dec 13 09:04:37 +0000 2018', 225990, 3383.5],
 ['Thu Dec 13 09:04:32 +0000 2018', 223023, 3377.0],
 ['Thu Dec 13 08:27:10 +0000 2018', -499, 3358.0],
 ['Thu Dec 13 07:59:55 +0000 2018', 58351, 3374.5],
 ['Thu Dec 13 07:59:50 +0000 2018', 2682, 3373.5],
 ['Thu Dec 13 06:00:05 +0000 2018', 32335, 3368.0],
 ['Thu Dec 13 06:00:02 +0000 2018', 36405, 3364.0],
 ['Thu Dec 13 05:59:47 +0000 2018', 5010, 3360.5],
 ['Thu Dec 13 05:59:41 +0000 2018', 107903, 3358.5],
 ['Thu Dec 13 05:51:39 +0000 2018', -35209, 3338.5],
 ['Thu Dec 13 05:50:29 +0000 2018', -6002, 3342.5],
 ['Thu Dec 13 05:50:22 +0000 2018', -158472, 3344.5],
 ['Thu Dec 13 05:29:11 +0000 2018', -72500, 3346.5],
 ['Thu Dec 13 05:29:04 +0000 2018', -68622, 3348.0],

4. 実際の値動きとともにグラフを描画

cryptowatchapi を使うと各取引所の直近の価格データを手に入れることができます。
価格データの抽出は get_ohlcv.py の中に記述してあります。取引所と単位時間(1min, 3min, 5min, 15min, 30min, 60min 等)を与えると時刻、始値、高値、安値、終値を返す関数を用意してあります。
※12/18 追記
稀に欠損値 all 0 が返ってくることがある模様…?

取得したツイートから得たロスカット情報は、longとshortに分けて保持します。
また、グラフの開始時刻を価格データのスタート時刻にするため、それより昔のロスカットデータを捨てて整理します(価格データは1分足だと500分ぶんしかないので、だいたいロスカットデータのほうが余る)。
この辺の実装は冗長なだけなので具体的なコードは割愛します。

価格とロスカット情報を2段に分けてプロットさせると図 2 のようになります。青は long のロスカット、赤は short のロスカットを表しています。2段目のグラフの縦軸は清算枚数を表しています。おおまかに、価格の下落により long のロスカットが発生し、上昇により short のロスカットが発生している様子が見て取れます。
また、価格とロスカット情報を1つにまとめてプロットさせると図 3, 4 のようになります。ロスカット情報を表す点は、濃度が清算枚数と対応しています。これを見ると価格の上下とロスカットの対応の様子がより分かりやすいかと思います。

f:id:calpeace:20181213200925p:plain
図2 BitMEX価格とロスカット散布図

f:id:calpeace:20181213201002p:plain
図3 BitMEX価格とロスカット散布図

f:id:calpeace:20181213203729p:plain
図4 BitMEX価格とロスカット散布図(別時間帯)

5. 取引 bot 化に向けたバックテストと課題

4まででは、過去のロスカットを抽出し可視化してみました。
ここで、リアルタイムでロスカットツイートを取得することにより、取引 bot のシグナルとして利用できるのではないかという目論見が立ちます。
そこで、得たロスカットデータをもとに、簡単なロジックのバックテストを行ってみました。
バックテストのコードもメインの ipynb ファイル内に記述してあります。

取引ルールは以下のようにします。

long のロスカットが発生したら short で entry、short のロスカットが発生したら long で entry。
価格は、ロスカットが発生した時刻の分足の終値で entry、次の分足の終値で exit とします。
コードでは、この辺の処理がしやすいように、途中のデータ整理で時刻の秒を切り捨てています。
(ex. hh:mm:ss = 19:22:30 にロスカットが発生したら、19:22の分足の終値で entry、19:23の分足の終値で exit する。言い換えれば 19:23:00に entry、19:24:00に exit)

ここで、
profit factor = (総利益)/(総損失の絶対値)
max drawdown : グラフの最大へこみ
と定義します。
PF は大きいほうがよく、drawdown の絶対値は小さいほうがよいです。

まずはロスカットデータの元である取引所 BitMEX でのバックテスト結果を2例示します(図5, 6)。
500分ぶんの価格データを利用したバックテストで、図 5 と図 6 はそれぞれ別の日に採取したデータを用いています。
ロスカットが多いときはモリモリ、少ないときも着実に積み重ねている様子が見て取れます。

f:id:calpeace:20181213210455p:plain
図5 BitMEXにおけるバックテスト
f:id:calpeace:20181213210523p:plain
図6 BitMEXにおけるバックテスト(2)

次に、国内の取引所 bitFlyerレバレッジ取引価格データを使ってバックテストします。
シグナルは BitMEX のロスカットデータですが、価格は相互に追従しあうものだと思われるため、試してみました。
結果を2例示します(図7, 8)。グラフはBitMEXのバックテスト結果とよく似ています。強いですね。

f:id:calpeace:20181213211325p:plain
図7 bitFlyerにおけるバックテスト
f:id:calpeace:20181213211353p:plain
図8 bitFlyerにおけるバックテスト(2)

しかし、果たしてそうでしょうか。

おそらく、実際にこのロジックを bot 化して運用しても、ここまでうまくはいかないのではないかと思われます。以下に述べるような問題点があるためです。

  • ロスカットが発生するような場面では、サーバが遅延する

実際に注文を出す際には、注文を出した瞬間の価格で必ず約定するわけではありません。ある程度の価格のブレがあり得ます。
特に、ロスカットが発生するような場面では、価格の激しい上下動があり、注文数も増加するため、取引所のサーバの遅延が起きます。
今回のバックテストでは、必ず終値で約定するとしているため、この影響は無視できないわけです。

  • 売り板と買い板のスプレッド損

売りたい人は少しでも高く売りたい、買いたい人は少しでも安く買いたい、それゆえ売り板と買い板には価格差が生じます。
この価格差はスプレッドと呼ばれます。取引所を実際に眺めてみるとわかりやすいかと思います。
実際に entry する場合には、成行注文/指値注文のどちらかを選択して注文することになります。
成行注文とは、価格はいくらでも構わないので買わせてくれ/売らせてくれ、という注文方式です。
すぐに約定する代わりに、先ほど述べたスプレッドぶん不利な価格で売買していることになります。
指値注文とは、価格を指定して注文する方式です。
スプレッドによる不利益はなさそうですが、約定せずにさらに価格が上昇/下落して、チャンスを失ってしまう可能性があります。
バックテストでは、この影響を無視して必ず終値で約定するとしていましたので、実際の結果はこの影響を受けて変わってくるでしょう。

あくまでもデータで遊んでみた!という体験をまとめたものですので、これを鵜呑みにして取引されても一切責任はとりません。

※12/16 追記
フォワードテストもやってみているので、その結果も書くかもしれない。
※12/20 追記
フォワードテスト第1弾、書いた。

6. 取引 botフォワードテスト

せっかくなので、BitMEXのロスカットデータを生かした bot を作ってみます。
bitFlyer でのレバレッジ取引です。python で書いて AWS Cloud9 上で動かしています。
pybitflyer や ccxt を使ってちょっと慣れればシンプルな売買はすぐ実装できます。
先駆者の数多くの指南記事がありますので、興味があればググってみてください。

第 1 弾のロジックは、5 章でバックテストしたものを微調整して、以下の通りとしました。

(例)

時刻 ロスカット 取引
22:13:00~22:13:59 0
22:14:00~22:14:59 -200
22:15:00~22:15:59 -300 22:15:00 short entry
22:16:00~22:16:59 0 short hold
22:17:00~22:17:59 0 22:17:00 short exit

entry を指値にしたのは、最初に entry と exit どちらも成行にしたものを組んで回してみた結果、あまりに危なっかしかったからです。
また、ロスカットが続いている間は exit しないことに決めたのは、取引回数が増えることによる成行スプレッド損を軽減するためです。
たぶんロスカットが続いている間は利益が出る方向に価格が推移しているので、ポジションを持ちっぱなしでも大丈夫だと考えました。

図10のように、勝とうが負けようが bot は淡々と取引を行っていきます。

f:id:calpeace:20181220003112p:plain
図10 取引の様子

図 11 に、実際の損益推移を示します。ログインボーナスでもらえる微小な BTC 現物の価格変動の影響があるため、bot が止まっているときも損益変動が少しあります。
バックテストではドローダウンがほとんどなかったのに、この結果を見ると命からがら生き延びているだけという感じがします。
ロットを 0.05 としているので、バックテストの結果のおよそ 1/20 が 500 分で得られる収益の理論値なわけですが、とてもじゃないがそのレベルに到達していないようです。
実際に bot を回してみると、サーバーが注文を受け付けなかったり、ラグがあったり、価格が上下にブレて不利な約定価格になっていたり、といった問題に直面します。
これを書いている間に、所有ポジションをチェックするあたりで書き換えるべき点が見つかったので、もうすこし改善の余地はありそうです。
今後もロスカットデータを生かした bot のアイデアを試していきます。良さげなモノがあればここに追記していきたいと思います。

f:id:calpeace:20181220010405p:plainf:id:calpeace:20181220010509p:plain
図11 損益推移(左: 11:00ごろスタート / 右: 09:00ごろスタート)

7. おわりに

f:id:calpeace:20181213214511p:plain
図12 Bitcoin年初来チャート(trading viewより)
昨年の今頃は少なからぬ人々がビットコインビットコインだと言っていた印象ですが、今年はモリモリ下り坂です(図9)。
ただ、取引所を筆頭に api をモリモリ公開してくれたり、ccxt をはじめとする優秀なライブラリがあったりするおかげで、プログラミングの経験が浅い自分のような人でも、おべんきょうの題材とするのには悪くないんじゃないかと感じています。また、自分で組んだ bot が健気に動いている様子を眺めていると、結果がショボかろうと愛しさが湧いてきます。おもしろいものです。

日々控室で同期を見ていると、この学科には様々な分野に長けた強い人が多いなぁと感じます。
そんな強い人々が取引 bot 作りに手を出したらきっとすごいことになるんじゃないかと思いつつ、筆をおきます。

最後までお付き合いいただきありがとうございました。