132
176

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python3ではじめるシステムトレード:長期投資

132
Last updated at Posted at 2020-09-20

長期投資の基本

2026年7月改訂
公開済みの記事について、市場規模の数値、時系列分析の説明、リスク管理の議論を更新しました。

本記事では、長期投資を考えるために必要な次の四つの視点を取り上げます。

  • 入手可能な長期間のデータから値動きの特徴を分析する
  • 投資対象となる市場の規模と構造を把握する
  • 見せかけのトレンドとランダムウォークを区別する
  • 投資を継続できなくなるような損失を避ける

長期投資は、長く保有すれば必ず利益が得られるという考え方ではありません。投資対象となる市場の構造、価格変動の性質、分散、費用、資金管理を合わせて考える必要があります。

長期間のデータから値動きの特徴を分析する

「できるだけ直近のデータを使った方が、現在の市場に適した分析ができる」と考える人は少なくありません。株式市場の性質は時間とともに変化するため、古いデータを使うべきではないという意見もあります。

確かに、制度、金融政策、市場参加者、取引技術などの変化によって、市場の構造が変わることはあります。しかし、そのことだけを理由に分析期間を短くすると、別の問題が生じます。

短期間のデータから得られた結果には、その期間に偶然発生した相場環境が強く反映されます。そのため、一時的な値動きを市場の普遍的な特徴と誤認したり、短期間の好成績が今後も続くと考えたりする危険があります。

さらに、分析期間や対象銘柄を何度も変更すると、自分の期待に合う結果だけを無意識に選んでしまうことがあります。過去データの分析は事実を確認する作業である一方、分析者の期待を正当化する作業にもなりやすいのです。

この危険を小さくするには、原則として、入手可能な範囲でできるだけ長期間のデータを使用することが重要です。長いデータには、上昇相場、下落相場、金融危機、インフレ、デフレ、低金利、金利上昇など、異なる市場環境が含まれます。

ただし、全期間を一括して分析するだけでも十分ではありません。期間を分割した分析やローリング分析を行い、結果が特定の時期だけに依存していないかを確認する必要があります。

長期間のデータを使う目的は、望ましい結果を得ることではありません。期待どおりにならない時期を含め、その投資方法がどのような条件で機能し、どのような条件で失敗するかを明らかにすることにあります。

市場規模

市場の規模は、将来の収益率を直接予測するものではありません。しかし、投資対象となる企業の数、売買の流動性、資金調達手段、投資家層の厚さを考えるための出発点になります。

株式・国債市場

公表時期のそろう直近値を中心に、主な市場規模を整理すると次のようになります。

市場 規模 基準日・定義
日本の株式市場 約8.67兆ドル Japan Exchange Group、内国株式時価総額、2026年5月
米国の上場株式市場 約76.9兆ドル 米国上場企業全体、2026年第2四半期
ニューヨーク証券取引所 約32.41兆ドル 内国株式時価総額、2026年5月
Nasdaq-US 約43.74兆ドル 内国株式時価総額、2026年5月
世界の株式市場 約166.45兆ドル WFE地域別集計の合計、2026年5月
米国債市場 約31.1兆ドル 市場残高、2026年6月
日本の内国債 約1,207.2兆円 2026年3月末

WFEの地域別集計を単純に合計すると、2026年5月の世界の株式市場は約166.45兆ドルです。その中でJapan Exchange Groupは約5.2%、NYSEとNasdaq-USの合計は約45.8%になります。

ただし、これは取引所別統計の単純集計です。複数市場への上場、外国企業の上場、集計範囲の違いなどがあるため、株価指数の国別構成比とは一致しません。

日本株が上昇しても、海外市場がそれ以上に拡大したり、為替レートが変化したりすれば、日本市場の世界に占める比率は上昇しません。国内の株価指数の水準と、世界市場における相対的な規模は分けて考える必要があります。

出所:

ファンドの運用資産残高

ファンド市場 純資産総額・運用資産残高 基準日
世界の規制対象オープンエンドファンド 約87.23兆ドル 2026年第1四半期末
世界のETF 約19.40兆ドル 2026年第1四半期末
米国のETF 約15.60兆ドル 2026年5月末
米国のミューチュアルファンド 約33.15兆ドル 2026年5月末
世界のヘッジファンド 約5.6兆ドル 2026年第2四半期末

出所:

株式市場や債券市場の規模と、ETF、投資信託、ヘッジファンドの運用資産残高は意味が異なります。ファンドは株式や債券を保有するための器であるため、両者を単純に合計することはできません。

