Google App Script 投資

【GAS】約定内容をスプレッドシートに追記(2)

はじめに

前回は、約定内容をスプレッドシートに追記するライブラリ「libAddStockOrderToList」を作成しました。

今回は、このライブラリを使用してGmailで楽天証券から米国株式の約定通知を受信したら、約定内容をスプレッドシートに追記する仕組みを作ります。

Google App Scriptを使いますので、概要は以下の記事を参照してください。

対象読者

ここで紹介する内容は、以下の条件を満たす方が対象となります。

対象読者

  • 楽天証券の口座を保有している
  • 楽天証券の米国株式約定通知メール設定において「配信希望」としている
  • 楽天証券からの配信メールにGmailを指定している
  • 米国株式約定内容をスプレッドシートに自動登録させたい

では、どのように構築するのか見ていきましょう。

約定内容をスプレッドシートに自動追記

今回は、以前作成した「約定内容カレンダー登録」処理を改造して実現します。

変更点は以下の通りです。

  • スプレッドシート追記用の情報抽出を追加(銘柄名、講座・売買、決済方法、約定単価)
  • スプレッドシートに約定情報を追加する関数呼び出しを追加

約定内容抽出

楽天証券から送られてくる米国株式の約定通知から、以下の赤字に示す部分を抽出します。

米国株式約定通知

関谷 様

米国株式の注文が約定しました。

注文番号:0000
銘柄名(銘柄コード):プルデンシャル・ファイナンシャル(PRU)
口座・売買:特定・買付
決済方法:外貨
約定単価:105.14米ドル
約定数量:2株(口)
約定日時:2021/12/14 23:30

約定は一部約定の場合があります。
詳細は約定照会画面でご確認ください。

■米国株式取引の約定照会
<ウェブ>
PCサイトにログイン後、「注文」→「米国株式」→「注文照会・訂正・取消」

<マーケットスピード>
ログイン後、「注文約定」→「米国株式」→「約定照会」

<iSPEED for iPhone/Android>
ログイン後、「注文」→「米国株式取引」→「約定照会」

■本メールの設定の確認・変更(配信・停止)
PCサイトにログイン後、「マイメニュー」→お客様情報の設定・変更「メールサービス」→通知メール「約定通知メール」
http://www.rakuten-sec.co.jp/cgi-bin/CTS/Direct_Login.cgi?homeid=USER&type=account&sub_type=&local=acc_mail_select&eventType=init

────────────────────────
このメールについてのご質問等は、楽天証券カスタマーサービスセンターまでお気軽にお問い合わせください。
楽天証券カスタマーサービスセンター
フリーダイヤル:0120-41-1004
携帯電話から:03-6739-3333(通話料有料)
受付時間 平日8:30-17:00 (土日祝・年末年始を除く)
https://www.rakuten-sec.co.jp/web/support/
────────────────────────
楽天証券株式会社

メール本文中に現れる「注文番号」から、「約定は一部約定の場合があります」までの間の情報が抽出する対象となります。

そのため、以下に示すようにCUT_START、CUT_ENDで抽出の先頭と終了を識別するための文字を定義しておきます。

// 検索文字列
var CUT_START = '注文番号';
var CUT_END = '約定は一部約定の場合があります。';

以下に示すコードが約定内容の抽出部分です。

      // 楽天証券からの約定メールの内容確認
      var rows = body.split("\n");
      for (var i in rows) {
        var row = rows[i];

        if(row.indexOf(CUT_START) >= 0){
          cutting = true;
        }

        if(cutting){
          if(row.indexOf(CUT_END) >= 0){
            cutting = false;
          }
          else{
            contents += row + '\n';
            if(row.indexOf('銘柄名(銘柄コード):') >= 0){
              ticker = row.match(/([A-Z]*)/);
              ticker_name = row.replace('銘柄名(銘柄コード):', '');
            }
            else if(row.indexOf('口座・売買:') >= 0){
              type = row.replace('口座・売買:', '');
            }
            else if(row.indexOf('決済方法:') >= 0){
              pay_type = row.replace('決済方法:', '');
            }
            else if(row.indexOf('約定単価:') >= 0){
              unit_price = row.replace('約定単価:', '');
              unit_price = unit_price.replace('米ドル', '');
            }
            else if(row.indexOf('約定数量:') >= 0){
              amount = row.match(/\d{1,2}/);
            }
            else if(row.indexOf('約定日時:') >= 0){
              tmp = row.match(/\d{4}\/\d{1,2}\/\d{1,2} \d{1,2}:\d{1,2}/)
              Logger.log(tmp[0]);
              startTime = new Date(tmp[0]);
              endTime = new Date(startTime.getTime() + 10 * 60000); // 終了時刻取得
            }
          }
        }
      }

