Pineスクリプトにはビルトイン関数 rand()
が用意されてないので、自分で疑似乱数生成器を実装してみる。実装するのは、C++11の minstd_rand0
とその改良版の minstd_rand
。
minstd_rand0
は、1988年にStephen K. ParkとKeith Millerが発表[1]した乱数生成器の実装を元にしたもの。論文の中で下記のPascalコードが示されている。
function Random : real; const a = 16807; m = 2147483647; begin seed := (a * seed) mod m; Random := seed / m end;
変数 seed
は 1
から 2147483646
までの整数の中から一つを割り当てて初期化する。
これをPineスクリプトで実装すると下記のようになる。seed
は timenow
の値で初期化している。
//@version=4
study("minstd_rand0")
var seed = timenow
a = 16807
m = 2147483647
seed := (a * seed) % m
//random = seed / float(m)
plot(seed)
変数 seed
を参照すれば、C++11の minstd_rand0
のように整数の乱数を得ることができる。float
の乱数が欲しい場合は、コメントアウトした random
の値を参照すれば良い。
実装が正しいかどうかは、変数 seed
を 1
で初期化し10000番目に生成された seed
の値が 1043618065
であることを確認すれば良い。
下記のコードを使って、乱数生成器の実装の正しさを確認した。
//@version=4
study("minstd_rand0 test")
var seed = 1
if barstate.isfirst
for i = 1 to 10000
a = 16807
m = 2147483647
seed := (a * seed) % m
//random = seed / float(m)
plot(seed, color=seed == 1043618065 ? color.green : color.red)
次に改良版の minstd_rand
を実装する。これは1993年にStephen K. Park、Keith W. Miller、Paul K. Stockmeyerが発表[2]した改良版で、a = 16807
の代わりに a = 48271
を使用することを推奨したものである。
よって、Pineスクリプトの実装は単に a
の値を 48271
に変更するだけで済む。
//@version=4
study("minstd_rand")
var seed = timenow
a = 4827
m = 2147483647
seed := (a * seed) % m
//random = seed / float(m)
plot(seed)
References
- S. K. Park and K. W. Miller. 1988. Random number generators: good ones are hard to find. Commun. ACM 31, 10 (Oct. 1988), 1192–1201. DOI:https://doi.org/10.1145/63039.63042
- Diane Crawford. 1993. Technical correspondence. Commun. ACM 36, 7 (July 1993), 105. DOI:https://doi.org/10.1145/159544.376068