市場規模の把握

市場規模を調べる目的は、大きな市場ほど将来も上昇すると考えることではありません。

市場が大きいということは、多数の企業が上場し、多数の投資家が参加し、大量の売買や資金調達が行われてきた結果です。一般に市場が大きく流動性が高ければ、売買が成立しやすく、さまざまな企業や金融商品へ分散しやすくなります。

一方、市場が小さい場合には、特定企業の比重が大きくなったり、一部の投資家の売買が市場全体へ強く作用したりすることがあります。

もっとも、市場規模は市場制度の良さを完全に証明するものでもありません。市場を評価するには、次の点も確認する必要があります。

  • 新しい企業が資金を調達できるか
  • 企業情報が適切に開示されているか
  • 少数株主の権利が保護されているか
  • 売買の流動性が確保されているか
  • 成長企業と衰退企業が適切に入れ替わるか
  • 低収益な事業から生産性の高い事業へ資本が移動するか

市場規模は、これらの機能を考えるための観察材料です。長期投資では、直近の株価上昇だけでなく、その背後にある市場の構造を見る必要があります。

他人のお金で経済活動をする

政府、企業、家計は、自己資金だけで経済活動を行っているわけではありません。銀行から借りたり、債券や株式を発行したりして、他者から資金を調達します。

資金調達は、大きく次の三つに分けられます。

  • 銀行融資
  • 債券
  • 株式

銀行は預金などを集め、借り手を審査して融資します。債券には、通常、利息と元本返済の契約があります。株式にはあらかじめ定められた返済義務はなく、株主は企業の残余利益と損失を引き受けます。

債務は別の主体の金融資産である

借り手にとっての債務は、貸し手にとっての金融資産です。

$$
\text{ある主体の債務}=\text{別の主体の金融資産}
$$

したがって、債務が増えたからといって、その金額が経済から消えるわけではありません。重要なのは、誰が、どの条件で借り、その資金を何に使い、将来どのような所得から返済するかです。

金融機関同士の債権と債務を、政府、家計、企業の債務へ単純に加えると、同じ資金仲介を重複して数えることがあります。そのため、国際比較では政府、家計、非金融企業からなる非金融部門の債務がよく使われます。

IMFのGlobal Debt Databaseによると、2024年の民間債務は、米国がGDP比約143.1%、日本が約181.4%、中国が約205.6%でした。数字の大小だけでなく、家計と企業のどちらが借りているか、借入がどのような資産や事業に使われているかを見る必要があります。

出所:

株式時価総額は資金流入額ではない

債務には元本と利息に関する契約があります。一方、株式は企業の所有権の一部です。

$$
\text{株式時価総額}=\text{現在の株価}\times\text{発行済株式数}
$$

市場で成立した一部の取引価格が、発行済株式全体の評価に使われます。そのため、株式時価総額が1兆円増加しても、1兆円の現金が新たに株式市場へ流入したとは限りません。

債務が多いと株式市場は小さくなるのか

債務が増えれば、その分だけ株式市場へ回る資金が減るという単純な関係はありません。

企業が借入によって設備や技術へ投資し、利益を増やせば、債務と株式時価総額が同時に増えることがあります。政府の借入も、社会基盤や教育などに有効に使われれば、企業活動を支える可能性があります。

反対に、債務が過大になれば、利払い負担、増税懸念、金融危機、民間投資の抑制などを通じて経済活動を圧迫します。

したがって、債務について重要なのは残高だけではありません。

$$
\boxed{
\text{調達した資金が、将来の所得や生産力を生む用途に使われているか}
}
$$

を確認する必要があります。

見せかけのトレンドとランダムウォーク

株価や為替レートなど、多くの経済時系列は、ランダムウォークに近い動きを示すことがあります。

対数株価を$p_t$とすると、ドリフト付きランダムウォークは、

$$
p_t=p_{t-1}+\mu+\varepsilon_t
$$

と表せます。

ここで、$\mu$は平均的な変化、$\varepsilon_t$はその時点で新たに加わる予測困難な変化です。

この式を繰り返し代入すると、

$$
p_t=p_0+t\mu+\sum_{i=1}^{t}\varepsilon_i
$$

となります。

$\varepsilon_t$が互いに独立で分散が$\sigma^2$なら、

$$
\operatorname{Var}(p_t)=t\sigma^2
$$

したがって標準偏差は、

