google apps script:テクニカル分析を計算する

Posted on January 2nd, 2017Updated on May 4th, 2019
google apps script:テクニカル分析を計算する

どんな記事

前回、相関係数のプログラムを公開してみましたが、今回は、JavaScriptやgoogle apps scriptをつかって基本的なテクニカル分析を計算させてみます。JavaScriptとgoogle apps scriptの記述は一緒です(ほぼ)。

基本のプログラム

まずはライブラリ化している基本的な関数を。

小数点の桁数を指定して四捨五入する

JavaScriptで小数の計算をさせると、ものすごーく小さいですが誤差がでます。計算上は大きな問題ではないのですが、そのまま出力すると小数の桁数が大変なことになるので、何気に重宝する関数です。

roundN
function roundN(v ,n){
  var a=1 ,i;
  for(i=0; i<n; i++){
    a += "0";
  }
  return Math.round(v *a) /a;
}

TR(True Range)

ワイルダーさん考案のテクニカル分析でよく使います。

TrueRange
function TR(high,low,last){
  var m = Math;
  return m.max(m.abs(high -low) ,m.abs(high -last) ,m.abs(low -last));
}

EMA(指数平滑移動平均)

ExponentialMovingAverage
function EMA(N,EMAy,P){
  return (EMAy *(N -1) +P *2) /(N +1);
}

配列の構造

テクニカル分析を計算するには、元となるデータ が必要です。それが各コードのはじめの部分にあるar = {sym:[[Date ,Open ,High ,Low ,Close]]}です。これは単に配列の構造を表していて、その構造にもとづいた配列のデータをあらかじめ作っておかないと動きません。

以下で解説します。

配列の構造

var list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"TR" ,"ATR"];

var ar = {
  Nikkei225 : [

   [2017/01/11 ,19358.64 ,19402.17 ,19325.46 ,19364.67]
  ,[2017/01/12 ,19300.19 ,19300.19 ,19069.02 ,19134.7]
  ]
  ,USDJPY : [
   [2017/01/11 ,114.723 ,115.444 ,114.183 ,114.551]
  ,[2017/01/12 ,115.407 ,115.416 ,113.771 ,114.69]
  ]
};

var ar = {
  Nikkei225 : [

   [2017/01/11 ,19358.64 ,19402.17 ,19325.46 ,19364.67]
  ,[2017/01/12 ,19300.19 ,19300.19 ,19069.02 ,19134.7 ,"計算されたTR" ,"計算されたATR"]
  ]
  ,USDJPY : [
   [2017/01/11 ,114.723 ,115.444 ,114.183 ,114.551]
  ,[2017/01/12 ,115.407 ,115.416 ,113.771 ,114.69 ,"計算されたTR" ,"計算されたATR"]]
  ]
};

このような構造をもとにループ処理で計算をまわしています。JavaScriptのループ処理については詳しく解説しているサイトがたくさんありますので、調べてみてください。

ATR(Average True Range)

平均的な日々の最大変動幅をもとめます。リスク管理に大変有用です。

移動平均はEMAをしようします、EMAの計算には前日のEMAが必要なため、最初の平均値だけ単純平均としています。使用しますが

AverageTrueRange
var
 ar   = {sym:[[Date ,Open ,High ,Low ,Close]]}
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"TR" ,"ATR"]
,n  = 20
,r  = 2  
;

function TR(){
  var target = ar[sym][day];
  target[list.indexOf("TR")] = roundN(
    TR(
      target[list.indexOf("High")]
      ,target[list.indexOf("Low")]
      ,target[list.indexOf("Close")]
    )
  );
}

function ATR_(){
  var sum = 0;
  for(var i=0; i<n; i++){
  sum += ar[sym][day-i][list.indexOf("TR")];
  }

  ar[sym][day][list.indexOf("ATR")] = roundN(sum /n ,r);
}

