見出し画像

定量分析のはじめかた2

定量分析の考え方の基礎として、金融の時系列データの取得方法と、金融の時系列データ分析に必要な事柄を説明しています。

前回はトラックレコードを読み込んで、簡単なパフォーマンス分析する方法を紹介しましたが、今回はAPIから金融時系列データを取得し、トレードに役立つ分析・可視化を行う、というかんたんな内容にしています。
確率や統計といった内容が出てきますが、難しいところはそこそこに、平易な内容を心掛けましたので、お楽しみいただければ幸いです。

データの取得

金融の時系列データを取得するAPIはいくつもありますが、この記事ではStooqというデータソースを利用します。Stooqは無料であることと、日足のデータではありますが、OHLC(四本値)+Volume(出来高)などのデータが簡単に取得できます。利便性が高いため利用させて頂いております。

時間足や分足、Tickデータなどを取得する場合、有料のデータプロバイダーを利用することがありますが、サービスによっては数百円から数百万円。。のデータプロバイダーから取得できる価格データもあります。
有料無料問わず、データをどのように活用し分析を行うか、目的に応じてサブスクリプションされるのがよいかと思います。

Pythonのデータソースへアクセスするときに、便利なライブラリである、
pandas-datareaderを使います。
pip(環境次第では pip3)で別途インストールする必要があります。

# ライブラリのインストール
pip install pandas-datareader

# gitから最新版のインストールも可能
pip install git+https://github.com/pydata/pandas-datareader.git

データソース(Stooq) を使って、AAPLのデータを取得してみましょう。
ライブラリのバージョンや、データソースのサービス変更によってデータが取得できない場合もありますので、その場合は別のデータソースを参照ください。

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt
import pandas_datareader.data as web

from typing import List, Dict, Any
from datetime import datetime
def get_stock_close(symbol: str, start: str, end: str) -> pd.DataFrame:
  """ Stooqから 株価の取得する関数 """
  start = datetime.strptime(start, '%Y,%m,%d')
  end = datetime.strptime(end, '%Y,%m,%d')
  df = web.DataReader(f"{symbol}.US", 'stooq', start, end)
  df.sort_index(inplace=True)
  return df

※"AAPL"はアップルのtickerですが、この記事ではあくまでも学習・検証用途に事例を説明しています。
プログラムは関数化しているため、再利用できるようにしています。
AAPL以外のデータ、開始と終了日付を任意のデータに変更することで、別の銘柄、期間で時系列データを取得することができます。
(この記事では1銘柄しか算出していませんが、複数の銘柄を取得するコードも今後掲載予定です)

aapl = get_stock_close("AAPL", "2023,1,1", "2023,7,21")
aapl.tail(10)
AAPLの直近10日分のOHLCVデータ

無事にデータが取得でき、データフレームが表示されていますね。

日次リターン、累積リターンの取得

次に、AAPLから日次リターンの取得、累積リターンを取得しグラフにて表示してみましょう。日次リターンは直近のデータと一つ前のデータ(shift=1)することで算出できます。累積リターンは cumprod()を用いることで累積積を計算し、リターンを算出しています。

def calculate_log_returns(df: pd.DataFrame, column: str) -> pd.Series:
  """ ログリターンの算出 """
  return np.log(df[column] / df[column].shift(1))

def calculate_cumulative_returns(log_returns: pd.Series) -> pd.Series:
  """ ログ累積リターンの算出 """
  return (1 + log_returns).cumprod()

def plot_data(data: Dict[str, pd.Series], title: str, xlabel: str, ylabel: str):
  """ プロットデータ """
  plt.figure(figsize=(14,7))
  for label, series in data.items():
    series.plot(label=label)
# AAPLのログリターン、累積リターンを取得
aapl_log_returns = calculate_log_returns(aapl, 'Close')
aapl_cum_returns = calculate_cumulative_returns(aapl_log_returns )

# グラフを出力
plot_data({'AAPL Cumulative Returns': aapl_cum_returns}, 'Cumulative Returns', 'Date', 'Returns')
AAPLの累積リターン(2023-01 ~ 2023-07)

logは数学で使われる、対数ログのことです。対数リターンを算出することで、価格変動率を一定のスケールに正規化し、分散不均一性の誤差を減らすことができ、さまざまなタイムホライズン(時間スケール)やアセット毎の収益を比較し易くなります。
対数リターンは、正規分布に従うという統計的な仮定に基づいており、対数リターンを用いることでこれらの手法を適用しやすくなります。

def calculate_bins(n: int) -> int:  
  """ スタージェスの公式によりビン数を算出 """  
  return round(1 + 3.322 * np.log10(n))

