1
0

Python 3ではじめるシステムトレード:疑似乱数の生成

Last updated at Posted at 2024-03-03

モンテカルロシミュレーションをするために、必要となる乱数生成器について知識をまとめてみました。情報は主にWikiとNumPyのWebサイトから得ています。ほとんどがChatGPTによる英語文書の翻訳です。参考文献の番号は元情報のページを参照してください。ウィキの疑似乱数生成アルゴリズムのページは一部原文を削り、一部加筆しました。またPCG64とSFC64の情報に関してはNumPyのリファレンスを参照しました。

擬似乱数生成アルゴリズム

ウィキペディア、フリー百科事典より

このページは、擬似乱数生成アルゴリズムが一般的に遭遇する特性についてです。理論計算機科学における形式的な概念については、擬似乱数生成器を参照してください。

擬似乱数生成器(PRNG)、または決定論的ランダムビット生成器(DRBG)[1]は、乱数の系列の特性を近似する特性を持つ数の系列を生成するためのアルゴリズムです。PRNGによって生成された系列は真にランダムではありません。なぜなら、それは初期値、いわゆるPRNGのシード(真にランダムな値を含むことがある)によって完全に決定されるからです。ハードウェア乱数生成器を使用してより真に近いランダムな系列を生成することができますが、実際に擬似乱数生成器も、数の生成の速度と再現性により、重要です[2]。

PRNGは、シミュレーション、電子ゲーム、暗号学などのアプリケーションで中心的な役割を果たします。暗号学的アプリケーションでは、以前の出力から予測できない出力が必要であり、より複雑なアルゴリズムが必要です。これらのアルゴリズムは、より単純なPRNGの線形性を引き継がないものです。

良好な統計的特性は、PRNGの出力にとって中心的な要件です。一般に、PRNGが意図された用途に十分にランダムに近い数を生成していると確信を持つためには、慎重な数学的分析が必要です。

潜在的な問題

実際には、多くの一般的なPRNGからの出力には、それらが統計的なパターン検出テストに失敗する原因となるアーティファクトが現れます。これには以下が含まれます:

一部のシード状態の期待よりも短い周期(この文脈では、そのようなシード状態は「弱い」と呼ばれます);

大量の数値生成の後の分布の一様性の欠如;

連続する値の相関;

出力系列の貧弱な次元分布;

特定の値が発生する距離がランダム系列分布と異なる方法で分布しています。
欠陥のあるPRNGによって示される欠陥は、気付かれない(そして知られていない)ものから非常に明白なものまで様々です。例としては、何十年もメインフレームコンピュータで使用されたRANDU乱数アルゴリズムがあります。それは深刻な欠陥がありましたが、非常に長い間、その不十分さは検出されませんでした。

多くの分野では、21世紀以前の研究作業でランダム選択やモンテカルロシミュレーションに依存していたり、他の方法でPRNGに依存していたりするものは、質の悪いPRNGを使用した結果として、理想的なものよりもはるかに信頼性が低いです[4]。

主要な問題を避けつつ比較的迅速に実行されるよく知られたPRNGの1つは、1998年に公開されたメルセンヌツイスター(以下で説明)です。この時期には、計算および統計的パフォーマンスの両方の点でより高品質のPRNGが開発されています。これらは擬似乱数生成器のリストで特定することができます。

線形再帰に基づくジェネレーター

20世紀後半には、PRNGに使用される標準的なアルゴリズムクラスには線形合同生成器(LCG)が含まれていました。LCGの品質は不十分であることが知られていましたが、より良い方法は利用できませんでした。

擬似乱数生成器の構築における主要な進歩は、2要素フィールド上の線形再帰に基づく技術の導入でした。そのようなジェネレーターは、線形帰還シフトレジスタ(LFSR)に関連しています。

特に1997年のメルセンヌツイスターの発明[9]は、以前のジェネレーターの多くの問題を回避しました。メルセンヌツイスターは$2^{19937}−1$回の反復の周期を持ち、(32ビット値に対して)最大623次元で等分布であることが証明されており、その導入時には他の統計的に合理的なジェネレーターよりも速く実行されていました。メルセンヌツイスターは線形再帰擬似乱数生成器(Linear Feedback Shift Register, LFSR)の一種ではないものの、線形再帰アルゴリズムに基づいています。これはビットシフトと排他的論理和(XOR)操作に基づくもので、従来のLFSRとは異なる方法です。

