【実践】自作システムで株を運用する際の絶対ルールと資金管理法

基礎知識・戦略

※本記事のコードや情報は執筆時点の仕様に基づいています。投資は自己責任であり、必ずデモ環境や少額資金でテストした上で運用してください。

Pythonでテクニカル分析のシステムを構築し、売買シグナルを自動で出せるようになった段階で、多くの個人投資家が「いよいよ実資金を投入しよう」と意気込みます。

しかし、ここが最も危険なタイミングです。

バックテストで好成績だったアルゴリズムが、実際の相場で同じパフォーマンスを出す保証はどこにもありません。システムが完成した「後」にこそ、明確な運用ルールと資金管理の仕組みを設計する必要があります。

この記事では、自作の株式アルゴリズムを実運用に移す前に必ず設定すべき「絶対ルール」と、破産リスクを数学的にコントロールする資金管理法、そしてシステムへの過信を防ぐマインドセットまでを体系的に解説します。

なぜ「運用ルール」がアルゴリズムそのものより重要なのか

アルゴリズムの精度を高めることに注力する人は多いですが、どれほど優秀なシグナルでも、運用ルールが欠如していれば資金は守れません。

ここでは、ルールなき運用がなぜ致命傷になるのかを整理します。

バックテストと実運用の決定的な違い

バックテスト環境と実運用には、以下のような本質的なギャップが存在します。

項目 バックテスト 実運用
約定価格 終値で即約定と仮定 スリッページが発生する
手数料 固定 or 無視しがち 売買頻度で大きく変動する
メンタル 影響ゼロ 含み損で判断が揺らぐ
データ品質 整形済みの過去データ 欠損・遅延・異常値がある
市場環境 過去の特定期間 未知の相場に直面する

バックテストの成績は「過去の最適解」に過ぎず、将来の利益を約束するものではありません。

「ルールがない運用」は投資ではなくギャンブル

運用ルールとは、感情を排除するための「事前の契約書」です。

  • 1回の取引で許容する最大損失額はいくらか
  • 月間の最大ドローダウンをいくらに設定するか
  • システムを停止する条件は何か

これらが明文化されていない状態で資金を投入することは、システムトレードではなく、ただの裁量ギャンブルと同義です。

生存バイアスの罠

ネット上で「年利50%を達成しました」と報告しているトレーダーの裏側には、同じ手法で資金を溶かした大勢の退場者がいます。

成功事例だけを見てルールを軽視すると、生存バイアスの罠に落ちます。

重要:アルゴリズムの「性能」よりも、運用の「規律」が長期的な生存率を決定します。

実運用前に設定すべき5つの絶対ルール

システムを稼働させる前に、以下の5つのルールを必ず紙やドキュメントに書き出してください。

「頭の中にある」だけでは、相場が荒れた瞬間に簡単に破られます。

ルール1:1トレードあたりのリスク上限を固定する

最も重要なルールが「1回の取引で失ってもよい金額の上限」を定めることです。

一般的に推奨される基準は以下の通りです。

  • 保守的: 総資金の 1% 以下
  • 標準的: 総資金の 2% 以下
  • 攻撃的: 総資金の 3% 以下(非推奨)

例えば、運用資金が100万円で1トレードリスクを2%に設定した場合、1回の損切りで許容する最大損失額は2万円となります。

この上限を超えるポジションサイズは、どれほどシグナルが強くても取らないでください。

ルール2:月間最大ドローダウンでシステムを停止する

月間で資金が一定割合以上減少した場合、無条件でシステムを停止するルールを設けます。

推奨値は月間 -10% です。

100万円の運用資金が90万円を下回った時点で、その月の取引はすべて停止し、以下を実行してください。

  • アルゴリズムのロジックに問題がないか検証する
  • 市場環境がシステムの想定レンジ外になっていないか確認する
  • 翌月、資金を減額して再開するか判断する

ルール3:ポジションの同時保有数を制限する

複数銘柄に同時にシグナルが出た場合、すべてに資金を投入すると、セクター全体が下落したときに壊滅的な損失を被ります。

  • 同時保有ポジション数は最大3〜5銘柄に制限する
  • 同一セクターへの集中は2銘柄までとする
  • 相関係数の高い銘柄の同時保有は避ける

