どんな記事
前回、価格データの自動取得について解説しましたが、今回はそれを応用してみます。自動取得した価格データをもとに【テクニカル指標を計算してgoogleスプレッドシートに保存する】一連の流れを解説してみようと思います。
準備するもの
このページのスキームを使用するには、以下のツールが必要です(いずれも無料)。
今回、これらの細かい解説については割愛しますが、簡単に言えば、「この無料の2つのツールを導入するだけで自動でテクニカル指標を計算させるスキームをつくることができる」ということですね!すばらしい(ΦωΦ)
コードとサンプル(完成品もあるよ)
さて、まずはコードから。
今回はひとつのGASに3つのファイルをつくりました(図の左側のことですね)。コードの煩雑化を防ぐためです。すべてテスト済み。コピペで使用できます。
補助コード
以前の記事でも紹介したCSVを取得する関数と、CSVを配列に変換する関数です。
function _getCsv(URL) {
var response = UrlFetchApp.fetch(URL)
,data = {
contentString : response.getContentText().toString()
,responseCode : response.getResponseCode()
};
return data;
}
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 );
}
moment.js
moment.gsは「moment.js」という時間処理系のライブラリを使用しています。リンク先のコードをそのままコピペして使います。
かなり有名なライブラリなので、分からないことがあれば検索して調べてみてください。
// moment.jsのコードをコピペ
メインのコード
メインの処理を行うコードです。解説はコード内にコメントアウトで書いてあります。
分からなければコメント欄からどんどんご質問ください!
function GET_AND_CALC_TFX(){
var GV = {
address : ""
,mail_title : "スクリプトを稼働しました"
,SS : SpreadsheetApp.getActiveSpreadsheet()
,ROW : 2
,SYM_TFX : ["USD/JPY","EUR/JPY","GBP/JPY"]
,SYM_TFX_NUM : [1 ,2 ,3 ]
,SYM_TFX_round : [4 ,4 ,4 ]
,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 ]
,ITEM_TECH : ["TR","ATR14","ATR20","EMA5","EMA20","EMA-Signal"]
,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");
GV["URL"] = "http://www.tfx.co.jp/kawase/document/PRT-010-CSV-003-"+GV.YEST+".CSV";
GV["SHEET"] = (function(sym_tfx){
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++){
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+')'
,'=round(('+abcATR14+row_1+'*13+'+abcTR+row+'*2)/15,'+round+')'
,'=round(('+abcATR20+row_1+'*19+'+abcTR+row+'*2)/21,'+round+')'
,'=round(('+abcEMA5+row_1+'*4+'+abcClose+row+'*2)/6,'+round+')'
,'=round(('+abcEMA20+row_1+'*19+'+abcClose+row+'*2)/21,'+round+')'
,'=if('+abcEMA5+row+'='+abcEMA20+row+',0,if('+abcEMA5+row+'>'+abcEMA20+row+',1,-1))'
]]
;
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]+"の新たなデータはありませんでした。")
}
}
}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()
);
}
}
完成品(サンプル)
サンプルも用意しています。
このサンプルについてはプログラムを走らせているので、この3銘柄についてはこのまますぐに使用できるはずです(変な点があればお知らせください)。
銘柄を増やす場合はいろいろありますので、下部の解説をご覧ください。
導入の手順
導入にあたって、この手のプログラムは人によって求めるものが全然変わってくると思います。以下に何通りか導入の方法を解説してみます。
まずは動かしてみる
なにはともあれ、まずは動かしてみましょう。
まずは以下のサンプルを開いて、次の手順を行います。
- 「ファイル ▷ コピーを作成」で自身のgoogleドライブにコピーを作成する。
- 作成したファイルを開き、「ツール ▷ スクリプトエディタ」でエディタを開く。
- 左上の名前を変更して保存(名前は何でも良い)。
- 「実行 ▷ GET_AND_CALC_TFX」から実行することができる。毎日自動的に実行する場合は「リソース ▷ 現在のプロジェクトのトリガー」で設定する(時間主導型、日タイマー、午前10時〜11時)。
銘柄を増やすには(東京金融取引所編)
こういう要望であれば比較的簡単です。
- まずはヒストリカルデータからデータを取得する。
- 取得したデータをもとにスプレッドシートの関数を使用してテクニカル指標を計算する。
- 数式をすべて値のみにする。
手順のスプレッドシートを用意してみたので、必要な方は見ていただくと分かりやすいと思います。
東京金融取引所以外の銘柄を増やすには
解説しはじめるとキリがないので詳細は割愛しますが、以前の記事「googleスプレッドシートでCSV(価格データ)を自動取得する(ちょっとした応用まで)」を参考に別途新たなスプレッドシートとGASを作成するのが良いと思います。
この記事と以前の記事を組み合わせれば個別株以外のほとんどの銘柄のテクニカル指標を自動で算出させることができます。
また、これをやる場合にはGASをライブラリ化してコードの効率をあげた方が良いと思われます。momentの部分とか、補助のコードあたりですね。同じコードをあちこちに書くのは効率がわるいので。
テクニカル指標を増やすには
これはスプレッドシートの関数でテクニカル分析の計算ができればいくらでも増やすことができます。たくさん良いブログがありますので関数でのテクニカル指標の算出の解説は他のブログに譲ろうと思います。この記事で提供したコードの拡張方法についてはメインのコードの解説でちょっとだけ触れてますので参考にしてみてく ださい。
その他の応用
その他の応用として筆者がやってることは次のようなことがあります。
- 日々のトレードのスプレッドシートに銘柄毎の最新の計算値を持ってくる
- Close
- ATR20
- EMA(300,50)
- MACD(19,6,9)
- +DI,-DI
- 相関係数
- 相関リスク
- 等々…
- 計算値をもとに資金管理やリスク管理の計算値を算出
- 日々の「破産の確率」を算出
- これらのスキームを応用して検証作業(バックテスト)
単一銘柄の分析ならMT4で良いんですけどね。筆者は今のところこのスキームが最高だとおもっています。 また、上記の中でいうと、最近は検証作業にかなり時間を費やしています。まずは「伝説のトレーダー集団 タートル流投資の魔術(amazonへ)」にある検証データをすべて試してみるのが目標です。年内には全部終わらせたいですね…!
このへんも少しずつブログにアップしていく予定です。
まとめ
なかなか、こういう話になってくるとややこしい記事になりがちですね。
できるだけ分かりやすい記事にできるように心がけていますが、分かりづらい部分があればどんどんご質問いただければと思います。
この記事で解説したように、自動化することによってプログラムが代わりに仕事をしてくれるようになるので、単純作業をプログラムにまかせることで重要なことに集中することができるようなります。人ひとりでできることは限られているのでどんどん活用していきたいものです。
それでもやっぱり限界があるので、それ以上となると売上あげて 雇用してチャレンジしていかないとですね。
ちなみにタイトルの「googleスプレッドシート版」というのは、筆者のなかで「Fusion Tables版」というものもあって「いつかその解説もしたいな」ということで、そういうタイトルにしてみてます。解説したいな、いつか――。
開発を承っています
- Pineスクリプト(インジケーターやストラテジー)
- Google Apps Script
- Python
- MQL4
などの開発を承っています。とくに投資関連が得意です。過去の事例は「実績ページ(不定期更新)」でご確認ください。ご相談は「お問い合わせ」からお願いします。
- 記事をシェア