akiyoko blog

akiyoko の IT技術系ブログです

「ビットコインとか勉強会#13」に参加してきました

会場

株式会社 LIFULL
〒102-0083 東京都千代田区麹町 1-4-4 8F

Twitter

twitter.com




ビットコイン取引高日本一の仮想通貨取引所 coincheck bitcoin
ビットコイン取引高日本一の仮想通貨取引所 coincheck bitcoin


 

全体の感想など

「ビットコインとか勉強会」の参加はこれで 5回目です。 *1, *2, *3, *4


最近はブロックチェーンの本を読んだりインターネットや Twitter で情報と集めたりしていろいろ勉強をしていて、仮想通貨やブロックチェーンの勉強会に行っても昔と比べて理解度が上がっていると思っていたのですが、「insight」や「electrumx」などのサーバサイドプロダクトの存在は初めて知りました。まだまだアンテナの張り方が足りないようですね。

もう少し話を聞きたかったので急遽、懇親会にも参加してみました。久々でしたが、すごくいい話が聞けました。

今回はどちらかと言うと開発者寄りの話でしたが、実際に手を動かしてコマンドを叩いてみるようなもくもく会的なイベントにも今後参加していきたいと思います。





 

ビットコインを支えるインフラについて

Yuki Akiyama 氏 (@you21979)(ビットバンク株式会社 ビットコインエンジニア)


暗号通貨 Advent Calendar 2017 - Qiita」を立てた方だとか。最近では、

などの記事も。

  • なぜインフラが必要なのか?
    • ウォレットを作るときに困るから
    • (自分以外の)ビットコインアドレスを指定して未使用のトランザクション(UTXO)の一覧を取得する、などの一見簡単なことができない
  • 解決するプロダクト
    • insight, electrumx
    • 端末側でウォレットを動かすためのバックエンドサーバ
  • insight
    • Node.js で作られている
    • REST-API で簡単に情報を取得できる(これがスゴイところ)
    • 5つの部品から構成されている
      • 魔改造版 bitcoind
      • bitcore-lib
      • bitcore-node(UTXOのデータベース)
      • insight-ui(ブロックエクスプローラの画面)
      • insight-api(REST-API)
    • マルチプラットフォームのウォレットをホスティングできる
    • まだ SegWit に対応していない(v5 から対応予定?)
      • Confirmされるまで見れない?
    • 最新版に追従しにくい。自分で魔改造版 bitcoind にパッチを当てる必要がある。かなり大変
    • データベースが巨大。来年には500BG超えそう。。
    • 開発が滞ってた?最近活発に?
    • オルトコインの対応は? ⇒ しにくい
      • 開発チームが insight の対応をしているところもあるが(Litecoin, ZCash, Dash, Zcoin)、結構不安定?
  • electrumx
    • ウォレットソフト electrum のサーバサイド実装
    • Python3で作られている。作者は kyuupichan
    • electrum を使ったクライアント? 例えば、Coinomi など
    • 最初からオルトコインに対応できるように設計されているのがスゴイ
      • 現在30種類くらい対応
      • coins.py に記述されているコインであれば、設定ファイルに記載するだけで対応可能。
      • 積極的にプルリクを取り込んでくれる
    • REST-API じゃないが、プッシュ通知とかがあって便利
    • APIの設計が細切れ?になってて、必要なデータを一度で取得できないため、いくつか組み合わせる必要あり
    • トランザクションをデコードしてくれない。自分で解析が必要
    • システム的に、定期的にメンテが必要。ダウンタイムが必要。オルトコインだと1ヶ月ちょっと??(ビットコインだと1年くらい)
    • ウォレット作るなら十分。他のことをやろうとすると大変??


 

しっかり学ぶ ICOのベストプラクティス

千賀 優作 氏 (@syrohei)(一般社団法人 分散技術総合研究所 代表理事)



千賀さんは最強のイーサリアマーだそうです。
RICO をオープンソースで開発中とのことで、それについての説明です。

  • スマートコントラクトが必要
  • (EIP20Token以外の)ICOの規格が統一されていない
    • 今年のICO の 90〜95%くらいは EIP20トークン?
    • Golem, Gnosis は受け取ったEtherを認識できないとか?で ICO が失敗したとか??
  • 学習コスト、開発コスト、ハードルが高い
  • セキュリティ的な要件、法的リスクもある
  • ICOのベストプラクティスとは?
    • スムーズなICOを実現するための準備
      • なりすましやフィッシング詐欺に適切な対処が可能
    • スマートコントラクトのメリットを強力に活用
      • Trusted なアプリケーションを低コストで稼働
    • コードの信頼性を維持
      • 絶対にバグをうまないコードを
  • RICOTruffle フレームワークによるベストでナイスな ICO開発
  • Ethereum のウィークポイント
    • Ethereum の tx は一つの tx で一つの method しか実行できない
      • 設計を考え直すこともしばしば
    • スマートコントラクトの無限ループが発生しやすい
      • 再帰的呼び出しに弱い(The DAO の攻撃)
    • 設計が複雑になりやすい。挙動を正確に把握しないとガスが無駄になりがち
    • 構造体が使いにくい(代わりにコントラクトを新規に生成したほうがいい?)
    • function() は多用しない(無限ループの脆弱性)
    • できる限りグローバル変数(外部変数)は使わない。設計を見直す
    • 条件分岐(if else)を多用し過ぎるとテストしづらくなるので、適度に列挙型 enum で状態遷移を明確に
    • 常にガスの利用を意識した処理を心がける(ストレージをなるべく使わない)
  • Truffle は Solidity ベースのスマートコントラクトを作成するのに最適
    • 最低限のコントラクト管理機能があり、テストも簡単に書ける
    • もはやデファクトスタンダードに
  • RICO における Proof of Donation による寄付証明とイベントハンドリング
  • RICO は、ICOに最適化されたオープンソースフレームワーク
    • Truffle のテンプレートエンジン
    • 誰かが誰かに寄付をした、ということを証明する
    • (機能拡張すれば)ホワイトリストにも対応できる

イーサリアムのスマートコントラクトについて知りたい、あるいは開発をしてみたいという方にはこちらの本が有益だと思います。私も最近読み終えました。

*1:<過去記事> akiyoko.hatenablog.jp

*2:<過去記事> akiyoko.hatenablog.jp

*3:<過去記事> akiyoko.hatenablog.jp

*4:<過去記事> akiyoko.hatenablog.jp

まだ CSV の文字化けで消耗してるの?(Excel で直接開いても文字化けしない CSVファイルを Python3 で作成するスマートな方法)

この投稿は 「python Advent Calendar 2017 - Qiita」 の 9日目の記事です。

こんにちは、akiyoko です。
「Python Advent Calendar」は 4年連続 4度目の参加になります。 *1, *2, *3



はじめに

皆さん、CSV は好きですよね? Excel も大好きですね?
じゃあ当然、CSVファイルは Excel で開きますよね。

文字化けは? ・・もちろん嫌いですよね。
でも CSVファイルを Excel で開こうとしたときに、こんな文字化け地獄を経験したことはありませんでしたか? *4


f:id:akiyoko:20171205230423p:plain:w400


