簡単なプログラムで株価のランダム・ウォーク理論を確かめてみる


はじめに

そもそも、僕がQiitaに投稿を始めたきっかけは、「Gushwell's C# Programming Page」というWebサイトの記事をリライトしようと思ったからです。

このサイトでは、Silverlightで作成したプログラムを多く公開していました。しかし、今となってはSilverlightもIEでしか動かないし、2021年10月でサポートも終わってしまいます。そのため、Silverlightから別のプラットフォームへ移植しなおそうと思ったのがきっかけでした。

グラフカルな動きが必要のないものは、C# + コンソールアプリで書き直し、Qiitaで公開しました。

例えば、

ミラー・ラビン素数判定法による素数判定メソッド
マチンの公式で円周率100万桁まで求めてみる
1次元セルオートマトン - ルール0からルール255まで全て試す

などなど。

でも、いくつかのプログラムは、どうしてもコンソールアプリには向かないものもあります。できればSilverlight同様、Webページでプログラムを動かしたい。

どうしようかなと、ずーっと悩んでいたのですが、僕のやりたいことは、アルゴリズムをコードで残しておきたいってことなので、まあC#である必要性はないんですよね。

C#大好き人間なので、C#で書きたいという気持ちはありますが、C#で移植するのをあきらめて、勉強を兼ねてJavaScriptに移植することにしました。

せっかくなので、できるだけ最新のJavaScriptの仕様で書こうと思います。ということで、IEは無視することにします。

その第一弾がこの記事です。能書きが長くなってしまいましたが、作成したのは、1次元ランダムウォークのプログラムです。Qiitaは、CodePenのコードを埋め込めるようなので、記事の最後で、CodePenのコードを埋め込んで動作を確認できるようにします。

1次元ランダムウォーク

wikipediaによれば、

ランダムウォーク(英語: random walk)は、次に現れる位置が確率的に無作為(ランダム)に決定される運動である。

とのことです。

ここでは、

ある時刻 t の時の値を V(t) で表した時、V(t+1)の値が、±n% の範囲で動く

と定義します。

今回作成したプログラムは、n = 5 に設定しました。

V(t+1)は、V(t)+1 あるいは V(t)-1 のいずれかとなるように値が遷移するようにするのが一般的なのかもしれませんが、株価や為替レートがランダムワークに従って動くという説もあるようなので、±1 に固定するのではなく、動く範囲を±5%にしてみました。5%という数字にはほとんど根拠はないです。

MyCanvasクラス

時間軸(t)を横軸に、変化する値(V(t))を縦軸として表し、折れ線グラフのように値をプロットしていきたいので、HTML5のcanvas APIをラップしした簡単なMyCanvasクラスを定義します。

直線を引く drawLineと、全体を塗りつぶすClearAllという2つのメソッドを定義しただけのものです。

class MyCanvas {
    constructor (id, width, height) {
        this.canvas = document.getElementById(id);
        this.ctx = this.canvas.getContext('2d');
        if (width)
            this.ctx.canvas.width = width;
        if (height)
            this.ctx.canvas.height = height;
        this.width = this.ctx.canvas.width;
        this.height =  this.ctx.canvas.height;
    }

    // 線
    drawLine(x1, y1, x2, y2, color = null, width = 1) {
        this.ctx.save();
        if (color != null)
            this.ctx.strokeStyle = color;
        this.ctx.lineWidth = width;
        this.ctx.beginPath();
        this.ctx.moveTo(x1, y1);
        this.ctx.lineTo(x2, y2);
        this.ctx.closePath();
        this.ctx.stroke();
        this.ctx.restore();
    }

    // すべてをクリア
    clearAll() {
       this.ctx.clearRect(0, 0, this.width, this.height);
    }
}

JavaScriptもclassキーワードが使えるようになったので、随分と便利になりました。

Walkerクラス

Walkerクラスは、ランダムウォークをするこのプログラムの核となるクラスです。

コンストラクタで、MyCanvasオブジェクトと値の初期値(V(0)の値)を受け取ります。

walkメソッドは、1歩進むだけのメソッド。ここで、一つ前の値から -5% から +5% までの範囲でランダムに値が上下するようにしています。このときCanvasの範囲をはみ出さないように制御しています。なお、このメソッドでは描画は行いません。

execが処理を開始するメソッド。ここで、setInterval使って、walkを繰り返し呼び出しています。そして、得られた値と一つ前の値を線で結んでいます。この描画は前述のMyCanvasクラスを使っています。

class Walker {
    constructor (canvas, initialvalue) {
        this.value = initialvalue;
        this.prevalue = initialvalue;
        this.canvas = canvas;
    }

    walk() {
        this._prevValue = this.value;
        let d = Math.floor(Math.random() * 11) - 5;
        this.value += this.value * d / 100;
        if (this.value <= 0)
            this.value = 1;
        if (this.value >= this.canvas.height)
            this.value = this.canvas.height - 1;
        return this.value;
    };

    exec() {
        let x = 0;
        let prevValue = this.value;
        this.timer = setInterval(() => {
            let p = this.walk();
            this.canvas.drawLine(x,  prevValue,  x+1, p);
            prevValue = p;
            x++;
            if (x > this.canvas.width)
                clearInterval(timer);
        }, 30);
    }

    stop() {
        clearInterval(this.timer);
        this.canvas.clearAll();
    }
}

Walkerクラスは、値変化の機能と描画の機能が蜜結合なので、そこがいまいちなところかな。
まあ、小さいプログラムなので良しとします。

mainメソッド

最後は、メイン処理を行うコードです。

var walker = null;

var main = function() {
    if (walker != null)
        walker.stop();

    let height = 400;
    let width = 600;
    let canvas = new MyCanvas('mycanvas', width, height);
    walker = new Walker(canvas, height / 2);
    walker.exec();
};

window.onload = function() {
    let btn =  document.getElementById('startButton');
    btn.onclick = main;
};

今回は、これらのコードをすべて、"randomwalk1d.js" ファイルにまとめています。
もうすこし大きなプログラムになったら、export、importを使った方がよいですかね。

HTML

HTMLファイルは、必要最低限のことだけを記述しています。CSSはインラインで埋め込んでいます。

<!DOCTYPE html >
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>random walk</title>
    <style>
      #mycanvas {
        background-color: beige;
      }
    </style>
</head>
<body>
  <canvas id="mycanvas" width="600" height="400"></canvas>
  <div>
    <button id="startButton">Start</button>  
  </div>
  <script src="randomwalk1d.js"></script>
</body>
</html>

実行例

以下、実行時のスクリーンショットです。

「ある会社の株価の推移です」と言われても頷いてしまいそうです。下降トレンド、もみ合い、上昇トレンドの3つが見られます。実に不思議です。

CodePenのコードを埋め込んでみる

上記コードをCodePenで書いて、埋め込んでみました。

[start]ボタンを押すと描画が始まります。

See the Pen randomwalk1d by Gushwell (@gushwell) on CodePen.