2003年には、George Marsagliaがxorshiftジェネレーターのファミリーを導入しました[10]。これもまた線形再帰に基づいています。そのようなジェネレーターは非常に高速であり、非線形操作と組み合わせることで、厳格な統計的テストに合格します[11][12][13]。

2006年には、WELLファミリーのジェネレーターが開発されました[14]。WELLジェネレーターは、状態空間が大きすぎて状態空間のゼロが多い場合の回復が非常に遅いというメルセンヌツイスターの品質をある意味で改善します。

暗号学的PRNG

主要記事:暗号学的に安全な擬似乱数生成器

暗号学的アプリケーションに適したPRNGは、暗号学的に安全なPRNG(CSPRNG)と呼ばれます。CSPRNGの要件は、シードを知らない敵が、ジェネレーターの出力系列とランダム系列とを区別することにおいて、ほとんど利点を持たないことです。言い換えると、PRNGは特定の統計テストに合格するだけで十分ですが、CSPRNGは、シードのサイズに対して多項式時間に制限されたすべての統計テストに合格する必要があります。この性質の証明は、計算複雑性理論の現在の芸術状態を超えていますが、整数因数分解など、困難であると想定される問題からCSPRNGを還元することによって、強力な証拠が提供されるかもしれません[15]。一般に、アルゴリズムがCSPRNGとして認定されるまでには、数年のレビューが必要かもしれません。

CSPRNGのクラスには次のものが含まれます:

ストリーム暗号

ブロック暗号: カウンター[16]または出力フィードバックモードで動作するもの

暗号学的に安全であるように特別に設計されたPRNG: Microsoftの暗号アプリケーションプログラミングインターフェース関数CryptGenRandom、Yarrowアルゴリズム(Mac OS XとFreeBSDに組み込まれている)、およびFortunaなど

組み合わせPRNG: 検出可能な非ランダム性を取り除くことを目的として、いくつかのPRNGプリミティブアルゴリズムを組み合わせようとするもの

数学的困難性の仮定に基づく特別な設計:例には、Micali–Schnorrジェネレーター[17]、Naor-Reingold擬似ランダム関数、およびBlum Blum Shubアルゴリズムがあり、強力なセキュリティ証明を提供します(そのようなアルゴリズムは、従来の構造に比べてかなり遅く、多くのアプリケーションには実用的ではありません)

ジェネリックPRNG:任意の一方向関数から(暗号学的に)安全なPRNGを一般的に構築できることが示されていますが[18]、このジェネリック構築は実際には非常に遅いので、主に理論面に関心があります。

NSAがNIST認定の擬似乱数生成器Dual_EC_DRBGに非対称のバックドアを挿入した可能性が高いことが示されています[19]。

ほとんどのPRNGアルゴリズムは、いくつかのテストで一様に分布する系列を生成します。高品質のPRNGの出力と真にランダムな系列を区別する方法があるかどうかは、暗号学の理論と実践の中心的な問題です。この設定では、識別者は、既知のPRNGアルゴリズムが使用された(ただし、それが初期化された状態はわかりません)か、真にランダムなアルゴリズムが使用されたかのいずれかであり、2つを区別する必要があります[20]。PRNGを使用する暗号アルゴリズムとプロトコルのほとんどのセキュリティは、適切なPRNGの使用と真にランダムな系列の使用を区別することが実現不可能であるという仮定に基づいています。この依存関係の最も単純な例は、ストリーム暗号であり、(最も頻繁に)メッセージのプレーンテキストをPRNGの出力と排他的論理和をとることにより、暗号文を生成します。暗号学的に適切なPRNGの設計は非常に困難であり、追加の基準を満たす必要があります。その周期のサイズは、PRNGの暗号学的適合性において重要な要因ですが、唯一の要因ではありません。

BSI評価基準

ドイツ連邦情報セキュリティ局(ドイツ語:Bundesamt für Sicherheit in der Informationstechnik、BSI)は、決定論的乱数生成器の品質に対する4つの基準を確立しました[21]。ここに要約します:

K1 - 生成された乱数の系列が互いに異なる確率が高い必要があります。

