プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

保有株式の時価総額を毎日集計する

日々変動する株価に対して向き合う

株価は日々変動していますが、自身のポジションが増えたり減ったりすることに一喜一憂しているのは不毛です。
とくにNISAで中長期で考えている場合がこれに当たりますが、そうはいっても自分の投資方針、銘柄選択の方針があっているのかどうか?を確認することは必要です。
そのためには、ベンチマークとしての日経平均やダウ平均との比較、月平均でプラスなのかマイナスなのか?といったことを分析することが必要と考えました。

証券口座ではその時々の自身のポジションの時価総額や損益は出ますが、これの中心値や平均値がどこにあるのかわかりません。
そのため、まずは1か月間の含み益の平均値や最大最小値をとってみるなどの分析をしようと考えました。

このようなことを行うためのツールとして、今回はGoogleスプレッドシートスクリプトの自動実行を行い、毎日の終値基準での時価総額を算出しました。

ここで、必要なデータは保有銘柄の取得平均額、保有株数、現在価格です。
また、ベンチマークとして日経平均とダウ平均を取得します。

本来は証券口座からAPIで自身のポジションが取得できたらいいのですが、そのような機能はなさそうなので、Google Financeから取得します(スクレイピング)。
サンプルコードが以下にありましたので、これを参考にします。
ライブラリID1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNwを追加する必要があります。
zenn.dev

function getStockPrice(code) {
  //GoogleファイナンスURLと銘柄コードを組み合わせ、スクレイピング先URLを定義
  let url = 'https://www.google.com/finance/quote/' + code + ':TYO';
  if (code == "NI225") {
    url = 'https://www.google.com/finance/quote/NI225:INDEXNIKKEI';
  }
  else if (code == "DJI") {
    url = 'https://www.google.com/finance/quote/.DJI:INDEXDJX';
  }
  //スクレイピング先URLに対し、フェッチしてHTMLソースを取得
  let html = UrlFetchApp.fetch(url).getContentText();
  //HTMLソースから株価部分を抽出し、変数に格納
  let stockPrice = Parser.data(html)
    .from('<div class="YMlKec fxKbKc">')
    .to('</div>')
    .build();
  stockPrice = stockPrice.replace(",", "");
  stockPrice = stockPrice.replace("\¥", "");

  //  console.log(Number(stockPrice));
  return Number(stockPrice);
}

参考コードに対して、日経平均とダウ平均が取得できる機能を追加、また文字列で取得されるので、数値になるように修正をしています。
これで、証券コードを引数で与えると株価が取得できます。

次に、シートとして、1~8行目までをHedderとしてここには手動で銘柄や証券コード、平均取得額、保有数などを追加していきます。

このHeader情報をよみとって、毎日データを取得し追加していきます。
あらゆる情報を自動で取り込む、とかはせず割り切りで足りない部分は手動で入力していきます。
もし動かしてみてデータが入力されない部分があれば、それは仕様です。コードを読み解いて、自動で入力されない部分は手動で対応してください。

function getCurrent() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const dataSheet = ss.getSheetByName('data'); //dataシート取得
  let codeRow = 4; //証券コード
  let rightMonRow = codeRow + 1//権利確定月
  let numRow =  rightMonRow + 1; //保有株数数
  let rowAveValueRow = numRow + 1; //平均取得単価
  let rowParamCnt = 4; //株数 - 評価損益
  let startColumn = 8 //H列
  let targetRow = dataSheet.getRange(dataSheet.getMaxRows(), 3).getNextDataCell(SpreadsheetApp.Direction.UP).getRow() + 1;
  let cmn = startColumn;

  //日付
  let date = new Date();
  dataSheet.getRange(targetRow, 2).setValue(date);
  //行タイトルを入れる
  dataSheet.getRange(targetRow - rowParamCnt, 3, targetRow - 1, 3).copyTo(dataSheet.getRange(targetRow, 3), SpreadsheetApp.CopyPasteType.PASTE_FORMULA, false);
  //評価損益合計
  dataSheet.getRange(targetRow + 3 - rowParamCnt, startColumn - 2).copyTo(dataSheet.getRange(targetRow + 3, startColumn - 2), SpreadsheetApp.CopyPasteType.PASTE_FORMULA, false);
  dataSheet.getRange(targetRow + 3 - rowParamCnt, startColumn - 1).copyTo(dataSheet.getRange(targetRow + 3, startColumn - 1), SpreadsheetApp.CopyPasteType.PASTE_FORMULA, false);
  //ベンチマーク取得
  dataSheet.getRange(targetRow + 3, 4).setValue(getStockPrice("NI225"));
  dataSheet.getRange(targetRow + 3, 5).setValue(getStockPrice("DJI"));
  do {
    //株数
    let value = dataSheet.getRange(numRow, cmn).getValue()

    dataSheet.getRange(targetRow, cmn).setValue(value);
    //平均取得単価
    value = dataSheet.getRange(rowAveValueRow, cmn).getValue()
    dataSheet.getRange(targetRow + 1, cmn).setValue(value);
    //現在価格
    let stockCode = dataSheet.getRange(codeRow, cmn).getValue()
    value = getStockPrice(stockCode);
    dataSheet.getRange(targetRow + 2, cmn).setValue(value);
    //評価損益
    dataSheet.getRange(targetRow - 1, cmn).copyTo(dataSheet.getRange(targetRow + 3, cmn, 1, 1), SpreadsheetApp.CopyPasteType.PASTE_FORMULA, false);
    cmn += 1;
  } while (dataSheet.getRange(3, cmn).getValue() != "") //3行目銘柄が空白
}

あとは、これを1日1回自動で起動するようにしておきます。
Google Financeの情報はディレイがあるようなので、15:20以降に1度実施されるようにしておきます。

function timerExe() {
  var now = new Date();
  var hour = now.getHours();
  var minite = now.getMinutes();
  var day = now.getDay()
  //日曜と土曜はスキップ
  if (day == 0 || day == 6) {
    return;
  }

  //15:10~16:09のとき実行
  if ((hour == 15 && 20 <= minite) || (hour == 16 && minite < 20)) {
    console.log("timerExe");
    getCurrent();
  }
}

自動実行はトリガーから設定します。
最小周期は1時間のようです。

結果

7月末までは調子が良かったですが、いっきにマイナスになりました。
7月末までは、日経平均よりも安定していたのですが、8月に入っての急落で一緒に急落しています。

まとめ

GASとGoogle spread sheetで日々のポジション推移を記録してみました。
このようにしてみると、輸出関連企業に偏っていたことがわかりました。
株価というものは、これぐらいの調整はあるもので日経平均3万円というのも想定PERから見ても下限を割ったわけではないそうです。とはいってもこれ以上さがるかもしれないしそうじゃないかもしれませんが、冷静に見つめていきましょう。
特にNISAでは狼狽売りは負けだと思うべきで、私の場合は評価額-30万円は配当2年分で取り返せる水準という見立てがあります。

www.youtube.com

また、株取引については、こちらで不定期に思ったことを書いています。
s51517765.hatenablog.jp