なんて大それたタイトルにしましたが、この記事の目的はTwitterからツイートを取得して市場参加者のセンチメントを測定して値動きと比較してみようというものです。
後半には初心者向けのCOTOHA APIのチュートリアルも記載しています。
相場とセンチメント
相場と参加者
ここ最近、コロナウイルスや原油相場暴落を受けて株価が大暴落だ〜なんてニュースをよく耳にしますよね。
ある記事では「2008年のリーマンショック級だ」なんて話も聞いたりします。
また、少し前にはビットコインを代表する仮想通貨も流行りましたね。
これらの相場の専門用語で「狼狽売り」という言葉があります。
狼狽売りとは、何らかの材料(ニュース)や相場環境により、株価が急激に下落した際に心理的に混乱を生じてパニック状態に陥り、持ち株を慌てて処分(売却)してしまうことを言います。
株式投資は、多分に人間の心理に影響されることから、後から冷静に判断すれば何ら株式価値に影響を及ぼさないことであっても、市場の雰囲気にのまれてしまい、このまま保有すれば膨大な損失が生じるのではないかとパニックに陥り、一刻も早く処分(売却)して損失を最小限に食い止めようとする意識が働くことにより生じる現象といえます。
引用:トレダビ
つまり、株式や仮想通貨の価格は人間の感情で動いている部分が大きいというのです。
そこで今回はTwitterのツイートから実際に相場参加者の感情を分析して、値動きと比較してみたいと思います。
そしてあわよくばツール化したいなあなんて。
COTOHA API
センチメントの測定に使用するのがCOTOHA APIです。
COTOHA APIはNTTコミュニケーションズが40年の研究を活かして作り上げた自然言語処理APIです。
COTOHA APIには、以下の機能(一部抜粋)があります。
・固有表現抽出:人名、地名などの固有名詞を自動で抽出する
・照応解析:これ、あれ、彼のような指示語が何を指しているのか特定する
・キーワード抽出:文章からキーワードを抽出する
・類似度判定:2つの文章の類似度を判定する
・ユーザー属性推定(β):文章からその人の年代、性別、趣味などの属性を推定する
・感情分析:文章からその人の感情がポジティブかネガティブか判定する
・要約(β):渡した文章を指定した行数で要約する
そしてこのCOTOHA APIは1日1000回までなら無料で使えちゃうのです。
これらの機能の中から今回は感情分析を使ってツイートからセンチメントを分析したいと思います。
1週間分の株価とセンチメント
実際に3/4から3/13までの8日間でTwitterから測定したセンチメントとその前日の価格差(前日比)を比較してみました。
センチメントは感情がPositiveなら+1、Negativeなら-1として、1日あたり200件のツイートの合計値としました。
測定対象はダウ平均株価です。
それではTwitterセンチメントスコアとダウの前日比を比較したグラフがこちらです。
結構相関してそうに見える...!!!
これは割とちゃんとセンチメントの指標となりうるのでは?
相場のセンチメント分析ツールとしてVIXや板情報を使うだけでなく、実際の感情を分析するというのも可能かもしれません。
しかし、まだ8日間という短い期間でのサンプルになるので、もっと長い期間で測定したら別の結果になるかもしれませんし、ノイズも取り除いてないのでそれによっても変わるかもしれません。
水曜日には「水ダウ」(水曜日のダウンタウン)というワードで拾ったツイートもありました。。
クロちゃんが出てる回だったらネガティブ感情に引っ張られそうです。
ただ少なくとも現時点ではかなり相関してそうな気がします。
実装
今回使ったコードはこちらです。
筆者が1月から勉強を始めたてのプログラミングど素人で、まだRubyしか書けなかったので今回はRubyで実装しました。
ツッコミポイントがたくさんあると思いますので、コメントの方でご指摘いただけたら嬉しいです。
実装折りたたみ
require 'csv'
require 'faraday'
require 'json'
require 'twitter'
# 変数
base_url = 'https://api.ce-cotoha.com'
@target_date_since = '2020-03-12'
@target_date_until = '2020-03-13'
keyword = 'ダウ'
total_score = 0
start_time = Time.new
# COTOHA env
@client_id = 'CLIENT_ID'
@client_secret = 'CLIENT_SECRET'
# Twitter env
@client = Twitter::REST::Client.new do |config|
config.consumer_key = 'CONSUMER_KEY'
config.consumer_secret = 'CONSUMER_SECRET'
config.access_token = 'ACCESS_TOKEN'
config.access_token_secret = 'ACCESS_TOKEN_SECRET'
end
# Faraday初期化
@connection = Faraday::Connection.new(url: base_url) do |builder|
builder.use Faraday::Response::Logger
builder.adapter Faraday::Adapter::NetHttp
end
# COTOHA APIのアクセストークン取得
def get_access_token
params = {
'grantType': 'client_credentials',
'clientId': "#{@client_id}",
'clientSecret': "#{@client_secret}"
}
response = @connection.post do |request|
request.url '/v1/oauth/accesstokens'
request.headers["Content-Type"] = 'application/json'
request.headers["charset"] = 'UTF-8'
request.body = JSON.generate(params)
end
response.body
end
# COTOHA APIにアクセスする際の共通処理
def base_api(url, params)
response = @connection.post do |request|
request.url url
request.headers['Content-Type'] = 'application/json'
request.headers['charset'] = 'UTF-8'
request.headers['Authorization'] = "Bearer #{@cotoha_access_token}"
request.body = JSON.generate(params)
end
response.body
end
# 感情分析
def emotional_analize(sentence)
params = { "sentence": "#{sentence}" }
base_api('/api/dev/nlp/v1/sentiment', params)
end
# キーワードでツイート検索取得
def get_tweet(query)
tweets = @client.search(query, result: 'recent', exclude: 'retweets', since: @target_date_since, until: @target_date_until).take(200)
end
### メインの処理
# トークン取得
@cotoha_access_token = JSON.parse(get_access_token)['access_token']
# ツイートを取得
tweets = get_tweet(keyword)
tweets.each_with_index do |tweet, i|
# ツイートを感情分析
request = JSON.parse(emotional_analize(tweet.full_text))['result']
# 感情評価別に読み替え
if request['sentiment'] == 'Positive'
total_score += 1
elsif request['sentiment'] == 'Negative'
total_score -= 1
end
# 取得ツイートと判定結果をcsv書き出し
CSV.open('sentiment_detail.csv', 'a') do |c|
c << [@target_date_until, keyword, request['sentiment'], tweet.user.screen_name, tweet.full_text.gsub(/[\r\n]/," "), start_time]
end
end
# 結果をcsvに書き出し
CSV.open('sentiment_total.csv', 'a') do |c|
c << [@target_date_until, keyword, total_score, start_time]
end
COTOHA APIを使ってみる
ここからは、今回の実装から一部抜粋してCOTOHA APIを使ってみようというコーナーです。
この先もRubyで話を進めていきます。
またKENTAさん(@poly_soft)等のインフルエンサーの方が未経験からWeb系企業への転職にRubyをおすすめしているおかげか、Twitter上でRubyを勉強している未経験の方をたくさん見かけます。
そういったRuby勉強し始めた方や、自然言語処理に興味出てきたけどPython書けませんって方に特に参考にしてもらえればと思います。
Pythonじゃなくたって興味さえあればデータ分析してみたっていいじゃない!自然言語処理やってみたっていいじゃない!おもしろそうなんだもの!!!!
COTOHA APIの登録
まずはCOTOHA APIに登録していきます。
COTOHA APIのページにアクセスし、「今すぐ無料登録」を押します。
※右上の無料登録が金色になった状態(最上部では白色)で無料登録を押しても同じページにリダイレクトされてしまうので注意してください。
メールが届くので、記載されているURLにアクセスすると、情報入力画面に遷移しますので、それぞれ入力していってください。
特に記入で困る項目はないと思います。
サインアップを押して、確認を終えてから画面遷移するまで少し時間が空きますが、待っていれば自動で遷移します。
焦らず待ちましょう。
サインアップが完了すると、再びメールが届きます。
メールに記載されているURLにアクセスすると、ログイン画面に遷移します。
そこでログイン情報を入力してログインを押します。
ログインすると、アカウント画面が表示されます。
これで晴れて、COTOHA APIを使えるようになりました!
実装
それでは登録したCOTOHA APIを実際に使ってみましょう!
今回はあくまでCOTOHA APIを使ってみることに主眼を置いているので、Twitterからツイートを取得する処理は省いて、文字列ベタ打ちで値を渡して感情分析を行うことをゴールにします。
これからやることステップに分けると、
- COTOHA APIのアクセストークンを取得する
- 取得した結果を変数へ代入する
- 感情分析APIを叩く
- 返ってきた分析結果を出力する
になります。
最終的なコードがこちらです。
require 'faraday'
require 'json'
# 変数
base_url = 'https://api.ce-cotoha.com'
sentence = '岡崎最高!'
# COTOHA env
@client_id = 'あなたのClient_ID'
@client_secret = 'あなたのClient_secret'
# Faraday初期化
@connection = Faraday::Connection.new(url: base_url) do |builder|
builder.use Faraday::Response::Logger
builder.adapter Faraday::Adapter::NetHttp
end
# 1.COTOHA APIのアクセストークン取得
def get_access_token
params = {
'grantType': 'client_credentials',
'clientId': "#{@client_id}",
'clientSecret': "#{@client_secret}"
}
response = @connection.post do |request|
request.url '/v1/oauth/accesstokens'
request.headers["Content-Type"] = 'application/json'
request.headers["charset"] = 'UTF-8'
request.body = JSON.generate(params)
end
response.body
end
# 3.感情分析APIを叩く
def emotional_analize(sentence)
params = { "sentence": "#{sentence}" }
response = @connection.post do |request|
request.url '/api/dev/nlp/v1/sentiment'
request.headers['Content-Type'] = 'application/json'
request.headers['charset'] = 'UTF-8'
request.headers['Authorization'] = "Bearer #{@cotoha_access_token}"
request.body = JSON.generate(params)
end
response.body
end
### メインの処理
# 2.取得したアクセストークンを変数に代入
@cotoha_access_token = JSON.parse(get_access_token)['access_token']
# 4.返ってきた分析結果を出力する
puts JSON.parse(emotional_analize(sentence))['result']
1. COTOHA APIのアクセストークンを取得する
まずは必要なライブラリを読み込みます。
require 'faraday'
require 'json'
もしfaradayがインストールされていない場合はインストールしておいてください。
$gem install faraday
インストールはたったこれだけです。
FaradayというのはHTTP等の通信を簡単にできまっせなライブラリです。
COTOHA APIを使うにはアクセストークンというものを取得する必要があります。
このアクセストークンはAPIを叩くことで取得できます。
叩くAPIのURLはログインした直後の画面に記載してあります。
また、アクセスするときに必要なClient_IDとClient_secretも同じ画面に記載してあります。
それでは、実装です。
# 変数
base_url = 'https://api.ce-cotoha.com'
sentence = '岡崎最高!'
# COTOHA env
@client_id = 'あなたのClient_ID'
@client_secret = 'あなたのClient_secret'
# Faraday初期化
@connection = Faraday::Connection.new(url: base_url) do |builder|
builder.use Faraday::Response::Logger
builder.adapter Faraday::Adapter::NetHttp
end
# 1.COTOHA APIのアクセストークン取得
def get_access_token
params = {
'grantType': 'client_credentials',
'clientId': "#{@client_id}",
'clientSecret': "#{@client_secret}"
}
response = @connection.post do |request|
request.url '/v1/oauth/accesstokens'
request.headers["Content-Type"] = 'application/json'
request.headers["charset"] = 'UTF-8'
request.body = JSON.generate(params)
end
response.body
end
変数のbase_urlにはCOTOHA APIのアカウントホームに記載してあるBASE_URLを削って代入しています。
これは、その後にこのbase_urlを使って初期化するfaradayをアクセストークン取得と感情分析の両方で使うためです。
COTOHA envのところではご自身のClient_IDとClient_secretを入力してください。
Faraday初期化ではさっきのbase_urlを渡します。
また、ブロックの中ではHTTP通信のログを標準出力する設定を行っています。
最後のget_access_tokenでAPIをたたいてアクセストークンを取得するメソッドを定義しています。
パラメータはparams内に記載して渡しています。
response = @connection.post~~でAPIを叩いて、その結果をresponseに代入しています。
これでAPIを叩いて、アクセストークンを取得する実装は完了です!
そして正直ここができてしまえば残りの工程はそれほど難しくないので、安心してください。
2. 取得したアクセストークンを変数へ代入する
続いて先ほど定義したget_access_tokenで取得した結果の中からアクセストークンだけを取り出し、変数に代入します。
### メインの処理
# 2.取得したアクセストークンを変数に代入
@cotoha_access_token = JSON.parse(get_access_token)['access_token']
APIを叩いて返ってくるデータはJSONという形式になっています。
そこでJSONという形をハッシュに変換してくれるJSON.parseの出番です。
このメソッドでハッシュ化してしまえばこっちのもんです。
アクセストークンはaccess_tokenというキーの値として入っているので、それを変数に代入して感情分析APIで使えるようにしておきましょう。
3. 感情分析APIを叩く
さあ、感情分析のAPIを叩いてみましょう!
ここでは、emotional_analizeメソッドを定義します。
# 3.感情分析APIを叩く
def emotional_analize(sentence)
params = { "sentence": "#{sentence}" }
response = @connection.post do |request|
request.url '/api/dev/nlp/v1/sentiment'
request.headers['Content-Type'] = 'application/json'
request.headers['charset'] = 'UTF-8'
request.headers['Authorization'] = "Bearer #{@cotoha_access_token}"
request.body = JSON.generate(params)
end
response.body
end
上の実装を見てもらえば分かる通り、1番のコードとかなり似てます。
1番を乗り越えた皆さんなら恐るるに足りません。
今回はparamsにsentenceというキーで感情を分析したい文章を渡します。
ダウのセンチメント測定時には取得したツイートを渡していました。
値には引数で受け取る文章を設定しておきましょう。
ブロック内のurlはアクセストークンを取得するときとは異なります。
このURLはCOTOHA APIのAPI一覧ページから飛べるリファレンスに記載してあります。
ここでbase_urlの代入時に削った分のパス(/api/dev)を追加して値を渡しましょう。
最後にHTTPヘッダーのAuthorizationに1と2で取得したアクセストークンを指定しましょう。
これで感情分析をするためのメソッド定義は終了です。
完成目前です!がんばりましょう!
4. 返ってきた分析結果を出力する
最後の工程です。
3で定義したメソッドを使って取得した感情分析の結果を画面に出力します。
最後の実装です。
# 4.返ってきた分析結果を出力する
puts JSON.parse(emotional_analize(sentence))['result']
こちらも見ていただければ分かる通り、2番とほぼ同じです。
ただしemotional_analizeを呼び出す際には分析するための文章を忘れずに渡しましょう。
ちなみに渡すための文章を代入した変数は1番でしれっと定義しています。笑
これで実装は全て完了です。
あとは実際に実装したコードを実行してみて下記のような結果が表示されていれば成功です!
{"sentiment"=>"Positive", "score"=>0.591956842833892, "emotional_phrase"=>[{"form"=>"最高", "emotion"=>"P"}]}
おめでとうございます!そしてお疲れ様でした!
他にもCOTOHA APIにはいろいろなAPIがあるので遊んでみてください。
今回のコードを少しいじるだけで他のAPIも使えるはずです。
終わりに
今回はCOTOHA APIを使って、Twitterから他の市場参加者のセンチメントを測定してみました。
また、Ruby初心者でもCOTOHA APIを試してみることができるように感情分析の実装を一緒に進めました。
データ分析の分野なので、COTOHA APIの記事を見ると、やはりPythonの記事ばかりでした。。
なので、この記事がRubyを勉強し始めた人で、「APIを触ってみたい」、COTOHA APIのキャンペーンを見て「自分もやってみたい」と思った人の助けになればと思います。
もし実際に参考にしてやってみたよって方がいましたら、なんならやってみようかなレベルでも大丈夫なのでコメントに書いてもらえると私がすごい喜びます笑(初めてこんなボリューミーな記事を書いたのでリアクション欲しい←)
あと最初にも書いたのですが、まだ勉強し初めて2ヶ月くらいしか経っておらず、私の実装自体も改善点だらけだと思いますので、そちらもコメントでご指摘いただけたらと思います。