$$
\operatorname{SD}(p_t)=\sigma\sqrt{t}
$$

です。

$\mu>0$なら期待値は時間とともに上昇します。しかし、実際に観察される一本の価格経路は、大きく上昇したり下落したりします。

したがって、

  • 株価に長期的な上昇傾向があること
  • 次の期間の上昇・下落を予測することが難しいこと

は矛盾しません。

見せかけのトレンド

ランダムウォークから生成された時系列でも、一定期間にわたって上昇や下落を続けることがあります。乱数だけから作られた系列にも、あたかも規則的なトレンドが存在するような形が現れます。

これを見せかけのトレンドと呼びます。

価格がしばらく上昇しているからといって、それだけで今後も上昇を続けるとは限りません。過去の上昇が企業利益、市場構造、金融条件などの変化によるものか、偶然現れた価格経路なのかを区別する必要があります。

見せかけの相関

互いに無関係な二つのランダムウォークの水準同士を回帰すると、高い相関や統計的に有意な関係が現れることがあります。

これを見せかけの相関または見せかけの回帰といいます。

そのため、価格水準をそのまま比較するだけでなく、価格の変化や収益率を調べることが重要です。

対数収益率は、

$$
r_t=p_t-p_{t-1}
$$

です。

価格水準が非定常であっても、その差分である収益率は定常的な性質を持つことがあります。

Pythonでランダムウォークを作る

次のコードは、乱数から20本のランダムウォークを生成して順番に表示します。

%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
ax.set_xlim(0, 99)
ax.set_ylim(-50, 50)
ax.grid(True)

line, = ax.plot([], [], linewidth=2)
locus, = ax.plot([], [], ".", markersize=1)

paths_x, paths_y = [], []
rng = np.random.default_rng()

def animate(_):
    x = np.arange(100)
    y = np.cumsum(rng.standard_normal(100))
    line.set_data(x, y)

    paths_x.extend(x)
    paths_y.extend(y)
    locus.set_data(paths_x, paths_y)
    return line, locus

anim = FuncAnimation(
    fig,
    animate,
    frames=20,
    interval=1000,
    blit=False,
    repeat=False,
)

anim.save("randomwalk.gif", writer="pillow")
plt.show()

randomwalk.gif

このシミュレーションが示すのは、トレンドが観察されたという事実だけでは、その背後に持続的な法則が存在するとはいえないということです。

株価は予測できるのか

株価の予測可能性を調べるときには、単位根検定とランダムウォーク検定を区別する必要があります。

ADF検定が調べること

拡張ディッキー=フラー検定、すなわちADF検定の帰無仮説は、系列に単位根が存在することです。

statsmodels.tsa.stattools.adfullerregression引数は、検定回帰に含める確定項を指定します。

  • n:定数項もトレンドも含めない
  • c:定数項を含める
  • ct:定数項と線形トレンドを含める
  • ctt:定数項、線形トレンド、二次トレンドを含める

これらは「四種類のランダムウォーク」ではありません。検定回帰に何を含めるかという指定です。

出所:statsmodels, adfuller

ADF検定で単位根を棄却できなかったとしても、ランダムウォークであることが証明されたわけではありません。また、単位根があっても、収益率に自己相関やその他の予測可能性が残る場合があります。

したがって、次の順序で調べます。

  1. 対数株価にADF検定を行う
  2. 対数収益率の自己相関を調べる
  3. Ljung–Box検定で複数ラグの自己相関をまとめて検定する
  4. 分散比検定でランダムウォークとの整合性を調べる
  5. ローリング窓で結果が時期に依存していないか確認する

Notebook内で完結するコンパクトなコード

次のコードは、外部の.pyファイルを作らず、Notebook内だけで分析を完結させます。ウォークフォワード予測や売買バックテストは行わず、検定結果の安定性だけを調べます。

必要なライブラリがない場合は、最初に次を実行します。

%pip install numpy pandas scipy statsmodels

CSVファイルには、少なくともDate列とClose列が必要です。

import numpy as np
import pandas as pd

