日々のテクニカル指標を自動計算させる:価格の取得から計算とデータの保存まで(googleスプレッドシート版)

日々のテクニカル指標を自動計算させる:価格の取得から計算とデータの保存まで(googleスプレッドシート版)
前回、価格データの自動取得について解説しましたが、今回はそれを応用してみます。自動取得した価格データをもとに【テクニカル指標を計算してgoogleスプレッドシートに保存する】一連の流れを解説してみようと思います。

日々のテクニカル指標を自動計算させる:価格の取得から計算とデータの保存まで(googleスプレッドシート版)

  1. 準備するもの
  2. コードの解説(完成品もあるよ)
    1. 補助コード
    2. moment.js
    3. メインのコード
    4. 完成品(サンプル)
  3. 導入の手順
    1. まずは動かしてみる
    2. 銘柄を増やすには(東京金融取引所版)
    3. 東京金融取引所以外の銘柄を増やすには
    4. テクニカル指標を増やすには
    5. その他の応用
  4. まとめ

1.準備するもの

このページのスキームを使用するには、以下のツールが必要です(いずれも無料)。

今回、これらの細かい解説については割愛しますが、簡単に言えば、「この無料の2つのツールを導入するだけで自動でテクニカル指標を計算させるスキームをつくることができる」ということですね!すばらしい(ΦωΦ)

目次へ

2.コードとサンプル(完成品もあるよ)

さて、まずはコードから。

今回はひとつのGASに3つのファイルをつくりました(図の左側のことですね)。コードの煩雑化を防ぐためです。すべてテスト済み。コピペで使用できます。

2-1.補助コード

以前の記事でも紹介したCSVを取得する関数と、CSVを配列に変換する関数です。

補助コード.gs

/**
 * get csv files
 * csvを取得してテキストで返す
 */
function _getCsv(URL) {
  var response = UrlFetchApp.fetch(URL)
     ,data = {
       contentString : response.getContentText().toString()   
      ,responseCode : response.getResponseCode() 
     };
  return data;
}



/**
 * Csv to array
 */
function _CSVToArray( strData, strDelimiter ){
  strDelimiter = (strDelimiter || ",");
  var objPattern = new RegExp(
    (
      "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
      "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
      "([^\"\\" + strDelimiter + "\\r\\n]*))"
    ),
    "gi"
  );
  var arrData = [[]];
  var arrMatches = null;
  while (arrMatches = objPattern.exec( strData )){
    var strMatchedDelimiter = arrMatches[ 1 ];
    if (
      strMatchedDelimiter.length &&
      (strMatchedDelimiter != strDelimiter)
      ){
        arrData.push( [] );
      }
    if (arrMatches[ 2 ]){
      var strMatchedValue = arrMatches[ 2 ].replace(
        new RegExp( "\"\"", "g" ),
        "\""
      );
      
    } else {
      var strMatchedValue = arrMatches[ 3 ];
    }
    arrData[ arrData.length - 1 ].push( strMatchedValue );
  }
  return( arrData );
}

目次へ

2-2.moment.js

moment.gsは「moment.js」という時間処理系のライブラリを使用しています。リンク先のコードをそのままコピペして使います。

かなり有名なライブラリなので、分からないことがあれば検索して調べてみてください

moment.gs

// moment.jsのコードをコピペ

目次へ

2-3.メインのコード

メインの処理を行うコードです。解説はコード内にコメントアウトで書いてあります。

分からなければコメント欄からどんどんご質問ください!

コード.js