ルール4:シグナルの「見送り条件」を明文化する

シグナルが出たからといって、すべてを機械的にエントリーするのは危険です。

以下のような状況では、シグナルを見送るルールを事前に設定します。

  • 決算発表の前後3営業日以内
  • 出来高が直近20日平均の50%を下回っている
  • 日経平均が前日比 -3% を超える暴落日
  • 重大な経済指標の発表直前(FOMC、雇用統計など)

ルール5:運用ログを毎日記録する

すべてのトレードを記録し、月次で振り返りを行うことが改善サイクルの根幹です。

記録すべき項目は以下の通りです。

  • 日付・銘柄コード・売買方向
  • エントリー価格・エグジット価格
  • 損益額・損益率
  • シグナル種別(どのアルゴリズムが発火したか)
  • 備考(見送った理由、感情の状態など)

重要:ルールは「作って終わり」ではありません。運用ログに基づいて四半期ごとに見直し、アップデートしてください。

資金管理の数学:ポジションサイズの計算方法

運用ルールの中でも、ポジションサイズの計算は最も実務的かつ重要なスキルです。

ここでは、固定リスク率に基づくポジションサイズの算出方法をコード付きで解説します。

固定リスク率モデルの考え方

固定リスク率モデルとは、「1トレードで失ってもよい金額」から逆算して、購入する株数を決定する方法です。

計算式は以下の通りです。


購入株数 = (総資金 × リスク率) ÷ (エントリー価格 - 損切り価格)

例として、以下の条件で計算します。

  • 総資金:100万円
  • リスク率:2%(= 許容損失 2万円)
  • エントリー価格:2,500円
  • 損切り価格:2,400円(100円幅)

購入株数 = 20,000 ÷ 100 = 200株

つまり、200株までなら損切りしても2万円の損失で収まります。

【コピペOK】ポジションサイズ自動計算コード

以下のPythonコードで、ポジションサイズを自動計算できます。


# ==============================
# ポジションサイズ計算ツール
# ==============================

