JavaScript、google apps scriptでテクニカル分析を計算する

JavaScript、google apps scriptでテクニカル分析を計算する
前回、相関係数のプログラムを公開してみましたが、今回は、JavaScriptやgoogle apps scriptをつかって基本的なテクニカル分析を計算させてみます。JavaScriptとgoogle apps scriptの記述は一緒です(ほぼ)。
2017年1月15日追記
解説:配列の構造についてを追記しました。
2017年9月26日追記
配列の構造とコードの解説を変更しました。

JavaScript、google apps script でテクニカル分析を計算する

  1. 基本のプログラムと配列の構造
    1. 小数点の桁数を指定して四捨五入する
    2. TR(True Range)
    3. EMA(指数平滑移動平均)
    4. 配列の構造
  2. ATR(Average True Range)
  3. HL(ハイローバンド、ドンチャンチャネル)
  4. EMA(指数平滑移動平均)
  5. MACD
  6. BB(ボリンジャーバンド)
  7. ADX

1.基本のプログラム

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

* ごく基本的なものしかライブラリ化していません。ライブラリ化すると配列を渡さないといけないので。
ループで配列つくる→ ライブラリにわたす→ そのなかでループ処理→ 効率悪い
ループで配列作りつつ計算→ 効率良い

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

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

roundN

function roundN(v ,n){ // xxxx.xxxxxx 少数第 n 位以下を四捨五入
  var a=1 ,i;
  for(i=0; i<n; i++){
    a += "0"; // n=2→100  n=3→1000
  }
  return Math.round(v *a) /a;
}

目次へ

1-2.TR(True Range)

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

True Range

function TR(high,low,last){ // last は前日終値
  var m = Math;
  return m.max(m.abs(high -low) ,m.abs(high -last) ,m.abs(low -last));
}

目次へ

1-3.EMA(指数平滑移動平均)

Exponential Moving Average

function EMA(N,EMAy,P){ //N 何日平均  EMAy 前日のEMA  P その日の価格
  return (EMAy *(N -1) +P *2) /(N +1);
}

目次へ

1-4.配列の構造

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

以下で解説します。

配列の構造

// 以下はATRを例としています。

// listは「items」の構造を表しています。
// 計算する指標によって項目は違います。
  
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]
  ]
};

// 計算が完了すると、配列のデータが下記のような「list」に準じた形になるイメージです。

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のループ処理については詳しく解説しているサイトがたくさんありますので、調べてみてください。

目次へ

2.ATR(Average True Range)

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

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

Average True Range

var
 ar   = {sym:[[Date ,Open ,High ,Low ,Close]]} // ※ここにデータを入れます(詳細はコチラ)
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"TR" ,"ATR"] // itemsのリストを用意しておく
,n  = 20 // ATRの計算期間
,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")]
    )
  );
}


// 最初のATR
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);
}


// 2つ目以降
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
  );
}

目次へ

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

一定期間の高値と安値。

HL

var
 ar   = {sym:[[Date ,Open ,High ,Low ,Close]]} // ※ここにデータを入れます(詳細はコチラ)
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"High20" ,"Low20"] // itemsのリストを用意しておく
,n  = 20 // HLの計算期間
;


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);  // 最安値
}

目次へ

4.EMA(指数平滑移動平均)

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

EMA

var
 ar   = {sym:[[Date ,Open ,High ,Low ,Close]]} // ※ここにデータを入れます(詳細はコチラ)
,list = ["Date" ,"Open" ,"High" ,"Low" ,"Close" ,"EMA20"] // itemsのリストを用意しておく
,n  = 20 // EMAの計算期間
,r  = 2  // 小数の桁数
;


// 最初のEMA(単純移動平均)
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);
}


// 2つ目以降
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
  );
}

目次へ

5.MACD

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

MACD


// ※すでに計算されたEMAがある前提

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"] // itemsのリストを用意しておく
,r  = 2            // 小数の桁数
;


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


// 最初のEMA9
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);
}


// 2つ目以降
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
  );
}


// MACD2
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
  );
}

目次へ

6.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"] // itemsのリストを用意しておく
,n  = 20
,r  = 2  // 小数の桁数
;


// BBはSMAを使用する
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);
}


// sigma(標準偏差)を算出
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;       //xxの総和
  }
  xm = sumx/n; //xxの平均
  
  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));
}


// 各BBの値をもとめる
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;
}

目次へ

7.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"] // itemsのリストを用意しておく
,n  = 14
,r  = 2            // 小数の桁数(銘柄毎)
,r_   = 2            // 小数の桁数(割合)
;


// DMを計算
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
    ;
}


// DIとDXを計算
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_
  );
}


// ADXを計算
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_);
}

目次へ

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のアップグレード行う、もしくはその他のブラウザを使用しての閲覧をお願いします。