// ※ 取引所のCSVは日毎のファイルです。日曜、月曜、祝日はこのコードは使えません。
function GET_AND_CALC_TFX(){
  
  var GV = {
    
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    // 設定 /////////////////////////////////////////
    
    // 稼働の報告メールが必要な場合はここにアドレスをいれる。
    // 例)address@gmail.com
    address     : "" 
    ,mail_title : "スクリプトを稼働しました"
    
    // 書き込み先 
    ,SS  : SpreadsheetApp.getActiveSpreadsheet()
    ,ROW : 2 // この場合2行目以下がすべてデータ
    
    // 銘柄
    // NUMは取引所が指定する銘柄コード
    // スプレッドシートは銘柄毎のシートを作成(※シートの名前をSYM_TFXの銘柄名と同一にすること)
    ,SYM_TFX       : ["USD/JPY","EUR/JPY","GBP/JPY"]
    ,SYM_TFX_NUM   : [1        ,2        ,3        ] //TFXのCSVの並び順
    ,SYM_TFX_round : [4        ,4        ,4        ] //TFXの銘柄毎の小数点
    
    // 項目
    // NUMは取得するCSVの項目に対応する列数
    ,ITEM_TFX     : ["Date","Source","Symbol","Open","High","Low","Close","SettlementPrice","SwapPoint","TradingVolume","OpenInterest"]
    ,ITEM_TFX_NUM : [1     ,""      ,3       ,6     ,8     ,10   ,12     ,14               ,16         ,17             ,18            ]
    // ※ テクニカル指標を増やす場合は下部のfomulas関連も適宜追加する
    ,ITEM_TECH    : ["TR","ATR14","ATR20","EMA5","EMA20","EMA-Signal"]

    // 設定ここまで /////////////////////////////////
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////

    // 数字を「ABC〜」に直すために使用する
    ,ABC : ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK","AL","AM"] 
  };
  GV["YEST"]  = moment().subtract(1 ,"days").format("YYYYMMDD"); // URL用の日付を作成
  GV["URL"]   = "http://www.tfx.co.jp/kawase/document/PRT-010-CSV-003-"+GV.YEST+".CSV";
  GV["SHEET"] = (function(sym_tfx){ // シートを配列化 [sheet ,sheet .sheet]
    var result = new Array();
    for(var i=0 ,len=sym_tfx.length; i<len; i++){
      result.push(GV.SS.getSheetByName(sym_tfx[i]));
    }
    return result;
  })(GV.SYM_TFX);

  
  // メインの処理
  try{
    var
     items      = GV.ITEM_TFX.concat(GV.ITEM_TECH) // 項目リストを作成しておく
    ,arraySS    = new Array()
    ,arraySS_b4 = new Array()
    ,preDate
    ,getCsv     = _getCsv(GV.URL)
    ,csvData    = _CSVToArray(getCsv.contentString,",")
    ;
    
    
    // 銘柄の数だけ処理を繰り返す
    for(var i=0 ,symLen=GV.SYM_TFX.length; i<symLen; i++){ // for1
      
      
      // 最新の価格と取引所から取得して成形する
      arraySS[i] = new Array();
      if(csvData[i].indexOf("�|�|�|")==-1){ // 休場の判別
        
        for(var j=0 ,itmLen=GV.ITEM_TFX.length; j<itmLen; j++){
          if(j==0){ 
            preDate       = csvData[GV.SYM_TFX_NUM[i]][GV.ITEM_TFX_NUM[j]]
            arraySS[i][0] = preDate.slice(0,4)+"/"+preDate.slice(4,6)+"/"+preDate.slice(6);
          }else if(j==1){
            arraySS[i][1] = "TFX";
          }else if(j==2){
            arraySS[i][2] = GV.SYM_TFX[i];
          }else{
            arraySS[i][j] = (csvData[GV.SYM_TFX_NUM[i]][GV.ITEM_TFX_NUM[j]] || "\'\'");
          }
        }
      
      // 休場の場合
      }else{
        arraySS[i][0] = "休場"
      }
      
      
      // 記録してあるデータの中で最も新しいものを取得
      var
       lastRow = GV.SHEET[i].getLastRow()
      ,lastCol = GV.SHEET[i].getLastColumn()
      ;
      arraySS_b4[i] = GV.SHEET[i].getRange(lastRow ,1 ,1 ,lastCol).getValues()[0];
      
      
      // テクニカル分析の数式を作成してデータと数式を挿入する
      // 外部から取得したデータが既存のデータより新しいかどうかを確認
      var isNewDate  = moment(arraySS[i][0] ,"YYYY/MM/DD").isAfter(moment(arraySS_b4[i][0]) ,"days");
      if(isNewDate && arraySS[i][0]!=="休場"){
        
        var
         abcHigh    = GV.ABC[items.indexOf("High")]  
        ,abcLow     = GV.ABC[items.indexOf("Low")]   
        ,abcClose   = GV.ABC[items.indexOf("Close")] 
        ,abcTR      = GV.ABC[items.indexOf("TR")]    
        ,abcATR14   = GV.ABC[items.indexOf("ATR14")] 
        ,abcATR20   = GV.ABC[items.indexOf("ATR20")] 
        ,abcEMA5    = GV.ABC[items.indexOf("EMA5")] 
        ,abcEMA20   = GV.ABC[items.indexOf("EMA20")]  
        ,abcEMA_Sig = GV.ABC[items.indexOf("EMA_Signal")]  
        ,row        = (lastRow+1)
        ,row_1      = lastRow
        ,round      = GV.SYM_TFX_round[i]
        // 数式を作成する
        // テクニカル指標を増やす場合はここも追加する
        ,formulas = [[
          '=round(max(abs('+abcHigh+row+'-'+abcLow+row+'),abs('+abcHigh+row+'-'+abcClose+row_1+'),abs('+abcLow+row+'-'+abcClose+row_1+')),'+round+')' // TR
          ,'=round(('+abcATR14+row_1+'*13+'+abcTR+row+'*2)/15,'+round+')'    // ATR14
          ,'=round(('+abcATR20+row_1+'*19+'+abcTR+row+'*2)/21,'+round+')'    // ATR20
          ,'=round(('+abcEMA5+row_1+'*4+'+abcClose+row+'*2)/6,'+round+')'    // EMA5
          ,'=round(('+abcEMA20+row_1+'*19+'+abcClose+row+'*2)/21,'+round+')' // EMA20
          ,'=if('+abcEMA5+row+'='+abcEMA20+row+',0,if('+abcEMA5+row+'>'+abcEMA20+row+',1,-1))' // EMA_Signal
        ]]
        ;
        if(isNewDate){
          var arLen = arraySS[i].length;
          GV.SHEET[i].getRange(lastRow+1 ,1 ,1 ,arLen).setValues([arraySS[i]]);                  // データを挿入
          GV.SHEET[i].getRange(lastRow+1 ,arLen+1 ,1 ,formulas[0].length).setFormulas(formulas); // 数式を挿入
          
          // データが古くなってくるとスプレッドシートが重くなるので、一番古いデータを消す工程を増やすと良い
          GV.SHEET[i].getRange(lastRow ,1 ,1 ,arraySS_b4[i].length).setValues([arraySS_b4[i]]);  // ひとつ前のデータを数式→値のみにする
          GV.SHEET[i].deleteRow(GV.ROW); // 一番古いデータを削除する
        }
        Logger.log(
          GV.SYM_TFX[i]+"の"+arraySS[i][0]+"のデータを追加しました。\n"
          +arraySS[i]+"\n"
          +formulas+"\n"
        );
        
        
      // 休場、もしくは外部から取得したデータが新しくない
      }else{
        Logger.log(GV.SYM_TFX[i]+"の新たなデータはありませんでした。")
      }
    } // end for1
    
    
  // エラーが発生した場合の処理  
  }catch(e){
    if(GV.address!==""){
      MailApp.sendEmail(
        GV.address
        ,("【エラー】"+GV.mail_title)
        ,e+"\n\n\n"+Logger.getLog()
      );
    }
    return;
  }
  
  // 報告のメールを送信する
  if(GV.address!==""){
    MailApp.sendEmail(
      GV.address
      ,GV.mail_title
      ,Logger.getLog()
    );
  }
}