def calculate_position_size(
    total_capital: float,
    risk_rate: float,
    entry_price: float,
    stop_loss_price: float,
    lot_unit: int = 100
) -> dict:
    ""
    固定リスク率モデルに基づくポジションサイズ計算

    Parameters
    ----------
    total_capital : float
        運用資金の総額(円)
    risk_rate : float
        1トレードあたりのリスク率(例: 0.02 = 2%)
    entry_price : float
        エントリー予定価格(円)
    stop_loss_price : float
        損切り価格(円)
    lot_unit : int
        売買単位(日本株は通常100株)

    Returns
    -------
    dict
        計算結果を格納した辞書
    ""
    # 許容損失額
    max_loss = total_capital * risk_rate

    # 1株あたりの損失幅
    loss_per_share = abs(entry_price - stop_loss_price)

    if loss_per_share == 0:
        print("エラー: エントリー価格と損切り価格が同じです。")
        return {}

    # 理論上の最大株数
    raw_shares = max_loss / loss_per_share

    # 売買単位に丸める(切り捨て)
    adjusted_shares = (int(raw_shares) // lot_unit) * lot_unit

    # 必要資金
    required_capital = adjusted_shares * entry_price

    # 実際のリスク額
    actual_risk = adjusted_shares * loss_per_share

    result = {
        "総資金": f"{total_capital:,.0f}円",
        "リスク率": f"{risk_rate * 100:.1f}%",
        "許容損失額": f"{max_loss:,.0f}円",
        "エントリー価格": f"{entry_price:,.0f}円",
        "損切り価格": f"{stop_loss_price:,.0f}円",
        "1株あたり損失幅": f"{loss_per_share:,.0f}円",
        "購入株数": f"{adjusted_shares:,}株",
        "必要資金": f"{required_capital:,.0f}円",
        "実リスク額": f"{actual_risk:,.0f}円",
    }

    return result


# ==============================
# 実行例
# ==============================
if __name__ == "__main__":
    params = {
        "total_capital": 1_000_000,
        "risk_rate": 0.02,
        "entry_price": 2500,
        "stop_loss_price": 2400,
        "lot_unit": 100,
    }

    result = calculate_position_size(**params)

    print("=" * 40)
    print("ポジションサイズ計算結果")
    print("=" * 40)
    for key, value in result.items():
        print(f"  {key}: {value}")
    print("=" * 40)

このコードの出力結果は以下のようになります。


========================================
ポジションサイズ計算結果
========================================
  総資金: 1,000,000円
  リスク率: 2.0%
  許容損失額: 20,000円
  エントリー価格: 2,500円
  損切り価格: 2,400円
  1株あたり損失幅: 100円
  購入株数: 200株
  必要資金: 500,000円
  実リスク額: 20,000円
========================================

【コピペOK】運用ログ記録・集計コード

日々のトレード結果をCSVに記録し、月次の成績を集計するコードも併せて紹介します。


import csv
import os
from datetime import datetime

# ==============================
# 運用ログ管理ツール
# ==============================

LOG_FILE = "trading_log.csv"
HEADERS = [
    "日付", "銘柄コード", "売買方向", "エントリー価格",
    "エグジット価格", "株数", "損益額", "損益率", "シグナル種別", "備考"
]


def init_log():
    ""ログファイルが存在しなければヘッダー付きで作成""
    if not os.path.exists(LOG_FILE):
        with open(LOG_FILE, "w", newline=", encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerow(HEADERS)
        print(f"ログファイルを作成しました: {LOG_FILE}")


def add_trade(
    symbol: str,
    direction: str,
    entry_price: float,
    exit_price: float,
    shares: int,
    signal_type: str = ",
    note: str = "
):
    ""トレード記録を1行追加""
    init_log()

    if direction == "買い":
        pnl = (exit_price - entry_price) * shares
    else:
        pnl = (entry_price - exit_price) * shares

    pnl_rate = pnl / (entry_price * shares) * 100

    row = [
        datetime.now().strftime("%Y-%m-%d"),
        symbol,
        direction,
        entry_price,
        exit_price,
        shares,
        round(pnl, 0),
        round(pnl_rate, 2),
        signal_type,
        note,
    ]

    with open(LOG_FILE, "a", newline=", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(row)

    print(f"記録完了: {symbol} {direction} 損益={pnl:+,.0f}円 ({pnl_rate:+.2f}%)")


def show_monthly_summary():
    ""今月のトレード成績を集計""
    if not os.path.exists(LOG_FILE):
        print("ログファイルが存在しません。")
        return

    current_month = datetime.now().strftime("%Y-%m")
    total_pnl = 0
    trade_count = 0
    win_count = 0

    with open(LOG_FILE, "r", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            if row["日付"].startswith(current_month):
                pnl = float(row["損益額"])
                total_pnl += pnl
                trade_count += 1
                if pnl > 0:
                    win_count += 1

    if trade_count == 0:
        print("今月のトレード記録はありません。")
        return

    win_rate = win_count / trade_count * 100

    print("=" * 40)
    print(f"月次サマリー: {current_month}")
    print("=" * 40)
    print(f"  トレード数: {trade_count}")
    print(f"  勝率: {win_rate:.1f}%")
    print(f"  合計損益: {total_pnl:+,.0f}円")
    print("=" * 40)


# ==============================
# 使用例
# ==============================
if __name__ == "__main__":
    # トレードを記録
    add_trade(
        symbol="7203",
        direction="買い",
        entry_price=2500,
        exit_price=2620,
        shares=200,
        signal_type="ゴールデンクロス",
        note="出来高増加を確認"
    )

    add_trade(
        symbol="9984",
        direction="買い",
        entry_price=8500,
        exit_price=8350,
        shares=100,
        signal_type="RSI反転",
        note="損切り執行"
    )

    # 月次集計を表示
    show_monthly_summary()

システムへの「過信」を防ぐマインドセット

コードが正しく動き、バックテストの成績が良好であるほど、システムへの過信が生まれやすくなります。

この過信こそが、最大のリスク要因です。

「過去の成績は将来を保証しない」を体に刻む

これは投資の世界で繰り返し語られる鉄則ですが、自分が苦労して作ったシステムに対しては、この原則を忘れがちになります。

対策として、以下のプロセスを必ず踏んでください。

  • フォワードテスト期間を設ける: 最低1ヶ月は実資金を入れず、シグナルだけを記録して成績を検証する
  • 段階的に資金を投入する: いきなり全額ではなく、最初は想定資金の25%から開始する
  • 異なる相場環境での検証: 上昇相場だけでなく、暴落期・レンジ相場でもバックテストを行う

ドローダウン時の行動プランを事前に決める

システムが連敗を喫した場合、人間の心理は以下のパターンに陥ります。

  • リベンジトレード: 損失を取り返そうとポジションサイズを増やす
  • ルール逸脱: 「今回だけ」損切りラインを動かす
  • システム放棄: 感情的にシステムを停止し、裁量トレードに走る

これらはすべて、事前にルールを定めておくことで防止できます。

ドローダウン水準 取るべきアクション
-5%(月間) 警戒モード:ポジションサイズを50%に縮小
-10%(月間) 停止モード:今月の新規エントリーを全停止
-15%(累計) 検証モード:最低2週間システムを止めて全面検証
-20%(累計) 撤退モード:全ポジション決済、ゼロからロジック再構築

「システムを疑う習慣」を持つ

優秀なシステムトレーダーほど、自分のシステムに対して懐疑的です。

定期的に以下の問いを自分に投げかけてください。

  • このシステムが機能しているのは、特定の市場環境のおかげではないか
  • 直近のパフォーマンスに引きずられて、リスクを過小評価していないか
  • バックテスト期間のデータに「先読みバイアス」が混入していないか

重要:システムを信じることと、システムを盲信することはまったく別の行為です。冷静な検証の習慣だけが、長期的な運用の生命線となります。

よくあるエラーと対処法

実運用を開始すると、コードのエラーだけでなく、運用設計上のミスにも直面します。

ここでは初心者が特に陥りやすい問題を取り上げます。

ポジションサイズの計算で損切り幅をゼロにしてしまう

損切り価格をエントリー価格と同じに設定すると、ゼロ除算エラーが発生します。

上記のコードでは loss_per_share == 0 の場合にエラーメッセージを返す処理を入れていますが、そもそも損切り幅がゼロのトレードはリスク管理として成立しません。

最低でもATR(Average True Range)の1倍以上の損切り幅を設定してください。

バックテストと実運用で成績が大きく乖離する

これは「カーブフィッティング(過剰最適化)」が原因であることがほとんどです。

対処法は以下の通りです。

  • パラメータの数を最小限に絞る(3つ以下が理想)
  • トレーニング期間とテスト期間を分離する(ウォークフォワード分析)
  • 複数の銘柄・期間で汎用的に機能するか確認する

ログを記録し忘れてPDCAが回せない

運用ログの記録は、最初の数日は続いても、すぐに面倒になって止めてしまうケースが多発します。

対処法として、上記のコードのようにプログラムで自動記録する仕組みを必ず構築してください。

人間の意志力に頼る運用は、必ず破綻します。

複数シグナルの同時発火で資金配分を間違える

3銘柄に同時にシグナルが出た際、それぞれに2%リスクで計算すると合計6%のリスクを同時に取ることになります。

同時保有ポジションの合計リスクが総資金の6%を超えないよう、上限を設けてください。

まとめ

この記事で解説した運用ルールと資金管理法の要点を整理します。

  • 1トレードのリスクは総資金の2%以下に固定する
  • 月間ドローダウンが-10%に達したら無条件で停止する
  • ポジションサイズは感覚ではなく数式で算出する
  • 運用ログを毎日記録し、月次で振り返る
  • フォワードテストを最低1ヶ月実施してから実資金を投入する
  • システムへの過信を防ぐため、定期的にロジックを疑う習慣を持つ

アルゴリズムの「開発」はゴールではなく、スタートラインに過ぎません。

本当の勝負は、ルールを守り続ける「運用の規律」にあります。

まずは今回紹介したポジションサイズ計算コードと運用ログツールを導入し、デモ環境での検証から始めてください。

本記事のコードはすべてコピペで動作します。まずはデモ環境で試し、十分な検証を経てから実運用に移行してください。

タイトルとURLをコピーしました