【日経先物】自動的に価格情報を収集する仕組みを作る
【2021-04-25 23:25追記】スクリプトを改良しました。また前回終値の列を追加し、それに合わせるよう記事の一部を修正しました。スクリプトを使っている方は最新のスクリプトに差し替えるようお願いします。
こんにちは、ジャド弟です。「日経先物の分析をしたいけど価格情報を毎日記録するのが面倒」と思っている人、いますよね?今回はそういう人のために、日経先物の価格情報を毎日自動的に収集するやり方をご紹介したいと思います。
仕組みの説明
今回は日経先物の日中と夜間の四本値をGoogleスプレッドシートに日々自動収集する仕組みを作りたいと思います。Googleスプレッドシートを使ったことがないという方は、申し訳ありませんがネットで検索する等して使い方を調べて下さい…。
データはJPXの「先物価格情報」のページから収集することにします。このページの情報はリアルタイムではなく20分遅れで更新されますが、日中と夜間の確定後の四本値を取得するには問題ありません。
以降では、パソコンのブラウザを使って、以下の手順で仕組みを構築していきます。
1. 価格情報を記録するためのGoogleスプレッドシートを作る
2. 価格情報を取得するためのスクリプトを追加する
3. 価格情報を自動的に取得するためのトリガを登録する
価格情報を記録するためのGoogleスプレッドシートを作る
ブラウザでGoogleドライブのサイトを開いて下さい。右上に「ドライブに移動」というボタンがありますのでクリックしてGoogleドライブに移動して下さい。
Googleドライブにログインしていない場合、次のようなログイン画面が表示されますのでGoogleアカウントでログインして下さい。
ログインしたら、左上の「+ 新規」ボタンを押してメニューを表示し、Googleスプレッドシートを新規作成して下さい。
作成したら、次のようにヘッダ行を入力しておいて下さい。(背景色は何でも良いです)
これでGoogleスプレッドシートの準備は完了です。
価格情報を取得するためのスクリプトを追加する
次は今回の仕組みのキモである、価格情報をJPXのサイトから取得してくるスクリプトを追加します。
Googleスプレッドシートの「ツール」メニューから「スクリプトエディタ」を押してスクリプトエディタを開いて下さい。
このような画面が表示されますので、元々入力されているスクリプトの雛形(function myFunction() { 〜の部分)を全て削除し、代わりに次のスクリプトをコピペして下さい。
// Ver. 4
// ・前回終値を追加するようにしました。
// ・メニューの表記を修正しました。
// Ver. 3
// ・四本値を追加する行を見つけるロジックを改善しました。
// Ver. 2
// ・トリガーを設定しても価格情報が取得されない不具合を解消しました。
// Ver. 1
// ・最初のバージョンです。
// メニューを追加する
function onOpen() {
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('拡張機能');
menu.addItem('日経先物の夜間四本値を取得する', 'addNk225NightCandle');
menu.addItem('日経先物の日中四本値を取得する', 'addNk225DaytimeCandle');
menu.addToUi();
}
// 四本値を表すクラス
class Candle {
constructor(date, session, open, high, low, close) {
this.date = date;
this.session = session;
this.open = open;
this.high = high;
this.low = low;
this.close = close;
}
getSessionLabel() {
return this.session == 'daytime' ? '日中' : '夜間';
}
}
// 夜間四本値をシートに追加する
function addNk225NightCandle() {
addCandle(true);
}
// 日中四本値をシートに追加する
function addNk225DaytimeCandle() {
addCandle(false);
}
// 指定されたセッションの四本値をシートに追加する
function addCandle(isNight) {
var candle = fetchCandle(isNight);
// アクティブなシート、または最初のシートに追加する。
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet() || ss.getSheets()[0];
var lastRow = getLastRow(sheet, 1, 6);
var numOfRows = 2; // 末尾の何行分をチェックするか
var firstRow = lastRow + 1 - numOfRows;
if (firstRow < 1) {
firstRow = 1;
}
var range = sheet.getRange(firstRow, 1, numOfRows + 1, 6);
var values = range.getValues();
var rowIdx = findRowIndex(values, candle, lastRow + 1 - firstRow);
var colIdx = 0;
values[rowIdx][colIdx++] = candle.date; // 取引日
values[rowIdx][colIdx++] = candle.getSessionLabel(); // セッション
values[rowIdx][colIdx++] = candle.open; // 始値
values[rowIdx][colIdx++] = candle.high; // 高値
values[rowIdx][colIdx++] = candle.low; // 安値
values[rowIdx][colIdx++] = candle.close; // 終値
range.setValues(values);
// 前回終値を追加する
var currentRow = firstRow + rowIdx;
sheet.getRange(currentRow, 7).setFormula('=IF(ROW(A' + currentRow + ')=2,"",F' + (currentRow - 1) + ')');
}
// 指定されたセッションの四本値をJPXのサイトから取得する
function fetchCandle(isNight) {
var session = isNight ? 'night' : 'daytime';
var response = UrlFetchApp.fetch('https://port.jpx.co.jp/jpx/template/quote.cgi?F=tmp/future_' + session);
var html = response.getContentText();
var tableBody = html.match(/<table>([\s\S]*?)<\/table>/)[1];
var trs = tableBody.match(/<tr>[\s\S]*?<\/tr>/g);
var trBody = trs[2].match(/<tr>([\s\S]*?)<\/tr>/)[1];
var tds = trBody.match(/<td[^>]*>[\s\S]*?<\/td>/g);
var date = extractDate(tds[2]);
var open = extractPrice(tds[3]);
var high = extractPrice(tds[4]);
var low = extractPrice(tds[5]);
var close = extractPrice(tds[6]);
return new Candle(date, session, open, high, low, close);
}
// HTMLタグから日付を抽出する
function extractDate(text) {
var matched = text.match(/<td[^>]*>\s*(\d+)\/(\d+)/);
var month = Number(matched[1]) - 1;
var day = Number(matched[2]);
var today = new Date();
var year = today.getFullYear();
if (today.getMonth() < month) {
// 年をまたいでいたら年を調整する。
year--;
}
return new Date(year, month, day);
}
// HTMLタグから価格を抽出する
function extractPrice(text) {
var extracted = text.match(/<td[^>]*>\s*([\d,]+|-)/)[1].replace(',', '');
return extracted == '-' ? null : Number(extracted);
}
// シートの最終行(指定されたカラム範囲が空ではない行のうち一番下にある行)の番号を返す。
function getLastRow(sheet, column, numOfColumns) {
var values = sheet.getRange(1, column, sheet.getLastRow(), numOfColumns).getValues();
for (var y = values.length - 1; y >= 0; y--) {
for (var x = 0; x < values[y].length; x++) {
if (values[y][x] != '') {
return y + 1;
}
}
}
return 0;
}
// valuesからcandleを書き出すべき行を見つけてそのインデックスを返す。見つからなかった場合はdefaultIndexを返す
function findRowIndex(values, candle, defaultIndex) {
for (var i = 0; i < values.length; i++) {
if (values[i][0].toString() == candle.date.toString() && values[i][1] == candle.getSessionLabel()) {
return i;
}
}
return defaultIndex;
}
コピペしたら、「プロジェクトを保存」のアイコンを押して保存して下さい。
保存したら、Googleスプレッドシートに戻ってページを再読込みして下さい。すると、メニューの「ヘルプ」の右側に「拡張機能」というメニューが追加されるはずです。
「拡張機能」を押すと以下のようなメニューが表示されます。
どちらかを選んでみて下さい。最初の1回目は次のような承認の要求画面が表示されますので、画面の指示に従ってスクリプト実行の許可を与えて下さい。
途中で以下のような画面が表示されたら、左下の「詳細」を押して、
「無題のプロジェクト(安全ではないページ)に移動」を押して下さい。これで先に進むことができます。
許可を与え終わったら、改めて「拡張機能」メニューからどちらかを選んでみて下さい。JPXのサイトから価格情報が取り出され、スプレッドシートに行が追加されます。
なお、既に同じ日付・セッションの行が存在する場合はその行に上書きされます。(行末に存在する場合のみ)
価格情報を自動的に取得するためのトリガーを登録する
さて、ここまででも「手入力する必要がなくなって楽になる!」という人もいそうですが、毎日メニューからポチポチするのも面倒ですよね?
そこで、毎日決まった時間に自動的に値を取ってくるようにしてみましょう。
再び「ツール」の「スクリプトエディタ」からスクリプトエディタを開き、左側の時計のアイコンを押して下さい。
トリガーの編集画面が表示されますので、右下の「+ トリガーを追加」を押して下さい。
トリガーの追加画面が表示されますので、以下のように設定して「保存」を押して下さい。
これで夜間のデータが毎日朝の6時〜7時の間に自動的に収集されるようになります。次は日中データのための設定です。
変わったのは「実行する関数を選択」と「時刻を選択」の箇所です。これで日中のデータが毎日夕方の4時〜5時の間に自動的に収集されるようになります。
おわりに
日経先物の価格情報を毎日自動的に収集するやり方をご紹介しました。データを収集するとチャートの表示やデータの分析など、いろいろなことができるようになります。また、この記事に載せたスクリプトはご自由に改変していただいて構いませんので、この仕組みをそのまま使うだけでなく、ぜひいろいろ拡張してみて下さい。
最後まで読んでいただきありがとうございました!
追記:日経先物以外の価格情報を収集したい方へ
本記事では日経先物を対象としましたが、日経先物以外のいろいろな銘柄の価格情報を収集できるスクリプトを作成しました(有料)。興味のある方はぜひ購入を検討してみて下さい。
この記事が気に入ったらサポートをしてみませんか?