def plot_histogram(data: pd.Series, title: str, xlabel: str, ylabel: str):  
  """ ヒストグラムのプロット """  
  bins = calculate_bins(len(data))
  plt.figure(figsize=(14,7))
  plt.hist(data, bins=bins, edgecolor='black')

  plt.title(title)
  plt.xlabel(xlabel)
  plt.ylabel(ylabel)
  plt.show()
aapl_returns = aapl_returns.dropna()
plot_histogram(aapl_returns, title='Histogram of AAPL Log Returns', xlabel='Log Returns', ylabel='Frequency')
AAPLのログリターン(ヒストグラム)
aapl_returns.describe()
>>> count 136 

N = 136
bins = 1+3.3222*np.log10(N)
>>> bins 8

この式は、「スタージェスの公式」と呼ばれており、ビンの数をデータを適切に統計的な分析、視覚化するために設定します。データサイズに基づくおおよそのビン(またはクラス)の数を計算します。Nはデータセット内の数を表します。

ヒストグラムと正規分布

正規分布はちょうど真ん中のピークとなる平均値(μ)を中心に、左右対称な形状を持つ特性があり、釣り鐘状の形状からベルカーブとも呼ばれています。
分布の幅(つまり、データの散らばり具合)は標準偏差(σ)によって決まり、標準偏差が大きいと分布が広がり、小さいと分布が細くなります。この形状は、価格変動やリターンが時間経過とともにランダムに発生するという金融市場の基本的な仮定を視覚化しています。

ヒストグラムの上に正規分布の曲線(確率密度関数)をプロットします。これにより、データがどの程度正規分布に従っているかを視覚的に確認できます。また、正規分布のパラメータ(平均と標準偏差)を求めました。

from scipy.stats import norm

def plot_histogram_with_normal_curve(data: pd.Series, title: str, xlabel: str, ylabel: str):
    """ 正規分布曲線を持つヒストグラムをプロット """
    mu, std = norm.fit(data)
    bins = calculate_bins(len(data))
    plt.figure(figsize=(14,7))
    plt.hist(data, bins=bins, density=True, alpha=0.6, color='g', edgecolor='black')
   
  xmin, xmax = plt.xlim()
    x = np.linspace(xmin, xmax, 100)
    p = norm.pdf(x, mu, std)
    plt.plot(x, p, 'k', linewidth=2)

    title = f"{title}: mu = {mu:.2f},  std = {std:.2f}"   
    plt.title(title)
    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    plt.show()
# ログリターンの計算でN/A値が導入される可能性があるため、N/Aを削除
aapl_returns = aapl_returns.dropna()

# ヒストグラムと正規分布をグラフ出力
plot_histogram_with_normal_curve(aapl_returns, title='Normal Distribution', xlabel='Log Returns', ylabel='Frequency')
ヒストグラムと正規分布のグラフ

予め指定したのビン数で、y軸(縦軸)が頻度でx軸(横軸)がログリターンの発生を表示しています。
正規分布は、金融市場の理論と実践でもたびたび出てくる概念であり、確率密度を表現します。具体的な証券やポートフォリオのリスクを評価したり、異常値の可能性を分析・評価します。

正規分布は金融は全体像を完全に捉えるわけではないため、モデルのリスクと効果を理解することにも注意する必要があり、「テールリスク」(正規分布の裾の部分である、あまり起こらない価格変動リスク)を過小評価する傾向があります。

次回の予告

単一銘柄(例えばAAPLの株価のみ)だけでなく、データ間の違いを分析し、可視化することで他の銘柄や指数との比較を行うことができます。単一銘柄だけでは、そのパフォーマンスを比較・評価するための基準点(ベンチマーク)が存在しないため、評価基準が不明瞭になります。

そのため、次回の分析では複数銘柄に基づくポートフォリオ群を作成し、銘柄間の相関性や共分散、さらには線形回帰分析などを通じて、ポートフォリオ全体の性質を評価し、可視化する予定です(変わる可能性もあり)
データを駆使したアプローチにより、投資ポートフォリオのリスクとリターンのバランスを知ることにより、定量的な評価することが可能と考えています(ひいらぎ)

今夏のコミケの内容について

SP本②について、上記のような金融のデータ分析や、統計学をネタにした話を記載しています。

黒猫アイランドさん、松崎美子さんはよりトレードの本質的な話、定量分析に関する話、ファンダメンタルズの深い話などですが、私のパートでは基本的には定量分析に関する話題を取り扱っています。

プログラミングのコードも多用に用意しまして、同人誌の購入者様に本文にあるソースコードをGoogle Colabで全て公開しています。
修正が必要な個所もあるでしょうから、ソースコード修正と、本文の入稿時点では気づかない箇所やもうちょっと工夫したい箇所などをブラッシュアップできたらと考えています。
統計学、時系列解析、機械学習などプログラミングを主体にした、多用な内容になっていますが、お楽しみいただければと思います。


この記事が気に入ったらサポートをしてみませんか?