CUT_STARTからCUT_ENDまでの間に出現した、以下の文字にマッチした場合に必要な情報を抽出します。

文字列の検索には「indexOf()」関数を使用します。

  • 検索文字「銘柄名(銘柄コード):」→ 抽出結果を銘柄コードを「ticker_name」に格納
  • 検索文字「口座・売買:」→ 抽出結果を結果を「type」に格納
  • 検索文字「決済方法:」→ 抽出結果を「pay_type」に格納
  • 検索文字「約定単価:」→ 抽出結果を「unit_price」に格納
  • 検索文字「約定数量:」→ 抽出結果を「amount」に格納
  • 検索文字「約定日時:」→ 抽出結果を「startTime」に格納

スプレッドシート登録

抽出した約定内容をスプレッドシートに登録します。

登録には前回作成したライブラリ「 libAddStockOrderToList 」に定義した「registToSpreadSheet()」を使用します。

まずは、ライブラリを使用できるようにするために、ライブラリ「 libAddStockOrderToList 」のスクリプトIDを確認しコピーします。

次に、ライブラリとして追加します。

ライブラリの「+」ボタンを押し、表示された画面にコピーした「 libAddStockOrderToList」 のスクリプトIDを貼り付けます。

すると、ライブラリとして「 libAddStockOrderToList 」が追加されて使えるようになります。

スプレッドシートに追加する関数は、「registToSpreadSheet()」です。

ライブラリ内の関数呼び出しは、

ライブラリ名.関数名

となるので、以下のように指定します。

      // スプレッドシートに追記
      libAddStockOrderToList.registToSpreadSheet('StockOrderList', '',
        ticker_name, type, pay_type, unit_price, amount, startTime);

スプレッドシート名は「StockOrderList」となります。※お好みで変更してください。

libAddStockOrderToList については以下の記事を参照ください。

全てのコード

Googleカレンダーに追加するコードを改造しています。

/*
 * 楽天証券からの約定メールの内容をGoogle Calendarに登録する
 * 
 * 1.Google Calenderに以下のフォーマットで終日イベントが作成される。
 *   「約定(code)x株」
 * 2.スプレッドシート「StockOrderList」に約定内容が追加される。
 * 
 * 2022/01/06 Created by N.Sekiya
 */

// 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var LABEL = '自動処理済';

// GMail検索文字列(楽天カードからの請求予定金額情報)
var SEARCH_QUERY = 'is:unread -label:' + LABEL + ' from:tradesys@rakuten-sec.co.jp subject:米国株式の注文が約定しました';

// 検索文字列
var CUT_START = '注文番号';
var CUT_END = '約定は一部約定の場合があります。';

