phpで移動平均(SMA,EMA)、ボリンジャーバンドを計算する

システム部のNです。

前回のブログでは、無料で使えるCryptowatch APIのOHLCデータをphpで取得する方法まで書きました。

今回はその続きで、OHLCデータを使って分析する手法のphpを書きたいと思います。

phpのライブラリにtrader 関数というライブラリがあり、もしもこのライブラリが組み込まれたphpであれば、その関数を使うだけでOKですが、通常のレンタルサーバのphpにはtrader 関数は組み込まれてないと思われます。
(詳細に調べたわけではないです。カゴヤやさくらサーバには無かったです。)

相場の分析では移動平均というものをよく用います。

引用
「株価や気温など時間で細かく変化するデータを眺めるとき、変動が細かすぎて全体の傾向を掴みにくい場合があります。
そのようなときには「移動平均」を用いることで、変化をより滑らかにしてデータを俯瞰できます。
・・・
最も簡単な移動平均は、直近データの単純相加平均を計算することによって求められます。」

最も簡単な移動平均をSimple Moving Average (SMA)と呼びます。

これをphpプログラムで計算する為にまず、配列にデータを入れて普通に平均値を求めるロジックをおさらいすると、

$aData[] = 12;
$aData[] = 1;
$aData[] = 100;
$aData[] = 13;

// 平均値
$Average = array_sum($aData)/count($aArrayData);

このようになります。

移動平均は過去のさかのぼる期間を定めて、その期間の平均を全期間で求めていくだけとなります。

もしもtrader 関数が使えるであればのならこれ 、trader_sma という関数を呼ぶだけですが、https://www.php.net/manual/ja/function.trader-sma.phpない場合は自分で作ります。

trait traitTrader // traitという色々なクラスで useで取り込める部品として作る
{
  // 単純"移動"平均 Simple Moving Average
  public function SMA($position, $period, $aPrice)
  {
    $result = 0;
    if($position>=$period-1 && $period>0) {
      for($i=0; $i<$period;$i++) {
        $result+=$aPrice[$position-$i];
      }
      $result/=$period;
    }
    return $result;
  }

  // 上記関数では、指定した $position のところの移動平均値が計算される
  // これを全期間分やりたい場合
  // 下記のように  $period:移動平均を計算する期間 $aPrice:価格が入った配列
  // を渡して、$aSMA 配列を作成する
  public function getSmaArray($period, $aPrice)
  {
    $aSMA = array();
    foreach($aPrice as $position=>$price) {
      $aSMA[$position] = $this->SMA($position, $period, $aPrice);
    }
    return $aSMA;
  }
}

単純移動平均よりも、おとといと昨日では昨日のデータのほうがより重要度が高いとみなして、現在から近いデータほど重みを増すという考えで計算したデータのほうがより今後の動きの予測として有効ではないかという考えで、直前のデータに重みを増す移動平均の計算方法もいくつかあります。

https://ja.wikipedia.org/wiki/%E7%A7%BB%E5%8B%95%E5%B9%B3%E5%9D%87

指数関数的に重みを減少させる指数移動平均
Exponential Moving Average

もしもtrader 関数が使えるのならこれ
trader_ema

https://www.php.net/manual/ja/function.trader-ema.php
無いなら自分で作る。