from scipy.stats import norm
from statsmodels.stats.diagnostic import acorr_ljungbox
from statsmodels.tsa.stattools import adfuller
def variance_ratio_test(log_price, q=12, drift=True):
    """異分散に頑健な重複期間の分散比検定。"""
    y = np.asarray(log_price, dtype=float)

    if q < 2 or len(y) < q + 2:
        raise ValueError("分散比検定に必要なデータが不足しています。")

    dy = np.diff(y)
    n = len(dy)
    mu = (y[-1] - y[0]) / n if drift else 0.0

    sigma2_1 = np.sum((dy - mu) ** 2) / (n - 1)

    dy_q = y[q:] - y[:-q]
    m = q * (n - q + 1) * (1 - q / n)
    sigma2_q = np.sum((dy_q - q * mu) ** 2) / m

    vr = sigma2_q / sigma2_1

    z2 = (dy - mu) ** 2
    scale = np.sum(z2) ** 2

    theta = 0.0
    for k in range(1, q):
        delta = n * np.dot(z2[k:], z2[:-k]) / scale
        theta += 4 * (1 - k / q) ** 2 * delta

    statistic = np.sqrt(n) * (vr - 1) / np.sqrt(theta)
    p_value = 2 * norm.sf(abs(statistic))

    return {
        "variance ratio": vr,
        "test statistic": statistic,
        "p-value": p_value,
    }