function ATR(){
  ar[sym][day][list.indexOf("ATR")] = roundN(
    EMA(
      n
      ,ar[sym][day-1][list.indexOf("ATR")]
      ,ar[sym][day][list.indexOf("TR")]
    )
    ,r
  );
}

HL(ハイローバンド、ドンチャンチャネル)

一定期間の高値と安値。

HL
var
 ar   = {sym:[[Date ,Open ,High ,Low ,Close]]}
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"High20" ,"Low20"]
,n  = 20
;

function HL(){
  var arHigh = [] ,arLow = [];
  for(var i=0; i<n; i++){
    arHigh.push(ar[sym][day-i][list.indexOf("High")])
    arLow .push(ar[sym][day-i][list.indexOf("Low")])
  }

  ar[sym][day][list.indexOf("High20")] = Math.max.apply(null ,arHigh);
  ar[sym][day][list.indexOf("Low20")]  = Math.min.apply(null ,arLow);  
}

EMA(指数平滑移動平均)

ライブラリのEMA関数だけだと不十分なので念のため。

EMA
var
 ar   = {sym:[[Date ,Open ,High ,Low ,Close]]}
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"EMA20"]
,n  = 20
,r  = 2  
;

function SMA(){
  var sum = 0;
  for(var i=0; i<n; i++){
    sum += ar[sym][day-i][list.indexOf("Close")];
  }
  ar[sym][day][list.indexOf("EMA20")] = roundN(sum /n ,r);
}

function EMA_(){
  ar[sym][day][list.indexOf("EMA20")] = roundN(
    EMA(
      n
      ,ar[sym][day-1][list.indexOf("EMA")]
      ,ar[sym][day][list.indexOf("Close")]
    )
    ,r
  );
}

MACD

移動平均線の進化系。トレンドフォローのシグナルの中で、今のところ一番使用頻度が高いです。

MACD
var
 ar   = {sym:[[Date ,Open ,High ,Low ,Close ,EMA6 ,EMA19]]}
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"EMA6" ,"EMA19" ,"MACD6_19" ,"MACD6_19_EMA9" ,"MACD6_19_2"]
,r  = 2            
;

function MACD6_19(){
  var target = ar[sym][day];
  target[list.indexOf("MACD6_19")] = roundN(
    target[list.indexOf("EMA6")] -target[list.indexOf("EMA19")]
    ,r
  );
}

function MACD6_19_EMA9_(){
  var n = 9 ,sum = 0;
  for(var i=0; i<n; i++){
    sum += ar[sym][day-i][list.indexOf("MACD6_19")];
  }

  target[list.indexOf("MACD6_19_EMA9")] = roundN(sum /n ,r);
}

function MACD6_19_EMA9(){
  target[list.indexOf("MACD6_19_EMA9")] = roundN(
    EMA(
      9
      ,ar[sym][day-1][list.indexOf("MACD6_19_EMA9")]
      ,ar[sym][day][list.indexOf("MACD6_19")]
    )
    ,r
  );
}

function MACD6_19_2(){
  var target = ar[sym][day];
  target[list.indexOf("MACD6_19_2")] = roundN(
    target[list.indexOf("MACD6_19")] -target[list.indexOf("MACD6_19_EMA9")]
    ,r
  );
}

BB(ボリンジャーバンド)

移動平均線のさらなる進化系。これからどんどんバックテストしてみたいテクニカル分析です。

BB
var
 ar   = {sym:[[Date ,Open ,High ,Low ,Close]]}
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"SMA" ,"sigma" ,"plus1_sgm" ,"plus2_sgm" ,"minus1_sgm" ,"minus2_sgm"]
,n  = 20
,r  = 2  
;

function SMA(){
  var sum = 0;
  for(var i=0; i<n; i++){
    sum += ar[sym][day-i][list.indexOf("Close")];
  }

  ar[sym][day][list.indexOf("SMA")] = roundN(sum /n ,r);
}