K2 - 数の系列は、指定された統計テストに従って「真にランダム」な数と区別がつかないものであるべきです。テストには、モノビットテスト(系列中の1と0の数が等しい)、ポーカーテスト(カイ二乗テストの特別なインスタンス)、ランズテスト(様々な長さのランの頻度を数える)、ロングランズテスト(20 000ビットの系列に長さ34以上のランが存在するかどうかをチェック)—BSI[21]とNIST[22]の両方から、および自己相関テストが含まれます。本質的に、これらの要件は、ビット系列がどれだけよく:ゼロとワンが同じくらい頻繁に現れるか; $n$個のゼロ(またはワン)の系列の後に、次のビットがワン(またはゼロ)である確率が半分であるか; および任意の選択された部分系列が、系列の次の要素についての情報を含まないかどうかをテストします。

K3 - 攻撃者が、与えられた部分系列から、系列の以前または将来の値、またはジェネレーターの内部状態を計算したり、それ以外の方法で推測することは(実用上)不可能でなければなりません。

K4 - 攻撃者が、ジェネレーターの内部状態から、系列の以前の数や以前の内部ジェネレーター状態を計算したり、推測することは(実用上)不可能であるべきです。
暗号学的アプリケーションでは、K3またはK4基準を満たすジェネレーターのみが受け入れられます。

数学的定義

所与:

$ P$ - 確率分布は
$ \left(\mathbb {R,\mathfrak {B}}\right)$上にあります
(ここで、$ \mathfrak {B}$は実数直線上の標準ボレル集合です)

$ \mathfrak {F}$ - ボレル集合の空でないコレクション
$ \mathfrak {F}\subseteq {\mathfrak {B}}$、例えば
$ \mathfrak {F}= (-\infty ,t ]:t \in \mathbb {R}$。もし
$ \mathfrak {F}$が指定されていない場合、それは
$ \mathfrak {B}$または
$ (-\infty ,t ]:t \in \mathbb {R}$のどちらかで、文脈に依存します。

$ A\subseteq \mathbb {R}$– 空でない集合(必ずしもボレル集合である必要はありません)。しばしば
$ A$は
$ P$のサポートとその内部の間の集合です。例えば、もし
$ P$が区間
$ \left(0,1\right)$上の一様分布である場合、
$ A$は
$ \left(0,1\right)$かもしれません。もし
$ A$が指定されていない場合、それは文脈に依存して、$ P$のサポートに含まれ、その内部を含むいくつかの集合と仮定されます。

関数
$ f:\mathbb {N_{1}} \rightarrow \mathbb{R}$(ここで、$\mathbb {N_{1}}=(1,2,3,\dots ))$
は正の整数の集合です)が
$ P$のための擬似乱数生成器と呼ばれるのは、
$ {\mathfrak {F}}$を与え、
$ A$の値を取る場合に限ります:

$ f\left(\mathbb{N_{1}}\right)\subseteq A$