def rolling_random_walk_tests(
    close,
    window=120,
    step=12,
    lb_lag=12,
    vr_lag=12,
):
    # 月次対数株価を使ったローリング検定
    monthly = close.resample(pd.offsets.MonthEnd()).last().dropna()
    log_price = np.log(monthly)
    rows = []

    if len(log_price) < window:
        raise ValueError(
            f"月次データが不足しています。必要数={window}, 実際={len(log_price)}"
        )

    for end in range(window, len(log_price) + 1, step):
        lp = log_price.iloc[end - window:end]
        r = lp.diff().dropna()

        lag = min(lb_lag, max(1, len(r) // 5))
        vr_q = min(vr_lag, len(lp) - 2)

        adf_c = adfuller(lp.to_numpy(), regression="c", autolag="AIC")
        adf_ct = adfuller(lp.to_numpy(), regression="ct", autolag="AIC")

        lb = acorr_ljungbox(
            r.to_numpy(),
            lags=[lag],
            return_df=True,
        )

        vr = variance_ratio_test(lp, q=vr_q, drift=True)

        rows.append({
            "start": lp.index[0],
            "end": lp.index[-1],
            "ADF p-value (c)": adf_c[1],
            "ADF p-value (ct)": adf_ct[1],
            "return autocorrelation (lag 1)": r.autocorr(1),
            f"Ljung-Box p-value (lag {lag})": lb["lb_pvalue"].iloc[0],
            f"variance ratio (q={vr_q})": vr["variance ratio"],
            "variance-ratio p-value": vr["p-value"],
        })

    return pd.DataFrame(rows)
tickers = ["usmv", "qqq", "spy", "dia"]

results = {}

for ticker in tickers:
    df = pd.read_csv(
        f"{ticker}.csv",
        index_col="Date",
        parse_dates=["Date"],
    ).sort_index()

    results[ticker] = rolling_random_walk_tests(df["Close"])

results["spy"].round(4).head()

image.png

分散比検定の帰無仮説は、価格系列がランダムウォークであることです。上の関数では、重複期間、有限標本補正、異分散頑健な分散を用いています。

計算方法の確認には、次の実装も参考になります。

検定結果の読み方では、次の点に注意します。

  • $p$値が大きいことは、帰無仮説が正しいことの証明ではない
  • ADF検定だけでは、収益率の予測可能性は判断できない
  • 一つの期間だけで棄却された結果を一般化しない
  • 統計的な規則性があっても、取引費用控除後の利益を意味しない

この分析から分かるのは、価格系列がランダムウォークとどの程度整合的であるか、結果が期間によって変化するかということです。実際の予測力を主張するには、別途、未使用データを使った予測評価が必要です。

破綻を避けるために

投資における破綻とは、資産が完全にゼロになることだけではありません。大きな損失、追加証拠金、借入金の返済、生活資金の不足などによって、投資を継続できなくなることも実質的な破綻です。

買い持ち、リバランス、損切り、オプションには、それぞれ異なる役割があります。

方法 主な役割 主な限界
買い持ち 売買を減らし、長期的な市場収益を受け取る 大幅下落をそのまま受ける
リバランス 資産配分とリスクを目標へ戻す 費用がかかり、超過収益を保証しない
損切り 一回の損失やポジションを限定する 往復売買や連続損失が起こり得る
オプション 損失の上限を設定する プレミアムを継続的に負担する
積立投資 購入時点を分散する 投資対象自体の下落や破綻は防げない

どの方法も、単独で破綻を完全に防ぐものではありません。

買い持ちとリバランス

二つの銘柄に最初に50%ずつ投資し、その後売買しない買い持ちと、毎日50%ずつへ戻すリバランスを比較します。

ここでは、同じフォルダにregn.csvlly.csvがあり、それぞれにDate列とClose列があるものとします。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

ticker1 = "regn"
ticker2 = "lly"

asset1 = pd.read_csv(
    f"{ticker1}.csv",
    index_col="Date",
    parse_dates=["Date"],
)["Close"]

asset2 = pd.read_csv(
    f"{ticker2}.csv",
    index_col="Date",
    parse_dates=["Date"],
)["Close"]

prices = pd.concat([asset1, asset2], axis=1).dropna()
prices.columns = [ticker1, ticker2]
prices = prices / prices.iloc[0]

買い持ちでは、最初に50%ずつ購入した株数を変更しません。

buy_and_hold = 0.5 * prices[ticker1] + 0.5 * prices[ticker2]

毎日リバランスする場合には、各日の二銘柄の単純収益率を50%ずつ受け取ります。

returns = prices.pct_change().dropna()

daily_rebalanced = (1 + returns.mean(axis=1)).cumprod()
daily_rebalanced = pd.concat([
    pd.Series([1.0], index=[prices.index[0]]),
    daily_rebalanced,
])

comparison = pd.DataFrame({
    "buy and hold": buy_and_hold,
    "daily rebalance": daily_rebalanced,
}).dropna()

np.log(comparison).plot()
plt.ylabel("log portfolio value")
plt.grid(True)
plt.show()

image.png

以前のコードにあった、

0.5 * np.log(asset1) + 0.5 * np.log(asset2)

は、買い持ちポートフォリオの対数価値ではありません。これは二つの価格の幾何平均の対数です。買い持ちポートフォリオは、まず価格水準で合計し、その後に対数を取ります。

また、上のリバランス計算には取引費用と税金を含めていません。毎日リバランスすると売買回数が多くなるため、実務では月次・四半期ごと、または目標比率から一定以上ずれたときだけ調整する方法が考えられます。

分散投資でも市場リスクは残る

二銘柄を保有しても、両社が同時に大きく下落する可能性があります。多数の銘柄からなる株価指数へ投資すれば、個別企業の倒産や不祥事による企業固有リスクを小さくできます。

ただし、株価指数も市場全体の下落を避けることはできません。

$$
\text{分散投資}
\neq
\text{損失の消滅}
$$

分散投資の目的は、報酬を得るために必ずしも必要でない個別企業への集中リスクを減らすことです。

積立投資が減らすのは購入時点の偏りである

ドルコスト平均法、すなわち積立投資は、購入時点を分散します。一度に高値で全額を投資する危険を減らす効果があります。

しかし、投資対象が長期間下落したり、価値を失ったりすれば、積立投資でも損失になります。積立投資は、投資対象そのもののリスクを消す方法ではありません。

長期間の下落でも積立を継続できるか、生活資金と投資資金を分けているかが重要です。

まとめ

本記事の議論は、次のようにまとめられます。

  • 投資方法を評価するときには、できるだけ長いデータと複数の市場環境を使う
  • 市場規模は将来収益率の予測値ではないが、流動性、分散可能性、資金調達、市場参加者の厚さを考える材料になる
  • 債務と株式は競合するだけでなく、経済活動を支える異なる資金調達手段である
  • ADF検定は単位根を検定するものであり、それだけでランダムウォークや予測不能性を判定することはできない
  • 見せかけのトレンドや相関を、持続的な投資法則と誤認しない
  • 分散された株価指数の買い持ちは、特別な予測能力を仮定しない基準戦略になる
  • リバランスは主として資産配分とリスクを管理する方法であり、利益を保証する方法ではない
  • 積立、損切り、オプションにも役割はあるが、単独で破綻を防ぐものではない
  • 生活資金と投資資金を分け、過大なレバレッジと継続困難な損失を避ける

長期投資で最も重要なのは、「損が出た株は利益が出るまで売らない」といった一律の規則ではありません。

投資対象を分散し、費用を抑え、自分が耐えられる損失の範囲で、事前に決めた方針を継続できるようにすることです。

Pythonに不慣れな人に

Jupyter notebookのインストール
Yahoo Finance USから株価をダウンロードしてみた

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

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

Python3ではじめるシステムトレード改訂版 アマゾンから購入いただけます。

19876202607270449

132
176
3

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
132
176

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?