目次へ

2-4.完成品(サンプル)

サンプルも用意しています。

このサンプルについてはプログラムを走らせているので、この3銘柄についてはこのまますぐに使用できるはずです(変な点があればお知らせください)。

銘柄を増やす場合はいろいろありますので、下部の解説をご覧ください。

* googleドライブにコピーしてそのまま使用することができます。

目次へ

3.導入の手順

導入にあたって、この手のプログラムは人によって求めるものが全然変わってくると思います。以下に何通りか導入の方法を解説してみます。

3-1.まずは動かしてみる

なにはともあれ、まずは動かしてみましょう。

まずは以下のサンプルを開いて、次の手順を行います。

  1. 「ファイル ▷ コピーを作成」で自身のgoogleドライブにコピーを作成する。
  2. 作成したファイルを開き、「ツール ▷ スクリプトエディタ」でエディタを開く。
  3. 左上の名前を変更して保存(名前は何でも良い)。
  4. 「実行 ▷ GET_AND_CALC_TFX」から実行することができる。毎日自動的に実行する場合は「リソース ▷ 現在のプロジェクトのトリガー」で設定する(時間主導型、日タイマー、午前10時〜11時)。

* その日の実行がすでに終わっている場合(午前10時〜11時以降)は、3銘柄の最新の行を削除して試してみてください。