ということで今回は、Excel で直接開いたときに文字化けしない CSV ファイルを Python3 で作成する方法 を紹介したいと思います。(おまけで Python2 でのやり方も書いておきますが、今時 Python2 で消耗している人なんていないですよね? *5



 

結論

結論を先に書くと、

  • Unicode の文字符号化方式は 「UTF-16(正確には、BOMありの UTF-16 LE)」
  • タブ区切り

で CSVファイルを作成すれば、Excel で直接開いても文字化けせず、それぞれの値がセルごとに分かれて表示されます。


(参考)Which encoding opens CSV files correctly with Excel on both Mac and Windows? - Stack Overflow



Windowsでは、リトルエンディアンのUTF-16符号化スキームが使われている。内部表現では16ビット符号なし整数を符号単位とするUTF-16符号化形式(CEFなのでBOMはなし)として扱い、ファイルなどではBOMありのUTF-16符号化スキーム(リトルエンディアン)が主である。


UTF-16 - Wikipedia

Note Microsoft uses UTF-16, little endian byte order.


Using Byte Order Marks | Microsoft Docs

とあるように、Microsoft Excel が 「BOMありの UTF-16 LE」を扱っているため、この方法がベストと言えそうです。


なお、「CSV(Comma-Separated Values)」と言いながらも区切り文字がタブなので、厳密には「TSV(Tab-Separated Values)」と呼ぶべきでしょうか。議論の余地はあるものの(*6)、拡張子を「.csv」としておくことでダブルクリック時に自動的に Excel が起動してくれるので(アプリケーションが関連付けられているので)、拡張子は「.csv」とした方がよいでしょう。



 

検証(Python 3)

ファイルオープン時に「encoding='utf-16'」と指定することで、符号化方式が「UTF-16 LE with BOM」となります。
「encoding='utf-8-sig'」(UTF-8 with BOM)だと、環境によっては(Mac + Excel 2011 とか?)文字化けすることがあるので推奨しません。

import csv


def main():
    rows = [['髙﨑 將'], ['あああ', 'いいい', 'ううう'], ['Ⅰ・Ⅱ・Ⅲ', '①②③']]

    # OK
    with open('utf_16_excel_tab.csv', 'w', newline='', encoding='utf-16') as f:
        w = csv.writer(f, dialect='excel-tab', quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # これでもOK
    with open('utf_16_excel_tab_2.csv', 'w', newline='', encoding='utf-16') as f:
        w = csv.writer(f, dialect='excel', delimiter='\t', quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化けしないが、セルごとに分かれないのでNG
    with open('utf_16.csv', 'w', newline='', encoding='utf-16') as f:
        w = csv.writer(f, quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化け (しない場合もある)
    with open('utf_8_sig.csv', 'w', newline='', encoding='utf-8-sig') as f:
        w = csv.writer(f, quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化け (しない場合もあるが、セルごとに分かれないのでNG)
    with open('utf_8_sig_excel_tab.csv', 'w', newline='', encoding='utf-8-sig') as f:
        w = csv.writer(f, dialect='excel-tab', quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化け
    with open('utf_8.csv', 'w', newline='', encoding='utf-8') as f:
        w = csv.writer(f, quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化け
    with open('utf_8_excel_tab.csv', 'w', newline='', encoding='utf-8') as f:
        w = csv.writer(f, dialect='excel-tab', quoting=csv.QUOTE_ALL)
        w.writerows(rows)


if __name__ == '__main__':
    main()


OK

f:id:akiyoko:20171205231119p:plain:w500

セルごとに分かれない

f:id:akiyoko:20171205231145p:plain:w500

文字化け

f:id:akiyoko:20171205231136p:plain:w500


なお、確認した環境は、

  • macOS 10.12.16 + Microsoft Office 365 & Excel for Mac 2011
  • Windows 10 + Microsoft Office 2010

です。



ちなみに、open 時に「newline=''」を指定している理由は、Windows 対策のためです。


(参考)

 

おまけ(Python 2)

# -*- coding: utf-8 -*-
import cStringIO

import codecs
import unicodecsv as csv


class UnicodeWriter:
    """
    A CSV writer which will write rows to CSV file "f",
    which is encoded in the given encoding.
    """

    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
        # Redirect output to a queue
        self.queue = cStringIO.StringIO()
        self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
        self.stream = f
        self.encoder = codecs.getincrementalencoder(encoding)()

    def writerow(self, row):
        self.writer.writerow([s.encode("utf-8") for s in row])
        # Fetch UTF-8 output from the queue ...
        data = self.queue.getvalue()
        data = data.decode("utf-8")
        # ... and reencode it into the target encoding
        data = self.encoder.encode(data)
        # write to the target stream
        self.stream.write(data)
        # empty queue
        self.queue.truncate(0)

    def writerows(self, rows):
        for row in rows:
            self.writerow(row)


def main():
    rows = [[u'髙﨑 將'], [u'あああ', u'いいい', u'ううう'], [u'Ⅰ・Ⅱ・Ⅲ', u'①②③']]

    with open('test_unicode_writer.csv', 'w') as f:
        w = UnicodeWriter(f, dialect=csv.excel_tab, encoding='utf-16')
        w.writerows(rows)


if __name__ == '__main__':
    main()

https://docs.python.org/2/library/csv.html#examples の UnicodeWriter をそのまま使えばいいよという話ですが、それにしても面倒臭いですよね。いっそ滅んでしまえばいいのに、Python2。



 

まとめ

Excel で直接開いても文字化けしない CSVファイルを Python3 で作成するには、

  • ファイルオープン時に「encoding='utf-16'」と指定
  • csv.writer の引数に「dialect='excel-tab'」と指定

とするのがスマートで確実です。

今回はちょっとレガシーな話題でした。



明日は、driller さんの「python Advent Calendar 2017 - Qiita」 10日目の記事です。
よろしくお願いします。




 

おまけ

文字コードに詳しくなりたい人は、こちらをどうぞ。

*1:《過去記事》akiyoko.hatenablog.jp

*2:《過去記事》akiyoko.hatenablog.jp

*3:《過去記事》akiyoko.hatenablog.jp

*4:ネタが古いですね。図は、「悪循環画像ジェネレータ」を利用させていただきました。

*5:・・はい、私です。

*6:「タブ区切りは CSV じゃなくて TSV だろ」問題がついに解決した - 頭ん中

「あなたの趣味は?」のアンケート結果を R で因子分析してみた

この投稿は 「R Advent Calendar 2017 - Qiita」 の 4日目の記事です。

こんにちは、akiyoko です。
「R Advent Calendar 2017」は 3年ぶり 2回目の参加になります。 *1

何をしたのか?

「あなたの趣味は?」というアンケート結果に対して「因子分析」を実施 することで回答の奥に潜む共通要因を探り、どんな趣味趣向を持った人たちがアンケートに回答してくれていたのか? を分析してみました。


具体的にはこんなシチュエーションです。

現在、アンケートの回収に Google Forms を使っていて、回答項目の一つに「あなたの趣味は何ですか?」(*2)という項目が含まれています。例えばこんな感じです(実際には他にも項目があります)。


f:id:akiyoko:20171202235107p:plain:w300

趣味アンケート

Q1.あなたの趣味は何ですか? 当てはまるものを次の中から全てお答えください


【選択肢】特に無い/将棋/囲碁/チェス/ポーカー/麻雀/その他のボードゲーム・テーブルゲーム/TVゲーム・PCゲーム(携帯用を含む)/映画鑑賞/音楽鑑賞/楽器演奏/演芸・演劇鑑賞/美術鑑賞/スポーツ観覧/ダンス/料理・お菓子作り/ガーデニング/読書/ネットサーフィン/パチンコ・パチスロ/競馬・競輪・競艇/カラオケ/その他(自由回答)


回答結果をグラフにすると、以下のようになりました。

f:id:akiyoko:20171203003721p:plain:w500

しかしながら、このままでは面白くない。何か新しい視点で分析できないものか? *3

ということで、このアンケート回答者の趣味の傾向から、どんなクラスタの人たちがアンケートに回答してくれているのか?ということを趣味の背後に潜んでいる共通因子から推測してみよう、と思い立ったわけです。


 

そもそも因子分析とは?

こちらの説明が非常に分かりやすいです。

  • 因子分析は,複数の変数間の関係性を探る際によく用いられる手法である(ただし正確には潜在的な変数を仮定するのだが,以下に説明する)。
  • 因子分析をする目的は,「因子」を見つけることである。
  • 因子とは,実際に測定されるものではなく,測定された変数間の相関関係をもとに導き出される「潜在的な変数」(観測されない,仮定された変数)である。
  • 言い換えると,因子分析とは「ある観測された変数(たとえば質問項目)が,どのような潜在的な因子から影響を受けているか」を探る手法といえる。


心理データ解析第8回(1)」より


よく「主成分分析」と混同しやすい「因子分析」ですが、

  • 因子分析をする目的は「共通因子を見つけること」である
  • その一方で,主成分分析の目的は「情報を縮約すること」である。

心理データ解析補足01」より

といった違いがあります。上記サイトの図が特に分かりやすいです。

私の感覚では、主成分分析は、主成分を1つに縮約して観測された変数に重み付けをして各データ行の「合計得点」を求めたいときや、主成分を2つに次元圧縮して特徴量を一つの散布図にまとめて表示するときに使うもの、と考えています。



 

なぜ R?

普段は Excel や Python でデータ分析をしていて R は使わないのですが、私の知る限りでは、因子分析に関しては Excel 単体ではできず、Python でも簡単にできるようなものがありません(scikit-learn には sklearn.decomposition.FactorAnalysis というクラスがあるのですがそれを使ったサンプルが何故かあまりありません。主成分分析をするサンプルならいつくもあるのですが・・)。
その点、R なら超簡単に出来てしまうことが分かってからは、因子分析には R を利用するようにしています。

実践

ここからが本番です。

Google Forms のアンケート結果をクレンジングしてファイルを CSV形式で保存し、R に読み込ませて分析します。

データクレンジング

Google Forms からアンケート結果を xlsx形式でエクスポートすると、こんな感じになっています。

f:id:akiyoko:20171202163927p:plain


Excel関数を使ってチェックボックス形式のデータを整形します。
具体的には、別の Excelファイルを新規作成し、(選択肢として不要なので)「特に無い」「その他」の列を削除した後、以下のようにして「0」「1」のデータに変換します。

f:id:akiyoko:20171203003640p:plain


[ファイル]>[名前を付けて保存]から、ファイルを CSV 形式で保存します。
ファイル名は、例えば「factor_analysis.csv」など、日本語を使わない方が無難です(RStudio から読み込めない可能性があります)。

将棋,囲碁,チェス,ポーカー,麻雀,その他のボードゲーム・テーブルゲーム,TVゲーム・PCゲーム(携帯用を含む),映画鑑賞,音楽鑑賞,楽器演奏,演芸・演劇鑑賞,美術鑑賞,スポーツ観覧,ダンス,料理・お菓子作り,ガーデニング,読書,ネットサーフィン,パチンコ・パチスロ,競馬・競輪・競艇,カラオケ
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0
1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0
(以下略)

 

RStudio にデータ投入

インストールしていない場合は、公式ダウンロードページ から RStudio をダウンロードしてインストールします。
私が使ったバージョンは、RStudio for Mac(Version 1.0.153)です。


作成した CSVファイルを読み込みます。

> data <- read.csv(file="~/Downloads/factor_analysis.csv", header=T, fileEncoding="Shift-JIS")
> head(data)
  将棋 囲碁 チェス ポーカー 麻雀 その他のボードゲーム.テーブルゲーム TVゲーム.PCゲーム.携帯用を含む. 映画鑑賞 音楽鑑賞 楽器演奏 演芸.演劇鑑賞 美術鑑賞 スポーツ観覧 ダンス 料理.お菓子作り
1    0    0      0        0    0                                   1                               0        0        0        0             0        0            0      0               0
2    0    1      0        0    0                                   0                               0        0        0        0             0        0            0      0               0
3    1    0      0        0    0                                   0                               0        0        0        0             0        0            1      0               0
4    1    1      0        0    1                                   1                               0        0        0        0             0        0            0      0               0
5    0    0      0        1    0                                   0                               0        0        0        1             0        0            0      0               0
6    0    0      0        0    0                                   0                               0        1        1        0             0        1            0      0               0
  ガーデニング 読書 ネットサーフィン パチンコ.パチスロ 競馬.競輪.競艇 カラオケ
1            0    0                1                 0              0        0
2            0    0                0                 0              1        0
3            0    1                1                 0              0        0
4            0    0                1                 0              0        0
5            0    0                0                 0              0        0
6            0    1                0                 0              0        0

上記は CSV ファイルのエンコード形式が「Shift-JIS」の場合の記述ですが、もし「UTF-8」にした場合は「fileEncoding="UTF-8"」とすれば OK です。


 

RStudio で因子分析

以降は、ほぼ「Rで因子分析やってみた」のままです。

まずは、因子数を決定します。

> c <- cor(data)
> e <- eigen(c)$values
> e
 [1] 2.7796088 2.6282309 1.7220938 1.6669475 1.4724370 1.3176913 1.2386144 1.0709480 0.9855064 0.8927945 0.7569210 0.6899642 0.6341069 0.6018854 0.5724795 0.4168670 0.3761065 0.3551432 0.3143882
[20] 0.2790165 0.2282491

固有値のグラフをスクリープロットとして出力します。

> plot(e, type="b", main="Scree Plot", xlab="Number", ylab="Eigenvalue")

f:id:akiyoko:20171203004038p:plain:w500


固有値の減少がなだらかになる直前までの固有値の数を因子数とする(スクリー基準)、および、因子数の基準となる固有値の最小値を「1」とする(カイザーガットマン基準)を考慮して、因子数を「6」としました。 *4, *5


最後に、因子数を 6 として因子分析をおこないます。

> factanal(x=data, factors=6, rotation="promax")

「rotation」の引数は、"none", "varimax", "promax" などがありますが、今回は、因子間の相関を仮定しないする(2017.12.26 訂正)プロマックス回転「 promax」を選択しました。 *6


f:id:akiyoko:20171203004437p:plain
f:id:akiyoko:20171203004450p:plain


この結果を因子負荷量の大小で色付けすると、以下の表のようになります。

f:id:akiyoko:20171203004907p:plain:w500


上記の表から、以下のように共通因子(趣味趣向クラスタ)を分類してみました。あくまでも仮説ですが。

  • 因子1:「麻雀」「囲碁」「将棋」の因子負荷量が大きい ・・・ 囲碁将棋系
  • 因子2:「美術鑑賞」「演芸・演劇鑑賞」の因子負荷量が大きい ・・・ アート系?
  • 因子3:「楽器演奏」「料理・お菓子作り」「ダンス」の因子負荷量が大きい ・・・ 音楽系?
  • 因子4:「競馬・競輪・競艇」「パチンコ・パチスロ」の因子負荷量が大きい ・・・ ギャンブル系
  • 因子5:「その他のボードゲーム・テーブルゲーム」「チェス」の因子負荷量が大きい ・・・ その他のボードゲーム系
  • 因子6:「映画鑑賞」「音楽鑑賞」の因子負荷量が大きい ・・・ オーソドックスな趣味系?


一部強引なところもあるかもしれませんが、アンケートに回答した人が「ああ、私はこの趣味趣向クラスタだな」と分かりやすいような分類になっているのではないかと思います。




 

まとめ

  • 因子分析は R でやれば超簡単
  • 数行で書けるよ

これを言うためだけに 8000字オーバーの記事を書いてしまいました。。



明日は、yamano357 さんの「R Advent Calendar 2017 - Qiita」 5日目の記事です。
よろしくお願いします。


 

おまけ

因子分析の結果表示でそれぞれの出力行がガタついて項目がズレてしまう場合は、
[Preferences]>[Appearance]から、Editor font に「Osaka-Mono」を選択すれば解決します(Mac の場合)。


f:id:akiyoko:20171203182418p:plain:w350



今回の場合はグラフ描画時に日本語を出力していませんが、RStudio でグラフを描画する際に文字化けしてしまう場合は、

par(family="HiraKakuProN-W3")

と事前に実行しておけばよいです。 *7

*1:《過去記事》akiyoko.hatenablog.jp

*2:今回はインドア系の趣味についてのみアンケートしました。

*3:選択肢に挙げた15種類の趣味は、総務省統計局が5年ごとに実施している「社会生活基本調査」(出典:平成28年 社会生活基本調査結果(総務省統計局))の「趣味・娯楽」の34種類の区分のうちの15種類と一致させているので、やろうと思えば、その種類別行動者数(≒趣味にしている人の割合)と照らし合わせることで世間一般の平均的な趣味趣向と比較することもできます。

*4:http://cogpsy.educ.kyoto-u.ac.jp/personal/Kusumi/datasem06/minemoto.pdf

*5:実際には「5」から「7」を順次選んで計算したところ、「6」が結論を導きやすかったという理由もあります。

*6:因子分析における因子軸の回転法について | Sunny side up!

*7:Rとウェブ解析:MACでグラフの日本語文字化けを防ぐ簡単な方法

「bitFlyer Drink Meetup! #9」に参加してきました

主催

bitFlyer

会場

株式会社bitFlyer 本社
東京都港区赤坂 9‐7‐1 ミッドタウン・タワー 8F



 

全体の感想など

11/28 から 11/30 までの直近3日間だけで

  • POSレジでの決済サービス開始 *1
  • 米国進出(bitFlyer USA Inc.) *2
  • FX 初のサーキットブレイク発動 *3

と(良くも悪くも)話題に事欠かない日本最大の仮想通貨取引所を運営する bitFlyer の勉強会に参加してきました。


bitFlyer ビットコインを始めるなら安心・安全な取引所で


国内シェアが8割、テレビCM を大量投入するなど、ビットコイン・仮想通貨の取引所としてはノリにノッている bitFlyer ですが、全銀協が推薦する実証実験プラットフォームベンダーに選出されたとの発表もあったことから、取引所以外にブロックチェーン自体にも注力していこうという方向性が窺えます。 *4


現在は「miyabi」という自社製ブロックチェーンをゼロから作っているとのことです。開発言語は C# で、チームがまだ小さいということもあってかお披露目はまだ当分先のようです。 *5



あと、会場はこんな感じで(私の写真ではありません)、六本木ミッドタウンの新オフィスに引っ越して 1ヶ月とのことでフロアも雰囲気もピカピカなオフィスでした。社員も90名に急増したとのことで、さすがノリノリですね(よく見ると床に刻み海苔らしきものが散らばってましたが、前日のイベントでピザでも食べたのでしょうか。まさにノリノリ)。




bitFlyer ビットコインを始めるなら安心・安全な取引所で



さて、LT の内容ですが、Hyperledger Sawtooth は今回初めて聞きました。PoET(Proof of Elapsed Time)も初耳です。

公式ドキュメント によると、Intel SGX のチップを使った Intel サーバ群を TEE(Trusted Execution Environments:信頼済み実行環境?)としたブロックチェーン上で、待ち時間をランダムに割り当てられたノードペアがブロックの承認をおこなうという仕様になっているようです(間違っていたらすいません)。

ただし PoET が動作するのは、Intel の分散台帳プラットフォーム「Sawtooth Lake」など限定的なブロックチェーン上のみのようで、実質 PoET はパブリックチェーンとしては利用できないということでしょうかね。
しかも、

実験用途にしか利用を推奨していない。
独自のコンセンサスアルゴリズムPoETを持つが、これは本来intelが提供するハードウェアを利用して行われるため完全版ではなく、オープンソース版ではシミュレータが用意されている。


開発は続けられているが、正式なプロダクトへの採用を勧めていない為、選択肢にはならない。


さまざまなブロックチェーン技術」より

とあるように、メインは実験用途とか。登壇者も「実務では使っていない」と言っていましたので、miyabi 開発のために他製品を調査してみたということなのかもしれません(実際、他の方も「社内勉強会の資料を外に出せるように手を入れた」と言っていました)。なお今回のデモは Docker のシミュレータ上で動作させるため、Intel SGX の TEE は利用しておらず、Mac でも問題なく動かせるというカラクリのようです。

また、(サンプルの ○✕ゲームの実装がそうなっているだけかもしれませんが、)Ether の Gas のようなトランザクション手数料の仕組みがないため、ノードのマイニングの報酬がなく、ノードを立てる経済インセンティブをどう設計するかについてはシステム上の懸念が残ります。というかそもそも、 Hyperledger 系プロダクトは分散台帳と暗号技術で守られた P2Pネットワーク、コンセンサスアルゴリズムを使いやすいように提供しているだけで、ブロックチェーン経済圏は範疇外ということなのかもしれません。

ブロックチェーンプラットフォームとしてメジャーなのはBitcoinとEthereumですが、それらとHyperledgerとの大きな違いは、bitcoinにとっての「bitcoin」、ethereumにとっての「ether」のような仮想通貨の単位がHyperledger には存在しないことです。Hyperledgerでは、純粋にブロックチェーンの持つ分散型台帳という特性を仮想通貨に限らず社会の様々なソリューションの技術基盤として汎用的に活用できるように開発されています。


Hyperledger入門 : Hyperledger(ハイパーレッジャー)って何? | BlockChain Online ブロックチェーンオンライン」より


Hyperledger プロジェクトの立ち位置については、http://doublehash.me/tag/hyper-ledger/ の図が分かりやすかったです。しかしながら Hyperledger Sawtooth はどちらかと言えば、Transaction and data は「Public」、Mining/Consensus は「Trusted(consensus)」(つまり図の左下のエリア)なんじゃないかな?と思いました。




まあそれはさておいて、(私が長年 Python を使ってきたということもあって)Python で任意のスクリプトを書けるのは面白いな、と思いました。
Python 製のブロックチェーンとしては他にも、

  • HydraChain
    • Ethereum の拡張版で、コンソーシアム型またはプライベート型のブロックチェーンを構築可能。Python でコントラクトを書けるのが特徴。
  • BigchainDB
  • DragonChain

などがありますが、Python で自由にコントラクトを記述できる有名どころとしては HydraChain が挙げられるでしょうか。ただし、HydraChain はノードが最低限 6台必要ということで検証用途としては Hyperledger Sawtooth に軍配が上がるということなのかもしれません(実際試してみましたが、Docker 上でデモを動かすのは非常に簡単でした)。



 

WindowsのDocker環境でブロックチェーンを動かしてみる

越智 佳景 氏(ブロックチェーンエンジニア 株式会社 bitFlyer)

  • Hyperledger
    • ビジネスのためのブロックチェーン技術 *6
    • Linux Foundationで開発
    • オープンソース
    • Sawtooth (ソウトゥース)は Hyperledger プロジェクトの一つで Intel が開発を主導 *7
  • PoW は参加者が限定されていない場合に有効
  • Sawtooth トランザクション
    • アプリ開発者が任意に設計できる
    • Validator が Transaction Processor(ビットコインのスクリプトに相当)に問い合わせ
    • ステートを変更する
  • Sawtooth ブロック
    • 代表ノードがブロックを作る
      • Intel SGX のチップ、Intel のサーバを信用する??
    • PoET(Proof of Elapsed Time:時間に応じてブロックを作れる可能性が高まる)
  • Docker
    • 3月あたりにEE(Enterprise)とCE(Community)に分かれた
    • 実行方法は二つ
      • Dockerfile(docker build . で Imageを作って docker run)
      • 複数コンテナをまとめて起動する場合は docker-compose.yaml(docker compose up でコンテナを起動)

なおブロックについては、チェーン内部にタイマーがあり、一定時間ごとに自動的にブロックが作られるようになっているとのこと。また State は、トランザクション外(メモリ上?)で管理されるそうです。




 

macOS の Docker環境で Hyperledger Sawtooth を動かす

ここから、私の macOS の Docker 上で Hyperledger Sawtooth のデモを動かしてみます。

環境は以下の通りです。

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G1036

$ docker --version
Docker version 17.09.1-ce, build 19e2cf6


Sawtooth Enterprise Blockchain に事例が紹介されていますが、その他に ○✕ゲームがデモ用に実装されているので、それを Docker 上で動作させてみます。と言っても、発表の内容をなぞるだけですが。


まず、Hyperledger の sawtooth-core の GitHub から、以下の手順で sawtooth-core-1.0.0rc3.zip をダウンロードします。なお現時点での最新版は「v1.0.0rc3」。

f:id:akiyoko:20171201024521p:plain

f:id:akiyoko:20171201024759p:plain


docker/compose/sawtooth-default.yaml を開いて、以下のように shell をコピペして shell1, shell2 に書き換えます。

  ...

  shell1:
    image: hyperledger/sawtooth-all:1.0
    container_name: sawtooth-shell-default1
    expose:
      - 8008
      - 4004
    depends_on:
      - rest-api
    entrypoint: "bash -c \"\
        sawtooth keygen && \
        tail -f /dev/null \
        \""

  shell2:
    image: hyperledger/sawtooth-all:1.0
    container_name: sawtooth-shell-default2
    expose:
      - 8008
      - 4004
    depends_on:
      - rest-api
    entrypoint: "bash -c \"\
        sawtooth keygen && \
        tail -f /dev/null \
        \""

 
以下のコマンドを実行して、コンテナを起動します。

$ docker-compose -f ~/Downloads/sawtooth-core-1.0.0rc3/docker/compose/sawtooth-default.yaml up

しばらくすると、各種コンテナが起動します。

$ docker ps
CONTAINER ID        IMAGE                                       COMMAND                  CREATED             STATUS              PORTS                              NAMES
2efe61c116df        hyperledger/sawtooth-all:1.0                "bash -c 'sawtooth..."   16 minutes ago      Up 15 minutes       4004/tcp, 8008/tcp                 sawtooth-shell-default1
9d14523518bb        hyperledger/sawtooth-all:1.0                "bash -c 'sawtooth..."   16 minutes ago      Up 15 minutes       4004/tcp, 8008/tcp                 sawtooth-shell-default2
59f216a70497        hyperledger/sawtooth-settings-tp:1.0        "settings-tp -vv -..."   16 minutes ago      Up 15 minutes       4004/tcp                           sawtooth-settings-tp-default
0f0d651f61b3        hyperledger/sawtooth-rest-api:1.0           "sawtooth-rest-api..."   16 minutes ago      Up 16 minutes       4004/tcp, 0.0.0.0:8008->8008/tcp   sawtooth-rest-api-default
f17d965f771b        hyperledger/sawtooth-xo-tp-python:1.0       "xo-tp-python -vv ..."   16 minutes ago      Up 16 minutes       4004/tcp                           sawtooth-xo-tp-python-default
2ae2e16405f2        hyperledger/sawtooth-intkey-tp-python:1.0   "intkey-tp-python ..."   16 minutes ago      Up 15 minutes       4004/tcp                           sawtooth-intkey-tp-python-default
25803f8bec59        hyperledger/sawtooth-validator:1.0          "bash -c 'sawadm k..."   16 minutes ago      Up 16 minutes       0.0.0.0:4004->4004/tcp             sawtooth-validator-default


次に、別々のターミナル上で

《ターミナル 1》

$ docker exec -it sawtooth-shell-default1 bash

《ターミナル 2》

$ docker exec -it sawtooth-shell-default2 bash

を実行し、起動した 2つの shell クライアントのコンテナにそれぞれログインします。


xo の遊び方、コマンドなどの仕様については、以下を参照。


《ターミナル 1》

### user1 用の鍵を作成
# sawtooth keygen user1
writing file: /root/.sawtooth/keys/user1.priv
writing file: /root/.sawtooth/keys/user1.pub

### ゲームを新規作成
# xo create --url http://rest-api:8008 --username user1 game1
Response: {
  "link": "http://rest-api:8008/batch_statuses?id=5ebd578b0c6800460bcf2e53cd8275f2e8266fee9e9fd421f94f7b92d0b785fe28debe5c0a986fb44c784df7a1e35cf678d8f3fe3e3255fcc1fe0b710420cbd8"
}

### ゲームが作成されたか確認
# xo list --url http://rest-api:8008
GAME            PLAYER 1        PLAYER 2        BOARD     STATE
game1                                           --------- P1-NEXT

### user1 が一手目を打つ
# xo take --url http://rest-api:8008 --username user1 game1 1
Response: {
  "link": "http://rest-api:8008/batch_statuses?id=19189296519d8ced6d94902203004607532bb59b5dd8b75fcc5ff99022dc02fb54e26c6618dec172d27e09cb7808d3f2b14aac7cdece01960a321b532673afe7"
}

### ゲームの状況を確認
# xo show --url http://rest-api:8008 game1
GAME:     : game1
PLAYER 1  : 03a8de
PLAYER 2  :
STATE     : P2-NEXT

  X |   |
 ---|---|---
    |   |
 ---|---|---
    |   |


《ターミナル 2》

### user2 用の鍵を作成
# sawtooth keygen user2
writing file: /root/.sawtooth/keys/user2.priv
writing file: /root/.sawtooth/keys/user2.pub

### ゲームの一覧を確認
# xo list --url http://rest-api:8008
GAME            PLAYER 1        PLAYER 2        BOARD     STATE
game1           03a8de                          X-------- P2-NEXT

### user2 が 2手目を打つ
# xo take --url http://rest-api:8008 --username user2 game1 3
Response: {
  "link": "http://rest-api:8008/batch_statuses?id=1d33ab7613cb9cffc5813502b1a47b1f9ea78d291fe2ce69187bd6128034593f0889eba850cf7e92e32db0f702cbc55e61508d1e743dd3fad19c2a47cd574792"
}

### 試合のステータスを確認
# xo show --url http://rest-api:8008 game1
GAME:     : game1
PLAYER 1  : 03a8de
PLAYER 2  : 039346
STATE     : P1-NEXT

  X |   | O
 ---|---|---
    |   |
 ---|---|---
    |   |

という感じで、xo-tp-python がトランザクションを処理しています。
もちろん鍵が合わないユーザーは、間違った順番で take できないように検証がおこなわれます。

なおブロックは、チェーン内部にタイマーがあり、一定時間ごとに自動的にブロックが作られるようになっているとのこと。ちなみに、State はトランザクション外(メモリ上?)で管理されるということです。

「BPStudy#123 〜技術書籍執筆の実際、ノウハウ」に参加してきました

主催

BPStudy

会場

国際英語学校代々木教会ビル会場 大会議室6F
東京都渋谷区代々木1-29-5 (教会ビル)

Twitter

twitter.com



 

全体の感想など

最近、何か技術本を書きたいなぁ、と思い始めていました。
というのも、
techbookfest.org

というのを少し前に知ったからです。
こういうアウトプットのし方もあるのね、と。

あと、ちょうど最近、

というのもホットエントリーになっていたり。


ちなみに結城浩さんは、過去に自身のブログでこういったことも書いています。

本を出版するのは、一冊目が一番たいへんだ。 ほんとうに、ほんとうに一冊目はたいへん。 二冊目以降は(一冊目に比べれば)夢のように楽だ。 何が楽になるかというと、自分の中に生じる不安を吹き飛ばすのが楽になる。 「こんなに大変で、自分はやりとげられるだろうか」という不安に対しては、 「うん、大丈夫。こういう大変さはいつもと同じだ」 と答えられるようになる。 「こんなに一冊の本に時間をかけても大丈夫なのだろうか」という不安に対しては 「気持ちが前向きになっているから大丈夫。この時間は品質向上に必要な時間なのだ」 と自分に対して答えられるようになる。 いつも、祈りは必要だ。いつも、呼吸が必要なように。 それはそれとして、 二冊目以降、 自分の不安な気持ちをなだめるためのエネルギーを、 具体的な仕事に向けることができるのはとても楽なことだ。


一冊の本の7分目ほどで、何か大切なものがキラキラッと見えることがある。 本を書き始める前には知らなかった何か、 ささやかではあるけれど本質的な何かを見つかる瞬間だ。 それは著者にとって大きな報酬の1つだ。 物語をつかむ瞬間。 大きな喜びの瞬間。


でも、一番大きな喜びは、出版後にやってくる。 それは、読者から送られてくる「なるほど、わかりました!」というフィードバックだ。


本を書くということ


私自身はこれまで本を書いたことはありませんが、この一年ほど某会報誌に毎月10ページほど寄稿していたこともあり、書くことの辛さ、難しさは多少は理解しているつもりです。でもどうせ書くなら、多くの人に届けられるものを書きたい。そんなことを悶々と思っていたときに偶然見つけたこの勉強会。これは行くしかないでしょうと。


そして今回感じたこと。本を書く人は、人に何かを伝えるのが上手い。
というか、話の「構成」がうまいのかなあ、と感じました。きちんと伝えられるような構成をまず考えているというか、伝えたいことを中心に話を作っているというか。技術書とは言えど、本を買った人に何かを残す、という使命をきちんと意識しているように思いました。



 

まず、共著からやってみよう 〜 Pythonエンジニアファーストブックで学んだノウハウの共有

鈴木 たかのり 氏(株式会社ビープラウド)

Slide:Pythonエンジニアファーストブックの紹介


  • 6章を5人で書いた。
  • ターゲットは、これからPythonを仕事で使うエンジニア
  • Pythonエンジニア養成読本を改訂
    • Pythonのバージョンを3系に
    • Bottle → Djangoに変更
    • ライブラリ、ツールを最新に
  • スケジュール
    • 2016年12月に改訂を打診
    • 3月にキックオフの飲み会
    • 6月に Web以外脱稿
    • 7月に Web脱稿
    • 9月9日発刊
  • 打ち合わせでストーリー作成
  • LEGOのデータを使おう!
    • 実際に Scrapy で LEGO のデータをクローリングしている人がいる *1

 
Pythonエンジニアファーストブックで学んだノウハウの共有
清原 弘貴 氏(株式会社ビープラウド)

Slide:共著からやってみよう 〜Pythonエンジニアファーストブックで学んだノウハウの共有

  • 初めてなら共著をオススメ
    • 今まで他の本をやってきた人の執筆ノウハウが使える
    • 執筆の流れが理解できる
  • 執筆ノウハウ
    • Sphinx で書く
    • term-validator でビルドのたびに漢字や表記の揺れを自動でチェックしてくれる
    • TODOや指摘をプルリクでやり取り(GitLab?)
    • Dropbox で PDFファイルを直接レビュー(すごい!!オススメ!)
      • PDFにコメントを付けられる
      • Dropbox と Adobe が提携してるから実現してる??
  • Slack でやりとり
  • コードは GitHub で公開している
  • 執筆の流れ
    • 意外と時間が掛かるし、流れや見積もり感覚が開発と少し違う
  • 良かったところ
    • 知識を補完し合える(得意・不得意)
    • よく知ってる人としてのレビュー、知らない観点からのレビュー
    • 著者みんなで告知できる
      • Twitter、POP行脚、イベント発表、打ち上げ
  • 積極的にレビューするのが大事
  • 共著に参加するには?
    • 声が掛かりそうな人と仲良くなる
    • 私できますよ的な雰囲気をアピール
    • 信頼貯金を貯めよう
  • 「意見は率直に」
    • by「ピクサー流 創造するちから」



 

技術書を書くということ。商業誌を書くということ 〜 Jupyter 実践入門執筆プロジェクトを終えて

池内 孝啓 氏(株式会社 slideship)


  • 技術書を書くということ
  • 動機
    • 利己的
      • 自己や自社のブランディング
      • 経験
      • 印税
    • 利己的
      • 世に広める
      • 後世に記録を残す
  • ブランディング
    • キャリアの方向性と書籍の領域がマッチしていればブランディングになる
    • 実績として分かりやすい
  • 技術の輪を広げる
    • コミュニティに還元(Pay it forward)
  • 印税?
    • 300頁/1時間あたり1.5頁=200時間
    • 一冊 120万円とすると、割に合わない?
  • 納本制度
    • Jupyter本も納本済み
    • 知識や技術が陳腐化しても、当時の考えや歴史は覆らない
  • 商業誌を書くということ
  • 利益を出す必要がある
  • 良い本かどうかはマーケットが判断
  • Jupyter本は、2016年2月頃に技術評論社へ企画を持ち込む
    • 紆余曲折を経て2017年に企画スタート
  • テーマ選択の理由は「行ける!」と思ったから
  • ベネフィットを届ける
  • 読者は高度な専門知識に対してお金を払っている
    • 正確な情報
    • 妥当な方法
  • 読者がどれだけ利益を得たかが全て
    • 知らなかったことが知れる。分からなかったことが分かる
    • 学習のきっかけ
  • 売上の向上のために
    • ニーズに答える
    • ベネフィットを提供
    • マーケットの大きなところを狙う
  • 利益率を上げるために
    • 執筆コストを下げる
    • 執筆ノウハウを共有
  • 執筆プロジェクトは、ステークホルダーの利益をどう最大化させるかという視点をもっと持つ
  • O'Reillyのアトラス?どうなったか不明
  • テキストからコンバート?
  • GitBook?(Sphinx の代替として)
    • Markdown を束ねるツール


 

はじめての執筆でわかった技術書ができるまでの流れ

岩崎 圭 氏(株式会社 SQUEEZE)

docs.google.com


  • スケジュール
    • 2016年10月キックオフ
    • 2017年6月が本来の〆切 → 8月に完成
  • 形式は Markdown
  • GitLab の git で管理
  • やり取りは Slack
  • pyhack の常連 + ブログも書いていたので? 声をかけてもらったのかな?
  • まずは企画を通す
  • 最初のキックオフMTGでアウトラインを出す
  • ツールは、Sphinx, Re:VIEW
  • 執筆が上手くいかない問題
    • 書く時間を上手く確保できない
      • 平日仕事が終わったら必ず「コワーキングスペースに行く」を習慣化
    • 筆が進まない問題
      • 各章で最初にアウトラインを書くようにした
    • 執筆のアクティビティを Slack に流す
      • 執筆が死んでる感を出さないように
  • 1章あたりどんなに短くとも2週間は掛かった
  • 原稿消滅事件
  • レビューはDropboxコメント機能を利用
  • 修正は時間と体力との戦い
  • もう少し上手くやりたかったこと
    • 日本語力不足の解消
    • 最低限の校正の自動化(textlint x CI など)
    • 原稿の自動ビルド(テンションが違う)
    • 原稿の時点である程度レビューしたかった
    • 素のMarkdownがつらい
      • コラム、Note、Point など書籍ならではのブロックの表現
  • とんでもない量の時間と体力を費やして本当に疲れた
  • 技術的な内容を日本語に変換するのが難しい

gitlab.com の原稿消失事件は、2月のコレらしい。
結局大丈夫だったとのこと。




 

LT

 

技術書は Jupyter Notebook で書けばいいんじゃない?

driller / どりらん 氏

  • Jupyter Notebook とドキュメントビルダーだけで OK!
  • nbconvert で変換
  • Shpinx, Pelican
  • nbsphinx
  • PDF や ePub を作成するなら ⇒ Sphinx
  • HTML形式だけでよいなら ⇒ Miyadaiku
  • ただし、テキスト校正ツールが使えない、コーディング規約のチェックが使えないなどの問題も

 

技術書査読・校正の現場から

Hayao Suzuki 氏


 

一流のエンジニア/経営者になるため基礎力を磨け!

高崎健太郎

  • 一流になるためには学びが重要
  • 自習、経験、環境
  • ぶれない軸
  • 一緒に学び合える仲間
  • 学びを与えてくれるもの
    • 歴史、スポーツ
      • 同じテーマで議論できる
      • 葛藤、挫折、新たな挑戦。組織論、戦術論


 

技術書の原稿はWordで書いちゃダメゼッタイという話

生形 可奈子 氏(アシアル株式会社)

  • スラスラわかるJavaScript は単著
  • 増刷で修正する場合は、軽微な修正であっても原稿データと同期を取る
  • Amazonレビューの「違反を報告」はヤバイ

「fin-pyもくもく会 #10」に参加してきました

主催

fin-py

会場

株式会社インタートレード
東京都中央区新川一丁目17番21号 茅場町ファーストビル3階

Twitter

twitter.com



 

全体の感想など

fin-py は今回で 3回目の参加となりました。

Python は業務で7年ほど&プライベートでもちょくちょく触っているのでそこそこ使いこなせますが、これまで金融業界の経験もないし、個人的にほとんど投資をしたことがないので、Finance の部分は素人同然。発表のときに「約定」を「やくてい」と読んでしまうほどのレベルです。。


まあ、金融業界にいなくても独学で十分という話もありますが。。


あと今回は参加者が多くてビックリしました。特に初参加の方が多かったようです。Quantopian 関連の人が多かったのでしょうか、詳しくはよく分かりません。



《過去記事》
akiyoko.hatenablog.jp

akiyoko.hatenablog.jp



 

やりたかったこと

bitFlyer の BTC-FX API を使ってトリガー検知

bitFlyer Lightning FX(ビットコイン FX) では、預入証拠金に対して最大15倍の取引ができるのが特徴です。最低取引金額が 0.001 BTC になっているため、1BTC=100万円として 1,000 円(レバレッジ15倍なら預入証拠金は約67円)から取引ができることになります。


bitFlyer ビットコインを始めるなら安心・安全な取引所で
bitFlyer ビットコインを始めるなら安心・安全な取引所で


背景としては、この一年の仮想通貨のトレンドとして、

Ripple(3月上旬)
アルトコイン(〜6月中旬)
草コイン(〜7月?)
ICO(〜9月中旬)
ハードフォーク(〜11月?)
チャイナショック(9月初旬) ⇒ アルトコインが焼かれる
CME先物発表(10月下旬) ⇒ アルトコインが焦土に
取引所増加
BTC-FX ⇐ 今ココ!?


みたいな流れがあったりするので、ちょっと触ってみようかと(まだ触ったことはありません)。


 

やったこと

  • FX 戦士たちの戦略調査
  • bitFlyer Lightning(FX取引所)を眺めてみる
    • いろんな音が鳴ってた ♪
  • pybitflyer 触ってみた
  • ccxt で書いてみた
  • テクニカル指標を扱うライブラリ「TA-Lib」を使ってグラフ書いてみた

 

環境
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G1036

$ python --version
Python 3.5.2 :: Anaconda 4.2.0 (x86_64)


 

TA-Lib のインストール

テクニカル指標を扱うライブラリ。
GitHub - mrjbq7/ta-lib: Python wrapper for TA-Lib (http://ta-lib.org/).

$ brew install ta-lib
$ pip install TA-lib

TA-Lib (0.4.10)

「error: command '/usr/bin/clang' failed with exit status 1」とのエラーが出るので、まず先に「brew install ta-lib」が必要。

(参考)python - /usr/bin/clang command failing trying to pip install TA-lib on MacOS - Stack Overflow


 

pybitflyer のインストール

id:yag_ays さん作の bitFlyer REST API のラッパーライブラリ。
bitFlyer LightningのAPIをPythonから使えるパッケージ「pybitflyer」を作りました - おおかみ山

$ pip install pybitflyer

pybitflyer (0.1.7)


使ってみる。

import pybitflyer

exec(open('env.py', 'rb').read())

api = pybitflyer.API(
    api_key=BITFLYER_KEY,
    api_secret=BITFLYER_SECRET,
)
api.board(product_code='FX_BTC_JPY')

こんな感じで、板情報が取れます(それぞれ100件くらい)。

{'asks': [{'price': 942400.0, 'size': 0.00310928},
  {'price': 942497.0, 'size': 0.60458056},
  {'price': 942498.0, 'size': 0.04},
  ...],
 'bids': [{'price': 942212.0, 'size': 0.0521},
  {'price': 942152.0, 'size': 0.3},
  {'price': 942151.0, 'size': 0.22},
  ...],
 'mid_price': 942306.0}


 

ccxt で書いてみた

pybitflyer とほぼ同じことが書けます。

import ccxt
from pprint import pprint

exec(open('env.py', 'rb').read())

ex = ccxt.bitflyer({
    'apiKey': BITFLYER_KEY,
    'secret': BITFLYER_SECRET,
})

pprint(ex.fetch_ticker('FX_BTC_JPY'))
print('-' * 50)
pprint(ex.fetch_order_book('FX_BTC_JPY'))
{'ask': 1019470.0,
 'average': None,
 'baseVolume': 234473.73139995,
 'bid': 1019144.0,
 'change': None,
 'close': None,
 'datetime': '2017-11-26T12:56:20.000Z',
 'first': None,
 'high': None,
 'info': {'best_ask': 1019470.0,
          'best_ask_size': 0.0152,
          'best_bid': 1019144.0,
          'best_bid_size': 1.4489,
          'ltp': 1019144.0,
          'product_code': 'FX_BTC_JPY',
          'tick_id': 10554736,
          'timestamp': '2017-11-26T12:56:20.9',
          'total_ask_depth': 8018.9239892,
          'total_bid_depth': 11740.4605367,
          'volume': 249894.26662009,
          'volume_by_product': 234473.73139995},
 'last': 1019144.0,
 'low': None,
 'open': None,
 'percentage': None,
 'quoteVolume': 249894.26662009,
 'symbol': 'FX_BTC_JPY',
 'timestamp': 1511700980000,
 'vwap': None}
--------------------------------------------------
{'asks': [[1019470.0, 0.0152],
          [1019475.0, 0.0152],
          [1019494.0, 0.2008],
          ...,
          [1735257.0, 0.79804842]],
 'bids': [[1019144.0, 1.4489],
          [1019143.0, 2.331],
          [1019140.0, 0.01],
          ...,
          [95000.0, 2.0]],
 'datetime': '2017-11-26T12:56:22.000Z',
 'timestamp': 1511700981575}


しかしながら、pybitflyer と同じく 100件ほどしか板情報が取れないため、例えばボリンジャーバンドを計算するための ticker の情報はどうやって収集すればいいの?というのが懸念点。



 

TA-Lib を使ってグラフ書いてみた

とりあえず、さくらのクラウドサーバ上の MongoDB に格納している ticker データからグラフ作ってみました。

前回の反省を活かし、Jupyter Notebook で。

% matplotlib inline

from datetime import datetime, timedelta

import matplotlib.pyplot as plt
import pandas as pd
import talib
from pymongo import MongoClient, ASCENDING
from sshtunnel import SSHTunnelForwarder

plt.style.use('ggplot')
pd.options.display.max_rows = 20

now = datetime.now()
df = None

with SSHTunnelForwarder(
    '153.xxx.xxx.xxx',
    ssh_username='ubuntu',
    ssh_pkey='/Users/akiyoko/.ssh/sakura.pem',
    remote_bind_address=('127.0.0.1', 27017)
) as server:
    # server.start()
    print(server.local_bind_port)

    client = MongoClient('127.0.0.1', server.local_bind_port)
    db = client['bittrex']
    collection = db['tickers']

    records = list(collection.find(
        {
            'symbol': 'BTC',
            'timestamp': {'$gte': now - timedelta(minutes=60 * 24)},
        },
        {'_id': False},
    ).sort('timestamp', ASCENDING))

    df = pd.DataFrame(records)
    # Need?
    # https://stackoverflow.com/a/17328858/8426544
    #df = df.set_index(pd.DatetimeIndex(df['timestamp']))

print(df.dtypes)

df['sma'] = talib.SMA(df['last'].values, timeperiod=12)
print(df)

ax = df.plot(x='timestamp', y='last')
df.plot(ax=ax, x='timestamp', y='sma', secondary_y=True)


f:id:akiyoko:20171126220525p:plain





 

LT

pandas はデータをリサンプリングできる。例えば、1分足から5分足へ。

例えば、こんな感じ。

% matplotlib inline

import matplotlib.pyplot as plt
import pandas as pd
import talib

plt.style.use('ggplot')
pd.options.display.max_rows = 20

df = pd.read_csv('DAT_ASCII_EURUSD_M1_2015.csv', sep=';',
                 names=('Time', 'Open', 'High', 'Low', 'Close', ''),
                 index_col='Time', parse_dates=True)
df.index += pd.offsets.Hour(7)

# cf. https://stackoverflow.com/a/36223274/8426544
# cf. http://nekopuni.holy.jp/2015/01/pythonnysol%E7%82%BA%E6%9B%BF%E9%AB%98%E9%A0%BB%E5%BA%A6%E3%83%87%E3%83%BC%E3%82%BF%E3%81%8B%E3%82%89%E4%BB%BB%E6%84%8F%E3%81%AE%E3%83%AD%E3%82%A6%E3%82%BD%E3%82%AF%E8%B6%B3%E3%83%81%E3%83%A3/
df = df.resample('1H').agg({
    'Open': 'first',
    'High': 'max',
    'Low': 'min',
    'Close': 'last',
}).ffill()
df['FastMA'] = talib.SMA(df['Close'].values, timeperiod=10)
df['SlowMA'] = talib.SMA(df['Close'].values, timeperiod=30)

df.plot(y=['Close', 'FastMA', 'SlowMA'])

from pandas_highcharts.display import display_charts
df = pd.DataFrame({'Close': df['Close'], 'FastMA': df['FastMA'], 'SlowMA': df['SlowMA']})
display_charts(df, chart_type="stock", title="MA cross", figsize=(640, 480), grid=True)

(参考)PythonでFXシストレのバックテスト(1)


resample() メソッドを使用することで時系列データの頻度を変換できます。日次のデータを週次や月次などのデータに変換できます。


どりらんさん共著の Jupyter 本に載ってる!(P.128 あたり)


Jupyter 上で動かせるチャートを書くなら、pandas-highcharts が良さげ。
python-highcharts もあるよ。


 

「fin-pyもくもく会 #9」に参加してきました

主催

fin-py

会場

株式会社インタートレード
東京都中央区新川一丁目17番21号 茅場町ファーストビル3階

Twitter

twitter.com



 

全体の感想など

前回の初参加からおよそ3ヶ月、3回ぶりの参加となりました。


《過去記事》
akiyoko.hatenablog.jp



前回は、Poloniex という仮想通貨取引所の API を使ってロボアドを作ろう、ということで API を初めて触ってみたのですが、その後の成果は全く奮わず。。

今回はそれを一歩進めて、API を使って仮想通貨の売買のテストをしてみることにしました。




最近は「インベスターZ」を読んで投資のノウハウを勉強中のど素人ですが、fin-py 常連の方々に「おっ!」と思ってもらえるような爪痕を残せるようになるまで頑張ってみたいと考えています。




そして、fin-py 主催者からのつぶやき。

爪痕残せた!(違)


実行環境

  • macOS Sierra 10.12.6
  • Python 3.5.2(Anaconda 4.2.0)


 

やったこと

ccxt というライブラリのコードを読みながら、実際に触ってみました。


まず、Exchange クラスは

def load_markets(self, reload=False):
def fetch_markets(self):
def fetch_tickers(self, symbols=None, params={}):
def fetch_order_status(self, id, market=None):
def fetch_order(self, id, symbol=None, params={}):
def fetch_orders(self, symbol=None, params={}):
def fetch_open_orders(self, symbol=None, params={}):
def fetch_closed_orders(self, symbol=None, params={}):

あたりのメソッドが使えそう。

また、取引所ごとに

def fetch_ticker(self, symbol, params={}):
def fetch_trades(self, symbol, params={}):
def create_order(self, symbol, type, side, amount, price=None, params={}):
def cancel_order(self, id, symbol=None, params={}):
def withdraw(self, currency, amount, address, params={}):

が用意されている。

しかしながら create_order() は、直接使うのではなく、指値注文なら

def create_limit_buy_order(self, symbol, *args):
def create_limit_sell_order(self, symbol, *args):

create_limit_xxx_order 系のメソッドを使うっぽい。たぶん。

def create_market_buy_order(self, symbol, amount, params={}):
def create_market_sell_order(self, symbol, amount, params={}):

create_market_xxx_order 系は成行注文かな。
見たところ、対応している取引所は少なそうな雰囲気ではあるが。

# sell one ฿ for market price and receive $ right now
print(exmo.id, exmo.create_market_sell_order('BTC/USD', 1))

# limit buy BTC/EUR, you pay €2500 and receive ฿1  when the order is closed
print(exmo.id, exmo.create_limit_buy_order('BTC/EUR', 1, 2500.00))

こんな感じで使えと。
https://github.com/ccxt/ccxt#python-1


以下、実際に試してみた。


 

fetch_balance

バランスを取得する。


(使用例)

import ccxt
from pprint import pprint

ex = ccxt.bittrex({
    'apiKey': BITTREX_KEY,
    'secret': BITTREX_SECRET,
})

ret = ex.fetch_balance()
pprint(ret)


(出力例)

{'BTC': {'free': 0.33, 'total': 0.33, 'used': 0.0},
 'LTC': {'free': 0.0, 'total': 2.22, 'used': 2.22},
 'XRP': {'free': 1000.0, 'total': 1000.0, 'used': 0.0},
 ...
 'free': {...,
          'BTC': 0.33,
          'LTC': 0.0,
          'XRP': 1000.0,
          ...},
 'info': [...,
          {'Available': 0.33,
           'Balance': 0.33,
           'CryptoAddress': '1Mxxxxxxxx',
           'Currency': 'BTC',
           'Pending': 0.0},
          {'Available': 1000.0,
           'Balance': 1000.0,
           'CryptoAddress': None,
           'Currency': 'XRP',
           'Pending': 0.0},
          ...],
 'total': {...,
           'BTC': 0.33,
           'LTC': 2.22,
           'XRP': 1000.0,
           ...},
 'used': {...,
           'LTC': 2.22,
           ...}}

ルート直下は、

- info: 全通貨の情報(作成済みのアドレスやバランスなどの量)
- free: ポジションフリーになっている量を全通貨分まとめて表示
- total: 保持している総量を全通貨分まとめて表示
- used: ポジションを取っている量を全通貨分まとめて表示

各通貨の下は、

- free: ポジションフリーになっている量
- total: 総量
- used: ポジションを取っている量

という形で出力されている。



 

fetch_order_book

注文板を取得する。
Bittrex でいうところの「ORDER BOOK」の板。


(使用例)

ret = ex.fetch_order_book('LTC/BTC')
pprint(ret)


(出力例)

{'asks': [[0.00724399, 162.062],
          [0.007244, 68.0758],
          [0.00724498, 12.119],
          ...,
          [0.01287905, 0.27054]],
 'bids': [[0.00721213, 4.87597329],
          [0.0072, 112.42175327],
          [0.007194, 54.9071],
          ...,
          [1e-08, 9874677.64]],
 'datetime': '2017-10-28T06:57:05.000Z',
 'timestamp': 1509173824684}

'asks' は売り出し価格、'bids' は買いたい値段。
成立した金額に近いものから順に(すなわち 'asks' は値段の低い順、'bids' は値段の高い順に)並んでいる。

'asks' および 'bids' のそれぞれのリストは、0番目が BTC換算の価格、1番目がそれぞれの売買ボリューム(アルトコインベースで BTC建てではない)。


 

fetch_trades

他人のものを含めて過去に成立した取引を抽出する。
Bittrex で言うところの「MARKET HISTORY」の板。


(使用例)

ret = ex.fetch_trades('LTC/BTC')
pprint(ret)


(出力例)

[{'amount': 3.63704229,
  'datetime': '2017-11-05T14:21:40.000Z',
  'id': '91373876',
  'info': {'FillType': 'PARTIAL_FILL',
           'Id': 91373876,
           'OrderType': 'SELL',
           'Price': 0.00720401,
           'Quantity': 3.63704229,
           'TimeStamp': '2017-11-05T14:21:40.993',
           'Total': 0.02620128},
  'price': 0.00720401,
  'side': 'sell',
  'symbol': 'LTC/BTC',
  'timestamp': 1509891700000,
  'type': 'limit'},
  ...]


 

create_limit_buy_order

指値で買い注文を出す。


(使用例)

ret = ex.create_limit_buy_order('LTC/BTC', 2, 0.0005)
pprint(ret)

の例だと、
「0.00050000 BTC / 1 LTC」の指値で、2 LTC の注文を出している。
第三引数は、合計金額ではなく、アルトコイン1単位あたりの値段なので要注意。


なお Bittrex では、合計金額が 50K satoshi 以下のゴミ注文を出すと「DUST_TRADE_DISALLOWED_MIN_VALUE_50K_SAT」というエラーが出るようなので、これも要注意。*1


(出力例)

{'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
 'info': {'message': '',
          'result': {'uuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f'},
          'success': True}}


 

fetch_order

自分が出したオーダーを抽出する。


オーダー時の 'id' を指定します。
売買成立後のオーダーを見ることも可能。


約定前のオーダーでは、'status' が 'open' になっています。
(部分的に売れている場合はどうなるのか?については要調査。)


(使用例)

ret = ex.fetch_order('d60c914b-9ba1-4e27-b055-deb7c6549f7f', 'LTC/BTC')
pprint(ret)


(出力例)

{'amount': 2.0,
 'average': None,
 'cost': 0.001,
 'datetime': '2017-11-05T14:36:54.000Z',
 'fee': {'cost': 0.0, 'currency': 'BTC'},
 'filled': 0.0,
 'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
 'info': {'AccountId': None,
          'CancelInitiated': False,
          'Closed': None,
          'CommissionPaid': 0.0,
          'CommissionReserveRemaining': 2.5e-06,
          'CommissionReserved': 2.5e-06,
          'Condition': 'NONE',
          'ConditionTarget': None,
          'Exchange': 'BTC-LTC',
          'ImmediateOrCancel': False,
          'IsConditional': False,
          'IsOpen': True,
          'Limit': 0.0005,
          'Opened': '2017-11-05T14:36:54.987',
          'OrderUuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
          'Price': 0.0,
          'PricePerUnit': None,
          'Quantity': 2.0,
          'QuantityRemaining': 2.0,
          'ReserveRemaining': 0.001,
          'Reserved': 0.001,
          'Sentinel': '4f9809dd-a8d5-4225-a7cf-1feebfcea9f6',
          'Type': 'LIMIT_BUY'},
 'price': 0.0005,
 'remaining': 2.0,
 'side': 'buy',
 'status': 'open',
 'symbol': 'LTC/BTC',
 'timestamp': 1509892614000,
 'type': 'limit'}

売買成立後のオーダーを見ると、'status' が 'closed' になっていました。ちなみに、キャンセル済みの場合でも 'status' は 'closed' でした。


 

fetch_open_orders

自分が出している約定前のオーダーの一覧を抽出する。
「OPEN ORDERS」の板。


(使用例)

ret = ex.fetch_open_orders('LTC/BTC')
pprint(ret)


(出力例)

[{'amount': 2.0,
  'average': None,
  'cost': 0.001,
  'datetime': '2017-11-05T14:36:54.000Z',
  'fee': {'cost': 0.0, 'currency': 'BTC'},
  'filled': 0.0,
  'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
  'info': {'CancelInitiated': False,
           'Closed': None,
           'CommissionPaid': 0.0,
           'Condition': 'NONE',
           'ConditionTarget': None,
           'Exchange': 'BTC-LTC',
           'ImmediateOrCancel': False,
           'IsConditional': False,
           'Limit': 0.0005,
           'Opened': '2017-11-05T14:36:54.987',
           'OrderType': 'LIMIT_BUY',
           'OrderUuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
           'Price': 0.0,
           'PricePerUnit': None,
           'Quantity': 2.0,
           'QuantityRemaining': 2.0,
           'Uuid': None},
  'price': 0.0005,
  'remaining': 2.0,
  'side': 'buy',
  'status': 'open',
  'symbol': 'LTC/BTC',
  'timestamp': 1509892614000,
  'type': 'limit'}]

 

cancel_order

約定前のオーダーをキャンセルする。

オーダー時の戻り値から取得した 'id' の値を第一引数に使います。


(使用例)

ret = ex.cancel_order('d60c914b-9ba1-4e27-b055-deb7c6549f7f', 'LTC/BTC')
pprint(ret)


(出力例)

{'message': '', 'result': None, 'success': True}

なお、すでにキャンセル済みのオーダーに cancel_order() すると、

ccxt.base.errors.InvalidOrder: bittrex cancelOrder() error: {"success":false,"message":"ORDER_NOT_OPEN","result":null}

という例外が発生します。


 

fetch_orders

自分の過去の取引履歴を抽出する。

キャンセルを除いた、過去に売買が成立した取引だけが抽出できるはず。
新しい順に出力されます。

(使用例)

ret = ex.fetch_orders('LTC/BTC')
pprint(ret)

(出力例)

[{'amount': 1.1,
  'average': 0.00689999,
  'cost': 0.00758999,
  'datetime': '2017-11-02T11:09:40.000Z',
  'fee': {'cost': 0.00001897, 'currency': 'BTC'},
  'filled': 1.1,
  'id': 'dc7bfda3-d170-4e30-8461-771d8f690c73',
  'info': {'Closed': '2017-11-02T11:09:41.203',
           'Commission': 0.00001897,
           'Condition': 'NONE',
           'ConditionTarget': None,
           'Exchange': 'BTC-LTC',
           'ImmediateOrCancel': False,
           'IsConditional': False,
           'Limit': 0.0069,
           'OrderType': 'LIMIT_SELL',
           'OrderUuid': 'dc7bfda3-d170-4e30-8461-771d8f690c73',
           'Price': 0.00758999,
           'PricePerUnit': 0.00689999,
           'Quantity': 1.1,
           'QuantityRemaining': 0.0,
           'TimeStamp': '2017-11-02T11:09:40.91'},
  'price': 0.0069,
  'remaining': 0.0,
  'side': 'sell',
  'status': 'closed',
  'symbol': 'LTC/BTC',
  'timestamp': 1509620980000,
  'type': 'limit'},
...]