\forall E\in {\mathfrak {F}}\quad \forall \varepsilon >0 \quad \exists N \in \mathbb {N_{1}} \quad \forall n \geq N,\quad \left|{\frac {\# \left\{  i\in \left\{1,2,\dots ,n\right\}:f(i)\in E\right\}}{n}}-P(E)\right|<\varepsilon

(#$S$ は有限集合 $ S$ の要素の数を示します。)

もし
$ f$が区間
$ \left(0,1\right)$上の一様分布のための擬似乱数生成器であり、そしてもし
$ F$がある与えられた確率分布
$ P$のCDFであるならば、

F^{*}\circ fは

$ P$のための擬似乱数生成器です、ここで

F^{*}:\left(0,1\right)\rightarrow \mathbb{R}

は$P$のパーセンタイルです、すなわち

F^{*}(x):=\inf \left\{t\in \mathbb{R}:x\leq F(t)\right\}。

直感的には、標準一様分布のシミュレーションから任意の分布をシミュレートすることができます。

初期のアプローチ

1946年にジョン・フォン・ノイマンが提案した初期のコンピュータベースのPRNGは、平方採中法として知られています。このアルゴリズムは次の通りです:任意の数を取り、それを二乗し、結果の数の中央の数字を「ランダム数」として取り除き、その数を次の繰り返しのためのシードとして使用します。例えば、数「1111」を二乗すると「1234321」になり、これは「01234321」として書くことができ、4桁の数の二乗としては8桁の数になります。これにより「2343」が「ランダム」数として得られます。この手続きを繰り返すと、次の結果として「4896」が得られ、以降も同様です。フォン・ノイマンは10桁の数を使用しましたが、プロセスは同じでした。

平方採中法は、より複雑なジェネレーターによって置き換えられています。

最近の革新は、平方採中をワイル系列と組み合わせることです。この方法は、長い期間にわたって高品質の出力を生み出します。

ジェネレーター 発表 NumPy
平方採中(Middle-square method) 1946
線形合同生成器(Linear congruential generator,LCG) 1958
線形帰還シフトレジスタ(Linear-feedback shift register,LFSR) 1965
メルセンヌツイスター(Mersenne Twister,MT) 1998 Yes
Xorshift 2003
WELL 2006
Philox 2011 Yes
Permuted Congruential Generator(PCG) 2014 Yes
Xoroshiro128+ 2018
Small Fast Chaotic(SFC) 2019 Yes

非一様ジェネレーター

主要記事:擬似乱数サンプリング

非一様確率分布から選択された数値は、一様分布PRNGと、2つの分布を関連付ける関数を使用して生成することができます。

まず、目標分布$f(b)$の累積分布関数$F(b)$が必要です:

$$F(b)=\int _{-\infty }^{b}f(b'),db'$$
ここで、$0=F(-\infty )\leq F(b)\leq F(\infty )=1$です。一様分布からのランダムな数値cを「通過する」確率密度として使用すると、

$$F(b)=c$$

となるため、

$$b=F^{-1}(c)$$

は分布$f(b)$からランダムに選択された数値です。これは逆関数法に基づいています。

例えば、累積ガウス分布の逆関数
$\operatorname {erf} ^{-1}(x)$に理想的な一様PRNGを入力$x$(範囲は(0, 1))として使用すると、ガウス分布を持つ(正のみの)値の系列を生成します。しかし、

実際の数値表現を使用する場合、分布の無限の「裾」は有限の値に切り捨てる必要があります。

$\operatorname {erf} ^{-1}(x)$の繰り返し再計算は、ジグラットアルゴリズムなどの手段を使用して、生成を高速化するために減らすべきです。

レイリー分布やポアソン分布など、他の非一様分布を生成する場合にも同様の考慮事項が適用されます。

線形合同生成器(LCG)

線形合同生成器(LCG)は、不連続な分割線形方程式で計算された擬似ランダム化された数値の系列を生成するアルゴリズムです。この方法は、最も古く、最もよく知られている擬似乱数生成アルゴリズムの一つです。その背後にある理論は比較的理解しやすく、実装が容易で、特にストレージビットの切り捨てによるモジュラー算術を提供できるコンピュータハードウェア上では高速です。

生成器は再帰関係によって定義されます:
$X_{n+1}=\left(aX_{n}+c\right){\bmod {m}}$
ここで
$X$は擬似ランダム値の系列であり、
$m,,0<m$ — 「法(modulus)」
$a,,0<a<m$ — 「乗数(multiplier)」
$c,,0\leq c<m$ — 「増分(increment)」
$X_{0},,0\leq X_{0}<m$ — 「種(seed)」または「開始値(start value)」
は生成器を指定する整数定数です。もしc = 0であれば、この生成器はしばしば乗法合同生成器(MCG)、またはLehmer RNGと呼ばれます。c ≠ 0の場合、この方法は混合合同生成器と呼ばれます。

c ≠ 0の場合、数学者はこの再帰をアフィン変換と呼びますが、コンピュータ科学では誤って線形と呼ばれることが確立しています。

歴史

Lehmer生成器は1951年に公開され、線形合同生成器は1958年にW. E. ThomsonとA. Rotenbergによって公開されました。

線形帰還シフトレジスタ(LFSR)

コンピューティングにおいて、線形フィードバックシフトレジスタ(LFSR)は、その前の状態の線形関数である入力ビットを持つシフトレジスタです。

単一ビットの線形関数として最も一般的に使用されるのは排他的論理和(XOR)です。したがって、LFSRは最も頻繁に、シフトレジスタの全体的な値のいくつかのビットのXORによって駆動される入力ビットを持つシフトレジスタです。

LFSRの初期値はシードと呼ばれ、レジスタの操作が決定論的であるため、レジスタによって生成される値の流れは、その現在(または前の)状態によって完全に決定されます。同様に、レジスタには有限数の可能な状態があるため、最終的には繰り返しのサイクルに入る必要があります。しかし、よく選択されたフィードバック関数を持つLFSRは、ランダムに見えるビットの系列を生成し、非常に長いサイクルを持つことができます。

LFSRの応用には、擬似乱数の生成、擬似ノイズシーケンス、高速デジタルカウンター、およびホワイトニングシーケンスの生成が含まれます。LFSRのハードウェアおよびソフトウェアの実装は一般的です。

送信エラーに対するクイックチェックを提供するために使用される巡回冗長検査(CRC)の数学は、LFSRのそれと密接に関連しています。一般的に、LFSRの背後にある算術は、研究や実装の対象として非常にエレガントです。単純な構成要素で比較的複雑なロジックを生成することができます。しかし、同じくらいエレガントではないかもしれないが、より良いパフォーマンスを提供する他の方法も考慮されるべきです。

NymPy ビットジェネレーター

Generatorによって生成されるランダムな値は、BitGeneratorに起源を持ちます。BitGeneratorは直接ランダム数を提供せず、シードの設定、状態の取得や設定、状態のジャンプや進行、およびnumbaなどのコードによって効率的にアクセスできる関数を提供するための低レベルラッパーへのアクセス用のメソッドのみを含みます。

サポートされているビットジェネレーター:

PCG-64 - デフォルトです。任意の量で進めることができる高速なジェネレーターです。advanceについてのドキュメントを参照してください。PCG-64は周期を持ちます。このクラスのPRNGについての詳細は、PCGの作者のページを参照してください。PCG64は、線形合同生成器(LCG)に基づいていますが、その出力を「置換」(permute)することによって得られる出力列を改善します。

PCG-64 DXSM - 並列コンテキストでの統計的特性が向上したPCG-64のアップグレードバージョンです。これらの改善についての詳細は、PCG64をPCG64DXSMでアップグレードするを参照してください。

MT19937 - 標準的なPythonビットジェネレーターです。状態があたかも$2^{128}$ 回の抽選が行われたかのような新しいジェネレーターを返すMT19937.jumped関数を追加します。メルセンヌツイスターは線形再帰擬似乱数生成器(Linear Feedback Shift Register, LFSR)の一種ではないものの、線形再帰アルゴリズムに基づいています。これはビットシフトと排他的論理和(XOR)操作に基づくもので、従来のLFSRとは異なる方法です。

Philox - 任意の数のステップを進めることができるか、独立したストリームを生成することができるカウンターベースのジェネレーターです。このクラスのビットジェネレーターについての詳細は、Random123ページを参照してください。

SFC64 - ランダムな可逆マッピングに基づく高速なジェネレーターです。通常、4つの中で最も高速なジェネレーターです。(少し)詳細については、SFCの作者のページを参照してください。これはカオス理論に基づくランダム性を利用したアルゴリズムです。

PCG64

PCG-64は、O'Neillの置換合同生成器の128ビット実装です([1]、[2])。PCG-64は周期を持ち、任意の数のステップを進めることができるだけでなく、ストリームもサポートしています。私たちが使用しているPCGファミリーの具体的なメンバーは、論文([2])で説明されているPCG XSL RR 128/64です。

PCG64は、倍精度浮動小数点数、符号なし32ビット整数、および64ビット整数を生成する関数ポインターを含むカプセルを提供します。これらはPythonで直接使用することはできず、低レベルアクセスをサポートするGeneratorや類似のオブジェクトによって使用される必要があります。

任意の数のステップを進めるadvanceメソッドをサポートしています。PCG-64 RNGの状態は、2つの128ビット符号なし整数によって表されます。

状態とシード

PCG64の状態ベクトルは、2つの符号なし128ビット値で構成され、外部的にはPythonの整数として表されます。1つはPRNGの状態であり、線形合同生成器(LCG)によって進められます。もう1つはLCGで使用される固定の奇数の増分です。

入力シードはSeedSequenceによって処理され、両方の値を生成します。増分は独立して設定することはできません。

並列機能

並列アプリケーションでBitGeneratorを使用する推奨の方法は、SeedSequence.spawnメソッドを使用してエントロピー値を取得し、これらを使用して新しいBitGeneratorを生成することです。

from numpy.random import Generator, PCG64, SeedSequence
sg = SeedSequence(1234)
rg = [Generator(PCG64(s)) for s in sg.spawn(10)]

互換性保証

PCG64は、固定されたシードが常に同じランダム整数ストリームを生成することを保証します。

SFC64

SFC64は、Chris Doty-HumphreyのSmall Fast Chaotic PRNGの256ビット実装です([1])。SFC64には、シードに依存して、異なるいくつかのサイクルが存在し、期待される周期は約$2^{255}$
([2])です。SFC64は64ビットカウンターを組み込んでおり、これは絶対最小サイクル長が$2^{64}$
であり、異なるシードが少なくとも$2^{64}$の反復で互いに衝突しないことを意味します。

SFC64は、倍精度浮動小数点数、符号なし32ビット整数、および64ビット整数を生成する関数ポインターを含むカプセルを提供します。これらはPythonで直接使用することはできず、低レベルアクセスをサポートするGeneratorや類似のオブジェクトによって使用される必要があります。

状態とシード

SFC64の状態ベクトルは、4つの符号なし64ビット値で構成されます。最後の値は、各反復で1ずつ増加する64ビットカウンターです。

入力シードはSeedSequenceによって処理され、最初の3つの値を生成します。その後、SFC64アルゴリズムは少数の回数反復されて混合されます。

互換性保証

SFC64は、固定されたシードが常に同じランダム整数ストリームを生成することを保証します。

[1]“PractRand”

[2]“Random Invertible Mapping Statistics”

パフォーマンスと推奨

推奨事項

一般的な使用に推奨されるジェネレーターはPCG64、または並列処理が重い場合にはそのアップグレードバージョンのPCG64DXSMです。これらは統計的に高品質で、全機能を備えており、ほとんどのプラットフォームで高速ですが、32ビットプロセスでコンパイルされた場合はやや遅くなります。重い並列処理を行う場合にPCG64DXSMを使用するタイミングの詳細については、PCG64をPCG64DXSMでアップグレードするを参照してください。

Philoxはかなり遅いですが、統計的特性は非常に高品質で、ユニークなキーを使用することで確実に独立したストリームを取得するのが簡単です。並列ストリームにそのスタイルを使用したい場合、またはそのスタイルを使用する別のシステムから移植している場合は、Philoxが適しています。

SFC64は統計的に高品質で非常に高速です。しかし、ジャンプ機能に欠けています。その機能を使用していない場合で、32ビットプロセスでも高速さを求めるなら、これが適しています。

MT19937はいくつかの統計テストに失敗し、現代のPRNGに比べて特に高速ではありません。これらの理由から、古い結果を再現するためのレガシーRandomStateを通じてのみ使用する場合を除き、独自に使用することはお勧めしません。ただし、多くのシステムのデフォルトとして非常に長い歴史を持っています。

64-bit Windows

64ビットLinuxと64ビットWindowsにおける相対的なパフォーマンスは、Philoxジェネレーターの顕著な例外を除いて、おおむね似ています。

Distribution  MT19937 PCG64 PCG64DXSM Philox SFC64
32-bit Unsigned Ints 100 155 131 29 150
64-bit Unsigned Ints 100 157 143 25 154
Uniforms 100 151 144 24 155
Normals 100 129 128 37 150
Exponentials 100 150 145 28 159
Overall 100 148 138 28 154
from numpy.random import Generator, PCG64,SFC64,MT19937, SeedSequence
import datetime
rng = Generator(PCG64())
start_now=datetime.datetime.now()
a=rng.standard_normal(100000000)
print(datetime.datetime.now()-start_now)
a.mean(),a.var()
##0:00:00.749294
##Out[]: (-6.0587404403358404e-05, 0.999995988929162)

rng = Generator(SFC64())
start_now=datetime.datetime.now()
a=rng.standard_normal(100000000)
print(datetime.datetime.now()-start_now)
a.mean(),a.var()

## 0:00:00.805515
## Out[]: (2.466525708217848e-05, 0.99977254868066)

rng = Generator((MT19937()))
start_now=datetime.datetime.now()
a=rng.standard_normal(100000000)
print(datetime.datetime.now()-start_now)
a.mean(),a.var()

## 0:00:00.964703
## Out[]: (0.0003127032312065196, 0.9997116080912387)

Python3ではじめるシステムトレード【第2版】環境構築と売買戦略

「画像をクリックしていただくとpanrollingのホームページから書籍を購入していただけます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0