目次へ

3-2.銘柄を増やすには(東京金融取引所編)

こういう要望であれば比較的簡単です。

  1. まずはヒストリカルデータからデータを取得する。
  2. 取得したデータをもとにスプレッドシートの関数を使用してテクニカル指標を計算する。
  3. 数式をすべて値のみにする。

手順のスプレッドシートを用意してみたので、必要な方は見ていただくと分かりやすいと思います。

* くりっく株365の場合はCSVファイルが変わります。

目次へ

3-3.東京金融取引所以外の銘柄を増やすには

解説しはじめるとキリがないので詳細は割愛しますが、以前の記事「googleスプレッドシートでCSV(価格データ)を自動取得する(ちょっとした応用まで)」を参考に別途新たなスプレッドシートとGASを作成するのが良いと思います。

この記事と以前の記事を組み合わせれば個別株以外のほとんどの銘柄のテクニカル指標を自動で算出させることができます。

また、これをやる場合にはGASをライブラリ化してコードの効率をあげた方が良いと思われます。momentの部分とか、補助のコードあたりですね。同じコードをあちこちに書くのは効率がわるいので。

目次へ

3-4.テクニカル指標を増やすには

これはスプレッドシートの関数でテクニカル分析の計算ができればいくらでも増やすことができます。たくさん良いブログがありますので関数でのテクニカル指標の算出の解説は他のブログに譲ろうと思います。この記事で提供したコードの拡張方法についてはメインのコードの解説でちょっとだけ触れてますので参考にしてみてください。

目次へ

3-5.その他の応用

その他の応用として僕がやってることは次のようなことがあります。

  • 日々のトレードのスプレッドシートに銘柄毎の最新の計算値を持ってくる
    • Close
    • ATR20
    • EMA(300,50)
    • MACD(19,6,9)
    • +DI,-DI
    • 相関係数
    • 相関リスク
    • 等々…
  • 計算値をもとに資金管理やリスク管理の計算値を算出
  • 日々の「破産の確率」を算出
  • これらのスキームを応用して検証作業(バックテスト)

単一銘柄の分析ならMT4で良いんですけどね。僕は今のところこのスキームが最高だとおもっています。また、上記の中でいうと、最近は検証作業にかなり時間を費やしています。まずは「伝説のトレーダー集団 タートル流投資の魔術(amazonへ)」にある検証データをすべて試してみるのが目標です。年内には全部終わらせたいですね…!

このへんも少しずつブログにアップしていく予定です。

目次へ

4.まとめ

なかなか、こういう話になってくるとややこしい記事になりがちですね。

できるだけ分かりやすい記事にできるように心がけていますが、分かりづらい部分があればどんどんご質問いただければと思います。

この記事で解説したように、自動化することによってプログラムが代わりに仕事をしてくれるようになるので、単純作業をプログラムにまかせることで重要なことに集中することができるようなります。人ひとりでできることは限られているのでどんどん活用していきたいものです。

それでもやっぱり限界があるので、それ以上となると売上あげて雇用してチャレンジしていかないとですね。

ちなみにタイトルの「googleスプレッドシート版」というのは、僕のなかで「Fusion Tables版」というものもあって「いつかその解説もしたいな」ということで、そういうタイトルにしてみてます。解説したいな、いつか――。

そんなところです!

では( ー`дー´)キリッ!

目次へ

Back to Top

Investment Tech Hack

Sorry... doesn't support your browser

To get the best possible experience using our site we recommend that you upgrade to a modern web browser. Investment Tech Hackではご利用中のブラウザサポートはしていません。
Internet Explorerのアップグレード行う、もしくはその他のブラウザを使用しての閲覧をお願いします。