function sigma(){
  var
   target = ar[sym]
  ,sumx   = 0
  ,xm
  ,sumxxm = 0
  ;

  for(var i=0; i<n; i++){
    var xxi = target[day-i][list.indexOf("Close")]
    sumx   += xxi;       
  }
  xm = sumx/n;

  for(var i=0; i<n; i++){
    var xxi = target[day-i][list.indexOf("Close")]
    sumxxm += (xx[i]-xm)^2;  
  }              
  ar[sym][day][list.indexOf("sigma")] = m.sqrt((sumxxm /n));
}

function BB(){
  var
   sma    = ar[sym][day][list.indexOf("SMA")]
  ,sigma    = ar[sym][day][list.indexOf("sigma")]
  ;

  ar[sym][day][list.indexOf("plus1_sgm")]  = sma +sigma;
  ar[sym][day][list.indexOf("plus2_sgm")]  = sma +sigma *2;
  ar[sym][day][list.indexOf("minus1_sgm")] = sma -sigma;
  ar[sym][day][list.indexOf("minus2_sgm")] = sma -sigma *2;
}

ADX

数あるテクニカル分析の中で、トレンドの強さを測ることができるものです。

ADX
var
 ar = {sym:[[Date ,Open ,High ,Low ,Close]]}
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"plus_DM" ,"minus_DM" ,"plus_DI" ,"minus_DI" ,"DX" ,"ADX"]
,n  = 14
,r  = 2            
,r_   = 2            
;

function DM(){
  var
   target   = ar[sym][day]
  ,target_  = ar[sym][day-1]
  ;

  ar[sym][day][list.indexOf("pre_plus_DM")] = roundN(
    target[list.indexOf("High")] - target_[list.indexOf("High")]
    ,r
  )
  ar[sym][day][list.indexOf("pre_minus_DM")] = roundN(
    target_[list.indexOf("Low")] - target[list.indexOf("Low")
    ,r
  )
  ar[sym][day][list.indexOf("plus_DM")] = pre_plus_DM <0 ? 0
    : pre_plus_DM==pre_minus_DM ? 0
    : pre_plus_DM <pre_minus_DM ? 0
    : pre_plus_DM
    ;
  ar[sym][day][list.indexOf("minus_DM")] = pre_minus_DM <0 ? 0
    : pre_minus_DM==pre_plus_DM ? 0
    : pre_minus_DM <pre_plus_DM ? 0
    : pre_minus_DM
    ;
}


function DI_DX(){
  var
   preDI_TR = 0
  ,pre_plus_DI  = 0
  ,pre_minus_DI = 0
  ,plus_DI
  ,minus_DI
  ,DX
  ;

  for(var i=0; i<n; i++){
    var target   =  ar[sym][day-i];
    preDI_TR     += target[list.indexOf("TR")];
    pre_plus_DI  += target[list.indexOf("plus_DM")];
    pre_minus_DI += target[list.indexOf("minus_DM")];
  }

  ar[sym][day][list.indexOf("plus_DI")] = roundN(
    pre_plus_DI  /preDI_TR *100
    ,r_
  );
  ar[sym][day][list.indexOf("minus_DI")] = roundN(
    pre_minus_DI /preDI_TR *100
    ,r_
  );
  ar[sym][day][list.indexOf("DX")] = roundN(
    Math.abs(plus_DI -minus_DI) /(plus_DI +minus_DI) *100
    ,r_
  );
}

function(){
  var preADX = 0;
  for(var i=0; i<n; i++){
    preADX += ar[sym][day-i][list.indexOf("DX")];
  }

  ar[sym][day][list.indexOf("ADX")] = roundN(preADX /n ,r_);
}
同じタグの記事
著者

タカハシ / 8年目の兼業トレーダー

元・日本料理の板前。現在は、投資やプログラミング、動画コンテンツの撮影・制作・編集などを。更新のお知らせは、各SNSやLINEで。LINEだと1対1でお話することもできます!

このブログと筆者について運用管理表

  • 記事をシェア
© Investment Tech Hack 2021.