ZigZagのCSVをPythonで集計する|pandasで20行

ZigZagの山と谷をCSVに出したら、集計はPython(pandas)なら20行ほどで済みます。時間足ごとの波の大きさ・長さ・押し目の比率まで、1回の実行で出せます。

この記事のコードは、実際に出力したCSVで動かして確認したものです。出力結果もそのまま載せています。

(確認環境:Python 3.13/pandas 3.0.1/Windows 11)

前提:CSVの形

次の列を持つCSVを想定しています。

symbol,timeframe,seq,type,time,bar_shift,price
USDJPY,M5,1,Peak,2026.05.22 15:20,3,156.123
USDJPY,M5,2,Bottom,2026.05.22 14:55,8,155.842

コードで使うのは timeframe・type・time・price などの一部だけです。ほかに列が増えていても、そのまま動きます(usecols で必要な列だけを読んでいるためです)。

コード

import pandas as pd

df = pd.read_csv("zigzag_export.csv", usecols=["symbol", "timeframe", "type", "time", "price"])
df["time"] = pd.to_datetime(df["time"], format="%Y.%m.%d %H:%M")
PIP = 0.01  # 円絡みの通貨ペア。ドルストレートなら 0.0001

legs = []
for tf, g in df.groupby("timeframe"):
    g = g.sort_values("time").reset_index(drop=True)       # 古い順に並べ直す
    g["pips"]  = g["price"].diff().abs() / PIP               # 1つ前の点からの値幅
    g["hours"] = g["time"].diff().dt.total_seconds() / 3600  # 1つ前の点からの時間
    g["ratio"] = g["pips"] / g["pips"].shift(1)              # 直前の波に対する比率
    legs.append(g)

legs = pd.concat(legs).dropna(subset=["pips"])

summary = legs.groupby("timeframe")[["pips", "hours"]].median().round(1)
summary["波の数"] = legs.groupby("timeframe").size()
print(summary.loc[["M5", "M15", "H1", "H4"]])

r = legs["ratio"].dropna()
print(f"\n比率の件数: {len(r)} / 100%以上: {(r >= 1).sum()}")
bins = [0, 0.382, 0.5, 0.618, 0.786, 1.0]
print(pd.cut(r[r < 1], bins=bins, right=False).value_counts().sort_index())

実行結果

            pips  hours  波の数
timeframe                   
M5          19.5    0.9   19
M15         33.9    3.8   19
H1          87.9   12.0   19
H4         130.9   80.0   19

比率の件数: 72 / 100%以上: 35
ratio
[0.0, 0.382)       9
[0.382, 0.5)       2
[0.5, 0.618)       6
[0.618, 0.786)     9
[0.786, 1.0)      11
Name: count, dtype: int64

上の表は時間足ごとの波の大きさ(pips)と長さ(時間)の中央値、下は直前の波に対する比率の分布です。

コードの要点

1. 必ず古い順に並べ直す

出力されるCSVは新しい点が先頭に来ることがあります。diff() は上の行との差を取るので、並び順が逆だと値幅の向きが入れ替わります。sort_values("time") で古い順にしてから計算しています。

2. 時刻の形式を指定する

MT5の時刻は 2026.08.18 03:45 のようなドット区切りです。format="%Y.%m.%d %H:%M" を指定しないと、読み込みに失敗したり、遅くなったりします。

3. 1pipsの大きさを銘柄に合わせる

PIP = 0.01 は円絡みの通貨ペアの値です。ドルストレートなら 0.0001、金なら業者の仕様に合わせます。複数の銘柄を1つのCSVで扱うなら、symbol ごとに値を切り替えてください。

4. 平均ではなく中央値

波の大きさには極端に大きい1本が混ざります。このデータでもH4の最大は875.9pipsで、中央値の6倍以上でした。「普段の大きさ」を見るなら中央値を使います。

🔴 結果を読むときの注意

比率の分布で72件中35件が100%以上になっています。ZigZagは上げと下げを交互に並べるだけなので、推進の波と修正の波を区別せずに割ると、押し目の深さにはなりません。下の分布は100%未満(直前の波を超えなかった波)だけに絞ったものです。

この考え方と結果の読み方は押し目は何%戻るのか|ZigZagのCSVで実測するで詳しく扱っています。

また、各時間足で同じ20点を取っても、M5は約1日分、H4は約2.5か月分です。時間足どうしを比べるなら、出力する点の数を増やすか期間で区切ってください。Excelで同じ集計をする方法は波の大きさを時間足ごとに集計する方法にまとめています。

CSVを用意する

この記事のCSVは、当サイトが開発・販売している ZigzagColor_csv(¥3,400)で出力しました。MT5のチャート上のボタン1つで、複数の時間足の山(Peak)と谷(Bottom)を上の形式のCSVに書き出します。直近の未確定の点は初期設定で出力から外れるので、後から動く点が集計に混ざりません。

自分でMQL5からCSVを書き出す場合はMQL5でCSVを出力する方法を参照してください。

まとめ

  1. ZigZagのCSVはpandasで20行ほどで集計できる
  2. 古い順に並べ直してから差を取る
  3. MT5の時刻はドット区切り。format を指定する
  4. 1pipsの大きさを銘柄に合わせる
  5. 🔴 比率は推進と修正を区別しないと押し目の深さにならない

本記事は過去データの集計方法を説明したものであり、将来の値動きや取引の成果を示すものではありません。投資判断はご自身の責任で行ってください。