リファレンス

engine_trades.csv フォーマットを読み解く

PineForgeが出力するトレード一覧CSVの完全リファレンス。列の意味、ペアのエンコード、pandasに載せる30行程度のPythonスニペット。

読了 約5分#docs#csv#engine

PineForge のバックテストは JSON サマリーと一緒に engine_trades.csv を書き出します。エントリー・エグジット・数量・PnL・トレード内のエクスカージョンが 1 行 1 フィルで並んだ台帳です。この記事は 列ごとの意味を曖昧さなく押さえるための参照です——往復を組み立てたりパリティ diff をするときに迷わないように。

ファイルの役割

engine_trades.csv は完了した 1 ランの約定一覧です。各行は 1 回のフィル——ポジションへの参入か決済か。Trade # がエントリーとエグジットをつなぎ、往復を復元します。

列設計は TradingView の「List of Trades」エクスポートに寄せています。触れたことがあればヘッダはほぼ同じです。実務上の差は、PineForge が常に MFE / MAE を出すこと。TradingView は Premium でのみ相当列を出します。そのほかはヘッダ対ヘッダで揃えています。

列ごとの意味

列名は TradingView のエクスポートと diff しやすいよう英語のままです。説明だけ日本語にします。

ColumnType説明
Trade #整数往復トレードの ID。エントリーとエグジットで同じ番号を共有。
Type文字列Entry long / Exit long / Entry short / Exit short のいずれか。
Date and timeUTCYYYY-MM-DD HH:MM。タイムゾーン接尾辞なし。常に UTC。
Pricefloat約定時点のフィル価格(建値通貨)。
Qtyfloat約定数量。常に正。方向は Type で判別。
Net PnLfloatその決済取引の損益。エグジット行のみ。 エントリー行は空かゼロ。
Net PnL %floatエントリー時のノーショナルに対する Net PnL の割合。
MFEfloatトレード存続期間中の最大順行幅——決済前に一度でも到達した最良の含み益。
MAEfloatトレード存続期間中の最大逆行幅——決済前の最悪の含み損。
Cumulative PnLfloat先頭行から現在のエグジット行までの Net PnL の累積和。

Trade #

往復の ID。ピラミディングでは同じ番号が 3 行以上続くこともあります。番号で束ねて読んでください。

Type

4 値だけ。ホールド行はありません。

Net PnL

エグジット行だけに意味があります。エントリー側は空かゼロ扱い。

MFE / MAE

保有中に見た最有利・最不利の含み損益。ストップの置き方を見るのに便利です。

読み方

Trade # でグループ化するのが基本。ファイル順は約定時刻順なので、別トレードのエグジットが先に出ることもあります。

pandas で読む

import pandas as pd
 
def load_trades(path: str) -> pd.DataFrame:
    df = pd.read_csv(path)
 
    # Parse timestamps; UTC, no tz suffix in the file
    df["Date and time"] = pd.to_datetime(df["Date and time"], utc=True)
 
    entries = df[df["Type"].str.startswith("Entry")].copy()
    exits   = df[df["Type"].str.startswith("Exit")].copy()
 
    entries = entries.rename(columns={
        "Date and time": "entry_dt",
        "Price":         "entry_price",
        "Qty":           "entry_qty",
        "Type":          "direction",
    })
    entries["direction"] = entries["direction"].str.replace("Entry ", "")
 
    exits = exits.rename(columns={
        "Date and time": "exit_dt",
        "Price":         "exit_price",
        "Net PnL":       "net_pnl",
        "Net PnL %":     "net_pnl_pct",
        "MFE":           "mfe",
        "MAE":           "mae",
    })
 
    # Join on Trade # (take last exit for pyramiding strategies)
    exits_agg = exits.groupby("Trade #").last().reset_index()
    entries_agg = entries.groupby("Trade #").first().reset_index()
 
    trades = entries_agg.merge(exits_agg[
        ["Trade #", "exit_dt", "exit_price", "net_pnl", "net_pnl_pct", "mfe", "mae"]
    ], on="Trade #")
 
    return trades
 
 
if __name__ == "__main__":
    trades = load_trades("engine_trades.csv")
    print(trades[["Trade #", "direction", "entry_dt", "exit_dt", "net_pnl", "mfe", "mae"]]
          .head(10)
          .to_string(index=False))
    print(f"\nTotal trades: {len(trades)}")
    print(f"Win rate:     {(trades['net_pnl'] > 0).mean():.1%}")
    print(f"Avg MFE:      {trades['mfe'].mean():.4f}")
    print(f"Avg MAE:      {trades['mae'].mean():.4f}")

よくある落とし穴

Net PnL はエグジットだけ。 行単位で足すと壊れます。

Cumulative PnL は建玉を含まない。 最後にポジションが残っていれば JSON の open_equity を見る。

時刻は UTC。 pd.to_datetime(..., utc=True) が安全。

行順とトレード順は一致しない。

他エンジンとの突合せ

TV エクスポートとベース列は同じ。MFE/MAE はプランによる。PineForge は常に出力。

次に読むなら

  • ギャラリー — 公開バックテスト 167 本。カードから「Download trades CSV」が使える場合があります。
  • MCPbacktest_pine はスタンドアロン Docker と同じ JSON を返します。CSV を書き出さず一覧解析も可能です。