ちなみに関数を自分で作るとえらそうなことを書いてますが、Windows版のMT4をインストールするとMQ4という自動トレード用の言語が使えて、その中に相場分析の色々な計算方法のサンプルソースがあるので、それを見てMQ4言語の文法をphp言語の文法に変換するという方法もありますw

 // これも trait traitTraderの中に作る


  // double ExponentialMA(const int position,const int period,const double prev_
  // value,const double &price[])
  // ↑ MQ4の中のサンプルソースの関数定義
  // ↓ それを基に作ったphp関数
  public function EMA($position, $period, $prev_value, $aPrice)
  {
    $result = 0;
    if($period>0) {
      $pr = 2 / ( $period + 1 );
      $result = $aPrice[ $position ]*$pr + $prev_value*(1-$pr);
    }
    return $result;
  }


  // 上記関数では、指定した $position のところの移動平均値が計算される
  // これを全期間分やりたい場合
  // 下記のように  $period:移動平均を計算する期間 $aPrice:価格が入った配列
  // を渡して、$aEMA 配列を作成する
  public function getEmaArray($period, $aPrice)
  {
    $aEma = array();
    $prev_value = $this->SMA(0, $period, $aPrice);
    foreach($aPrice as $position=>$price) {
      if($position<$period) {
        $ema = $this->SMA($position, $period, $aPrice);
      } else {
        $ema = $this->EMA($position, $period, $prev_value, $aPrice);
      }
      $aEma[$position] = $ema;
      $prev_value = $ema;
    }
    return $aEma;
  }

移動平均と現在の価格がどれくらい離れているか?

離れすぎていたら危険ではないか?

短期間と長期間の移動平均値がクロスしたらシグナルとして、みんなが売買するのでエントリーするなどなど色々な使い方ができます。

もうひとつ、私が重要と勝手に思っている指標としてボリンジャーバンドというものがあります。

これは移動平均で算出した値から統計の標準正規分布の±3σ標準偏差内99.73%、あるいは±2σ標準偏差内95.45%のなかに価格が収まるかもしれないという考え方の使い方をしますが、実際には価格の変動というのは、標準正規分布にあてはまる性質のものではないらしいです。

ただ現在価格の上下に帯の線が引けるため上がりすぎ、下がりすぎなのでは?という推測をするのに使えますが過信は非常に危険です。

バンドウォークというバンドをブレイクして上がり続ける問うような動きもあります。

ボリンジャーバンドを求めるには、単純移動平均の標準偏差を求めます。

期間は21で大体求めますし、みんなが見てるのは$period 21のボリンジャーバンドです。

 // これも trait traitTraderの中に作る

  // 標準偏差を求める関数
  public function StdDev_Func($position, $aPrice, $aMAprice, $period)
  {
    $StdDev_dTmp = 0;
    if($position>=$period) {
      for($i=0; $i<$period; $i++) {
         $StdDev_dTmp += pow($aPrice[$position-$i]-$aMAprice[$position],2); 
         // 分散を計算 (平均と価格の差の2乗)
      }
      $StdDev_dTmp = sqrt($StdDev_dTmp/$period); 
      // 分散のスクエアルート(平方根)が標準偏差
    }
    return $StdDev_dTmp;
  }

// --------------------------
    // ボリンジャーバンドを計算するには
    // traitTraderをuseしているクラスの中で下記のように求める

    // 単純移動平均をまず求めて
    $aSMA = $this->getSmaArray($period, $aPrice);

    // $aPrice[0] = 100万円;
    // $aPrice[1] =  90万円; // のように価格が入っている配列
    foreach($aPrice as $i=>$price) {

      // 単純移動平均の標準偏差を計算する
      $StdDev = $this->StdDev_Func($i, $aPrice, $aSMA, $period);

      $DT['+3σ'][$i] = $aSMA[$i]+3*$StdDev; // 標準偏差σ の3倍を平均に加える
                       // 99.73%区間の上限
      $DT['-3σ'][$i] = $aSMA[$i]-3*$StdDev; // 標準偏差σ の3倍を平均から引く
                       // 99.73%区間の下限
      $DT['+2σ'][$i] = $aSMA[$i]+2*$StdDev; // 標準偏差σ の2倍を平均に加える
                       // 95.45%区間の上限
      $DT['-2σ'][$i] = $aSMA[$i]-2*$StdDev; // 標準偏差σ の2倍を平均から引く
                       // 95.45%区間の下限
    }

スタッフブログ最新記事

月別 アーカイブ

2019年

2018年

2017年

2016年

2015年

2014年

2013年

2012年

2011年

2010年

2009年

2008年

2007年

ご応募はお電話でも受け付けています
教育官ブログ
\風俗業界時評/シン・コラム
英語スタッフブログ!