engine_trades.csv フォーマットを読み解く
PineForgeが出力するトレード一覧CSVの完全リファレンス。列の意味、ペアのエンコード、pandasに載せる30行程度のPythonスニペット。
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 しやすいよう英語のままです。説明だけ日本語にします。
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 は常に出力。