Juliaで時系列解析をしていきます。
仮想通貨(BTC)を対象にして操作していきます。
その準備としてまずは、、、
Juliaにおける時系列の基礎に慣れておきます。
よくTimeSeries.jlが出てくるので、
今回はそれの操作に慣れていきましょう。
併せてDates.jlにも慣れておきましょう!
ですので、Dates.jlもしくは、
TimeSeries.jlに慣れていない方を対象にしています。
それではレッツゴー!
仮想通貨(BTC)の価格データを取得する方法
まずは準備として、
ビットコインの価格推移データを取得します。
取得する方法はいくつかあります。
①Kaggle
Kaggleでビットコインの価格推移を
csv形式でダウンロードできます。
ダウンロードボタンをポチるだけなので簡単です。
どうやら最新価格には対応していないっぽい。
https://www.kaggle.com/mczielinski/bitcoin-historical-data
②yfinance
pythonのyfinanceを使用する方法です。
yahoo! financeの株や仮想通貨のデータを
APIを通して取得することが出来ます。
以下にコードの例を載せておきます。
juliaからpython側のAPIを使用するには、
PyCall.jlが必要になります。
1 2 3 4 5 6 |
using PyCall yf = pyimport("yfinance") ticker = yf.Ticker("GBTC") gbtc = ticker.history(period = "2y") |
私は上のコードで半年くらい前は動いていたのですが、
気づいたらエラーが出るようになりました。
エラーを調べたのですが、解決できなかったので、
とりあえず一旦保留です。
一応、もし実行途中でエラーがでるようでしたら、
pythonでyfinanceのアップデートすると直ると、
どこぞに書いてあったのですが、私は直りませんでした。
pip install yfinance --upgrade --no-cache-dir
それもそのはず、私はそもそも
pythonではyfinanceは正常に動作していました。
なのでjulia側の問題だったのですが、
とりあえず未解決のままです。
というわけで他の方法にします。
③query2.finance.yahoo.comにデータを要求する
私がやりたいことに一番しっくり来た方法です。
juliaでhttps://query2.finance.yahoo.comに、
欲しいデータを要求します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#using HTTP, JSON, TimeSeries, DataFrames function get_symbols(symbol::String, from::String, to::String) from = string(Integer(datetime2unix(DateTime(from * "T12:00:00")))) to = string(Integer(datetime2unix(DateTime(to * "T12:00:00")))) parse(Int, from) > parse(Int, to) ? error("in get_symbols: to must be older than from") : nothing url = "https://query2.finance.yahoo.com/v7/finance/chart/$symbol?&interval=1d&period1=$from&period2=$to" response = HTTP.get(url, cookies = true) body = JSON.parse(String(response.body))["chart"]["result"][1] values = body["indicators"]["quote"][1] x = DataFrame( Open = values["open"], High = values["high"], Low = values["low"], Close = values["close"], Volume = values["volume"], Adjusted = body["indicators"]["adjclose"][1]["adjclose"], Time = Dates.Date.(unix2datetime.(body["timestamp"])) ) delete!(x, isnothing.(x).Close) x = TimeArray(x, timestamp = :Time) return(x) end |
参考:https://github.com/JuliaTagBot/YahooFinance.jl
参照先のほぼコピペですが、2か所変更しています。
①URLのqueryを1から2へ(2の方が新しい?)
②deleterow!をdelete!へ変更
deleterow!はDataFrames.jjlで定義されていますが、
アップデートによってdelete!へ名称変更したためです。
関数の引数で銘柄と期間を指定します。
現状は1日単位のデータを取得しますが、
urlのところで "interval=1h" と変更すれば、
1時間単位にすることも可能です。
その場合は期間が730日以内である必要があります。
それでは、Date.jlとTimeSeries.jlに慣れていきましょう!
ビットコインのデータは、Date.jlの説明では使用しませんが、
TimeSeries.jlの説明では使用します。
Dates.jlの基本操作
Dates.jlには3つの型があります。
Date型、Time型、DateTime型です。
日付や時刻を取得する方法
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
using Dates dt = now() #2021-08-11T20:55:06.202 d = today() #2021-08-11 d = Date(now()) t = Time(now()) #20:58:36.509 typeof(d) #Date typeof(t) #Time typeof(dt) #DateTime |
now()と叩けば、DateTime型として、
今現在の日時が取得できます。
日付だけ欲しければ today()と叩きます。
もしくは Date(now()) のように、
now()で得られら日時をDate()でラップすれば、
日付だけを取得できます。
時刻だけ欲しければ、
now()をTime()で包めば取得できます。
ちなみにtoday()があるなら、
yesterday()やtomorrow()もあるのかな?
と、思いましたがありませんでした(笑)
日付や時刻を自由に生成する方法
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
d = Date(2023) #2023-01-01 d = Date(2023, 7, 25) #2023-07-25 d = Date("2023-07-25") #2023-07-25 typeof(d) #Date t = Time(15, 30, 20) #15:30:20 t = Time(15, 30, 20, 800) #15:30:20.8 t = Time("15:30:20") #15:30:20 t = Time("15:30:20.800") #15:30:20.8 typeof(t) #Time dt = DateTime(2023, 7, 25, 10, 55) #2023-07-25T10:55:00 dt = DateTime(2023, 7, 25, 10, 55, 30, 20) #2023-07-25T10:55:30.020 dt = DateTime("2023-07-25T10:55:30") #2023-07-25T10:55:30 typeof(dt) #DateTime |
Date()の引数に数字を入れてあげれば日付を作成できます。
Date()は3つまで数字を指定でき、
年、月、日の順番になります。
存在しない月や日を入れるとエラーになります。
もしくはString型の "yyyy-mm-dd" を
Date型に直接変換することも出来ます。
Time()についても同じですが、
時刻は、時、分、秒、ミリ秒まで指定できます。
String型の "HH:MM:SS.sss" を
直接 Time型に変換することも可能です。
DateTime()はDateとTimeの合成なので、
同様に考えることが出来ます。
日時をパースする方法
例
1 2 3 4 5 6 7 8 9 10 11 |
str = "25/12/2023" d = Date(str, "dd/mm/yyyy") #2023-12-25 str = "2023-12-25" d = Date(str, "yyyy-mm-dd") #2023-12-25 str = "25/12/2023 19:00" dt = DateTime(str, "dd/mm/yyyy HH:MM") #2023-12-25T19:00:00 |
例えば日付をパースする場合は、
y, m, dでフォーマットを指定します。
手動で日時を作成する場合と違って、
パース対象が年、月、日の順番である必要はありません。
ただ、与えられてた文字列に対して、
フォーマットを示してあげるだけです。
TimeやDateTimeに関しても同様に言えます。
なお、時間をパースするときは、
H:時、M:分、S:秒、s:ミリ秒になります。
日時の計算をする方法
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Date(2023) #2023-01-01 Year(2000) #2000 years Month(3) #3 months Day(15) #15 days Date(2023) + Year(2000) #4023-01-01 Date(2023) + Month(3) #2023-04-01 Date(2023) - Month(3) #2022-10-01 Time(15) #15:00:00 Hour(5) #5 hours Minute(30) #30 minutes Second(50) #50 seconds Time(15) + Hour(5) #20:00:00 Time(15) + Minute(30) #15:30:00 now() + Day(2) #2021-08-23T08:10:38.007 |
Date型、Time型、DateTime型それぞれ
Year(), Month(), Day(), Hour()などを使うことで、
日時を自由に加算、減算することが出来ます。
例えば、now()でDateTime型の日時が得られるので、
それに now() + Day(2) のように加算すると
2日後の日時が取得出来ます。
unix時間へ変換する方法
例
1 2 3 4 5 6 7 8 9 10 11 |
ut = datetime2unix(now()) #1.629530289256e9 typeof(ut) #Float64 str = "2023-07-25T10:55" ut = datetime2unix(DateTime(str)) #1.6902825e9 Integer(ut) #1690282500 |
DateTime型はunix timeに変換することが出来ます。
now()でDateTime型を取得出来るので、
それをdatetime2unix()へ変換出来ます。
仮想通貨の価格データ取得③の from (to) では、
引数でString型で例えば "2021-02-19" を受け取って、
時間をくっつけるために * で文字列の連結をしています。
そしてその結果をDateTime型に変換しています。
TimeSeries.jlの基本操作
まずビットコインのデータを取得します。
前述で定義したget_symbols関数を使います。
取得範囲は3年分で、BTC/USDのデータです。
それでは単純移動平均線を引いてみましょう!
dataは、get_symbols()の戻り値(TimeArray型)です
その中にAdjustedがあります。
1 2 3 4 5 6 |
#using TimeSeries, Statistics #simple moving average sma25 = moving(mean, data.Adjusted, 25) sma100 = moving(mean, data.Adjusted, 100) |
meanを使うにはStatistics.jlが必要です。
単純移動平均をプロットしてみましょう!
1 2 3 4 5 6 |
#using Plots plot(data.Adjusted, label="origin", legend=:topleft) plot!(sma25, label="sma25") plot!(sma100, label="sma100") |
プロットするとこんな感じになります。