function registStockContractInfoToCalendar() {

  // デフォルトカレンダーを取得
  var calendar = CalendarApp.getDefaultCalendar();

  var threads = GmailApp.search(SEARCH_QUERY, 0, 1);
  if (threads.length === 0) {
    Logger.log("メールが見つかりません");
    return;
  }

  for(var k in threads){
    var thread = threads[k]
    var messages = thread.getMessages();
    for (var j in messages){
      var message = messages[j];
      var body = message.getPlainBody();    // HtmlメールからPlain textの本文を取得する
      var cutting = false;
      var ticker = null;
      var amount = null;
      var startTime = null;
      var endTime = null;
      var contents = '';

      // スプレッドシート追記用
      var ticker_name = null;
      var type = null;
      var pay_type = null;
      var unit_price = null;

      // 楽天証券からの約定メールの内容確認
      var rows = body.split("\n");
      for (var i in rows) {
        var row = rows[i];

        if(row.indexOf(CUT_START) >= 0){
          cutting = true;
        }

        if(cutting){
          if(row.indexOf(CUT_END) >= 0){
            cutting = false;
          }
          else{
            contents += row + '\n';
            if(row.indexOf('銘柄名(銘柄コード):') >= 0){
              ticker = row.match(/([A-Z]*)/);
              ticker_name = row.replace('銘柄名(銘柄コード):', '');
            }
            else if(row.indexOf('口座・売買:') >= 0){
              type = row.replace('口座・売買:', '');
            }
            else if(row.indexOf('決済方法:') >= 0){
              pay_type = row.replace('決済方法:', '');
            }
            else if(row.indexOf('約定単価:') >= 0){
              unit_price = row.replace('約定単価:', '');
              unit_price = unit_price.replace('米ドル', '');
            }
            else if(row.indexOf('約定数量:') >= 0){
              amount = row.match(/\d{1,2}/);
            }
            else if(row.indexOf('約定日時:') >= 0){
              tmp = row.match(/\d{4}\/\d{1,2}\/\d{1,2} \d{1,2}:\d{1,2}/)
              Logger.log(tmp[0]);
              startTime = new Date(tmp[0]);
              endTime = new Date(startTime.getTime() + 10 * 60000); // 終了時刻取得
            }
          }
        }
      }
      Logger.log('ticker_name:' + ticker_name);
      Logger.log('type:' + type);
      Logger.log('pay_type:' + pay_type);
      Logger.log('unit_price:' + unit_price);
      Logger.log('amount:' + amount);
      Logger.log('date time:' + startTime);

      // スプレッドシートに追記
      libAddStockOrderToList.registToSpreadSheet('StockOrderList', '',
        ticker_name, type, pay_type, unit_price, amount, startTime);

      // Googleカレンダーに登録
      if(ticker && amount && startTime && endTime){
        var title = '約定' + ticker + amount + '株'; 
        Logger.log(title);
        Logger.log(contents);
        if(checkExist(calendar, startTime, endTime, title) == false){
          var options = {
            description : contents
          }
          var event = calendar.createEvent(title, startTime, endTime, options);
          event.setColor(CalendarApp.EventColor.GREEN);
          event.removeAllReminders();   // 結果なので通知は無し
        }
      }

      // 処理済みメールとしてラベルを付ける
      putLabel(thread); 
    }
  }
}

/*
 * 登録済み情報があるかチェック
 * 
 */
function checkExist(calendar, registStart, registEnd, registTitle){

  // イベントリスト取得
  var events = calendar.getEvents(registStart, registEnd);
  for(const event of events){
    var title = event.getTitle();
    //Logger.log('title:' + title);
    if(title.indexOf(registTitle) >= 0){
      return true;    // イベント登録済み
    }
  }
  // イベント未登録
  return false;
}

/*
 * 処理済みとしてスレッドにラベルを付ける
 * 
 * LABELで指定されるラベルが存在しない場合は作成する
 */
function putLabel(thread){
  var label = GmailApp.getUserLabelByName(LABEL);
  if(label){
    thread.addLabel(label);
    Logger.log('既存ラベル使用');
  }
  else{
    var newlabel = GmailApp.createLabel(LABEL);
    thread.addLabel(newlabel);
    Logger.log('新規ラベル追加');
  }
}

Googleカレンダーの登録が残っていますが、必要なければcalendar.createEventからの3行を削除してください。

繰返し実行

正しく動作することを確認したら、繰り返し実行できるよう設定します。

トリガーを設定し、registStockContractInfoToCalendar()を定期的に呼び出すようにします。

トリガーの設定方法については、以下の記事を参照ください。

繰り返し実行する間隔は、急ぐ必要のない処理なので5分おきにします。

まとめ

いかがでしたでしょうか。

これで楽天証券からの米国株式約定通知メールを受信すると、カレンダーに追加し、スプレッドシートに追加されるようになりました。

自分が必要な情報を、自動的に必要な場所に必要な形にすることで、ほんの少しストレスが解消されて、生きやすくなると思います。

それを積み重ねることで、積みあがった自由時間を使い、もっと自由な発想で面白いことに取り組めるようになるはずです。

技術は人を自由にすると思うのです。

では、今日も良い一日を。

-Google App Script, 投資
-, , , ,