Google App Script LINE 投資

【GAS】約定内容をカレンダーとスプレッドシートに記録しLINE通知

はじめに

今回は、約定通知メールを受け取った時の以下の処理を統合します。

  • Googleカレンダーに追加
  • Googleスプレッドシートに追加
  • LINEに通知

これまでの処理は、以下の記事を参照ください。

対象読者

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

対象読者

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

では、これまでの処理を統合しましょう。

約定メール受信処理統合

今回は、以下の記事で紹介したコードにLine通知機能を追加することで実現します。

Lineに通知する処理部分のみを追加すればよいので、変更点は以下の通りです。

  • Line通知内容の作成
  • Line通知処理実装

約定内容抽出

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

米国株式約定通知

関谷 様

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

注文番号: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/
────────────────────────
楽天証券株式会社

この部分の抽出は、カレンダーに「メモ」として登録するために既に抽出しています。

以下に示すコードの「contents」に格納されるので、これをLineの通知に使用します。

      // 楽天証券からの約定メールの内容確認
      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); // 終了時刻取得
            }
          }
        }
      }

Line通知処理

Line通知処理は以下のコードを使用します。

function sendLine(strDate, strSubject, strMessage){
   
  //Lineに送信するためのトークン(「約定通知」に通知する)
  var strToken = "<ここにLINE notifyで取得したトークンを記載します>";
  var options =
   {
     "method"  : "post",
     //"payload" : "message=" + strDate + strSubject + strMessage,
     "payload" : "message=" + strMessage,
     "headers" : {"Authorization" : "Bearer "+ strToken}
 
   };
   UrlFetchApp.fetch("https://notify-api.line.me/api/notify",options);
}

呼び出し側からは、以下のように使います。

      // LINEに通知する
      sendLine(null, null, contents);

※sendLine()中で、strDataとstrSubjectは使ってないので、sendLine()の引数から削除しても問題ありませんね。

「<ここにLINE notifyで取得したトークンを記載します>」は使用するトークンに置き換えてください。

Lineに通知するためには準備が必要なので、以下の記事を参考にして「LINE notifyのトークン」を取得してください。

全てのコード

Googleカレンダーに登録した後に、sendLine()を使い、contentsをLine通知に使用しています。

/*
 * 楽天証券からの約定メールの内容をGoogle Calendarに登録する
 * 
 * 1.Google Calenderに以下のフォーマットで終日イベントが作成される。
 *   「約定(code)x株」
 * 2.スプレッドシート「StockOrderList」に約定内容が追加される。
 * 3.Lineに通知する
 * 
 * 2022/01/15 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 registStockContractInfo() {

  // デフォルトカレンダーを取得
  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();   // 結果なので通知は無し
        }
      }

      // LINEに通知する
      sendLine(null, null, contents);

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

function sendLine(strDate, strSubject, strMessage){
   
  //Lineに送信するためのトークン(「約定通知」に通知する)
  var strToken = "<ここにLINE notifyで取得したトークンを記載します>";
  var options =
   {
     "method"  : "post",
     //"payload" : "message=" + strDate + strSubject + strMessage,
     "payload" : "message=" + strMessage,
     "headers" : {"Authorization" : "Bearer "+ strToken}
   };
   UrlFetchApp.fetch("https://notify-api.line.me/api/notify",options);
}

/*
 * 登録済み情報があるかチェック
 * 
 */
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('新規ラベル追加');
  }
}

繰返し実行

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

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

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

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

まとめ

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

これで楽天証券からの米国株式約定通知メール受信後の処理が統合されて、カレンダー追加、スプレッドシート追加、Line通知が自動化されました。

今まで手作業していた内容がすべて自動化されたことで、とても清々しい気分になるかと思います。

もっともっと自動化による便利さを追求しましょう。

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

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