また以下で累計を導出することも出来ます。
1 2 3 4 5 |
#cumulative sum basecall(data.Volume, cumsum) #plot(basecall(data.Volume, cumsum), label="cumulative sum of Volume") |
プロットするとこんな感じです。

今までのコードを単につなげるだけで実行できますが、
一応、ひとまとめにしたコードを載せておきますね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
using HTTP, JSON, TimeSeries, DataFrames, Plots, Statistics function get_symbols(symbol::String, from::String, to::String) from = string(Integer(datetime2unix(DateTime(from * "T12:00:00")))) to = string(Integer(datetime2unix(DateTime(to * "T12:00:00")))) parse(Int, from) > parse(Int, to) ? error("in get_symbols: to must be older than from") : nothing url = "https://query2.finance.yahoo.com/v7/finance/chart/$symbol?&interval=1d&period1=$from&period2=$to" # &interval=可能な入力: 1m, 5m, 15m, 30m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo response = HTTP.get(url, cookies = true) body = JSON.parse(String(response.body))["chart"]["result"][1] values = body["indicators"]["quote"][1] x = DataFrame( Open = values["open"], High = values["high"], Low = values["low"], Close = values["close"], Volume = values["volume"], Adjusted = body["indicators"]["adjclose"][1]["adjclose"], Time = Dates.Date.(unix2datetime.(body["timestamp"])) ) #deleterows!(x, isnothing.(x).Close) #deleterowsからdeleteへ名称変更 delete!(x, isnothing.(x).Close) x = TimeArray(x, timestamp = :Time) return(x) end data = get_symbols("BTC-USD", "2018-08-20", "2021-08-20") plot(data.Open, label="BTC") #plot(Float64.(data.Adjusted)) #----------------------------------------------------- #simple moving average sma25 = moving(mean, data.Adjusted, 25) sma100 = moving(mean, data.Adjusted, 100) plot(data.Adjusted, label="origin", legend=:topleft) plot!(sma25, label="sma25") plot!(sma100, label="sma100") #cumulative sum cs = basecall(data.Volume, cumsum) plot(cs, label="cumulative sum of Volume") |
というわけで今回はここまでで、
次回は時系列解析に踏み込んでいこうかな。
最後まで読んでいただきありがとうございました。