1. はじめに
個人投資家向けのAPIデータ配信サービス「J-Quants」を使用すると、東証上場銘柄の様々な金融データが取得できます。
J-Quants運営チーム様の記事
https://qiita.com/j_quants/items/724c7dda5262a1ad835a
使いこなせれば本格的なデータ分析が可能となるはずです。
この素晴らしいデータに報いるためにも、金融ドメイン知識をモリモリつけたいものですね。
さて、J-Quantsでは無料登録でも財務データをAPI取得できます(スゴい!)。
取得できる年数に制限がありますが、スクリーニングや銘柄管理など、十分に活用できるシーンはありそうです。
そこで、まずは銘柄コードから銘柄や財務のデータを取得して、スプレッドシートに出力するGASコードを作成しました。
2. データを取得してスプレッドシートに出力
2.1. リフレッシュトークンとIDトークンの取得
以下のコードでIDトークンが取得できるか確認します。「成功」が出力できればOK。
function getTokens() {
var url1 = "https://api.jquants.com/v1/token/auth_user";
var data = {
"mailaddress": "*******@*********",
"password": "***********"
};
var options1 = {
"method" : "post",
"payload" : JSON.stringify(data),
"contentType" : "application/json",
"muteHttpExceptions" : true
};
var response1 = UrlFetchApp.fetch(url1, options1);
if (response1.getResponseCode() === 200) {
var jsonRes1 = JSON.parse(response1.getContentText());
var REFRESH_TOKEN = jsonRes1["refreshToken"];
var url2 = "https://api.jquants.com/v1/token/auth_refresh?refreshtoken=" + REFRESH_TOKEN;
var options2 = {
"method" : "post",
"muteHttpExceptions" : true
};
var response2 = UrlFetchApp.fetch(url2, options2);
if (response2.getResponseCode() === 200) {
Logger.log("成功"); // Success
} else {
Logger.log("失敗"); // Failure
}
} else {
Logger.log("失敗"); // Failure
}
}
2.2. J-Quants APIで取得できるデータ
無料プランでは以下の機能が使用可能です。
・上場企業の情報を取得する事ができます
https://jpx.gitbook.io/j-quants-ja/api-reference/listed_info
・株価情報を取得することができます
https://jpx.gitbook.io/j-quants-ja/api-reference/daily_quotes
・四半期の財務情報が取得できます
https://jpx.gitbook.io/j-quants-ja/api-reference/statements
・翌日発表予定の決算情報が取得できます
https://jpx.gitbook.io/j-quants-ja/api-reference/announcement
2.3. データ取得とスプレッドシートへの出力
今回は、スプレッドシートの1列目に記載した銘柄コードから、APIにより銘柄と財務情報を取得し、選別した結果を2列名以降に出力するGASコードを示します。
コード作成にはChatGPTさんの力をフルで借りました(ChatGPTさんはvar変数がお好きなようです)。
function getData() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// ヘッダーの記入
sheet.getRange(1, 1).setValue('銘柄コード');
sheet.getRange(1, 2).setValue('会社名');
sheet.getRange(1, 3).setValue('33業種コード名');
sheet.getRange(1, 4).setValue('市場区分名');
sheet.getRange(1, 5).setValue('開示日');
sheet.getRange(1, 6).setValue('開示時刻');
sheet.getRange(1, 7).setValue('当会計期間の種類');
sheet.getRange(1, 8).setValue('一株あたり当期純利益');
sheet.getRange(1, 9).setValue('一株あたり純資産');
sheet.getRange(1, 10).setValue('一株あたり配当実績_合計');
sheet.getRange(1, 11).setValue('自己資本比率');
sheet.getRange(1, 12).setValue('営業活動によるキャッシュ・フロー');
sheet.getRange(1, 13).setValue('投資活動によるキャッシュ・フロー');
sheet.getRange(1, 14).setValue('財務活動によるキャッシュ・フロー');
sheet.getRange(1, 15).setValue('期末発行済株式数');
// トークンの取得
var url1 = "https://api.jquants.com/v1/token/auth_user";
var data = {
"mailaddress": "*******@*********",
"password": "***********"
};
var options1 = {
"method" : "post",
"payload" : JSON.stringify(data),
"contentType" : "application/json",
"muteHttpExceptions" : true
};
var response1 = UrlFetchApp.fetch(url1, options1);
if (response1.getResponseCode() === 200) {
var jsonRes1 = JSON.parse(response1.getContentText());
var REFRESH_TOKEN = jsonRes1["refreshToken"];
var url2 = "https://api.jquants.com/v1/token/auth_refresh?refreshtoken=" + REFRESH_TOKEN;
var options2 = {
"method" : "post",
"muteHttpExceptions" : true
};
var response2 = UrlFetchApp.fetch(url2, options2);
if (response2.getResponseCode() === 200) {
var response2Json = JSON.parse(response2.getContentText());
var idToken = response2Json.idToken;
Logger.log("成功"); // Success
} else {
Logger.log("失敗"); // Failure
}
} else {
Logger.log("失敗"); // Failure
}
// シートの1列目から銘柄コードの配列を取得
var lastRow = sheet.getLastRow();
var codes = [];
for (var i = 2; i <= lastRow; i++) {
var code = sheet.getRange(i, 1).getValue() + "0"; //末尾に0を加える
codes.push(code);
}
// リスト情報と財務諸表のURLを作成
var infoUrls = codes.map(code => `https://api.jquants.com/v1/listed/info?code=${code}`);
var statementUrls = codes.map(code => `https://api.jquants.com/v1/fins/statements?code=${code}`);
// 認証ヘッダーを設定
var headers = {
"Authorization": "Bearer " + idToken
};
// リクエストオブジェクトを作成
var infoRequests = infoUrls.map(url => ({ "url": url, "headers": headers }));
var statementRequests = statementUrls.map(url => ({ "url": url, "headers": headers }));
// fetchAllで一括リクエスト
var infoResponses = UrlFetchApp.fetchAll(infoRequests);
var statementResponses = UrlFetchApp.fetchAll(statementRequests);
// 銘柄一覧リクエストのレスポンスを処理
infoResponses.forEach(function(response, index) {
var rowIndex = 2 + index;
var content = JSON.parse(response.getContentText());
var info = content['info'][0]; // 最初の要素を取得
if (info) {
sheet.getRange(rowIndex, 2).setValue(info['CompanyName']);
sheet.getRange(rowIndex, 3).setValue(info['Sector33CodeName']);
sheet.getRange(rowIndex, 4).setValue(info['MarketCodeName']);
} else {
sheet.getRange(rowIndex, 2, 1, 3).clearContent(); // 会社名、業種コード名、市場区分名をクリア
}
});
// 財務情報リクエストのレスポンスを処理
statementResponses.forEach(function(response, index) {
var rowIndex = 2 + index;
var content = JSON.parse(response.getContentText());
var fyStatements = content['statements'].filter(statement => statement['TypeOfCurrentPeriod'] === 'FY'); //会計年度をFYでフィルタリング
//最新のFY財務情報を取得
if (fyStatements.length > 0) {
fyStatements.sort(function(a, b) {
return new Date(b['DisclosedDate']) - new Date(a['DisclosedDate']);
});
var latestFYStatement = fyStatements[0];
// 情報をセット
sheet.getRange(rowIndex, 5, 1, 11).setValues([[
latestFYStatement['DisclosedDate'],
latestFYStatement['DisclosedTime'],
latestFYStatement['TypeOfCurrentPeriod'],
latestFYStatement['EarningsPerShare'],
latestFYStatement['BookValuePerShare'],
latestFYStatement['ResultDividendPerShareAnnual'],
latestFYStatement['EquityToAssetRatio'],
latestFYStatement['CashFlowsFromOperatingActivities'],
latestFYStatement['CashFlowsFromInvestingActivities'],
latestFYStatement['CashFlowsFromFinancingActivities'],
latestFYStatement['NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock']
]]);
} else {
sheet.getRange(rowIndex, 2, 1, 11).clearContent(); // 財務情報をクリア
}
});
}
3. 結果
メールアドレスやパスワードは、スクリプトプロパティに格納した方が望ましいです。
また、レスポンス重視でfetchAllで一括リクエストしてますが、銘柄数が多い場合は制限かけた方がいいかもです。
取得した情報を基にして、複数の銘柄を独自指標を用いて分析することが可能ですね。
以上、少しでも参考になれば幸いです。