레퍼런스

engine_trades.csv 형식 읽기

PineForge가 내보내는 트레이드 목록 CSV 완전 레퍼런스. 열별 의미, 트레이드 페어 인코딩, pandas로 불러오는 30줄 내외 Python 스니펫.

약 5분 읽기#docs#csv#engine

PineForge 백테스트는 JSON 요약과 함께 engine_trades.csv를 남깁니다. 엔진이 본 모든 fill을 행 단위로 적은 원장—진입·청산·수량·PnL·트레이드 내 최대 유리/불리 폭입니다. 이 글은 각 열이 정확히 무엇을 뜻하는지 한국어로 짚는 참조이며, 왕복을 재구성하거나 패리티 diff를 할 때 헷갈리지 않게 하려는 목적입니다.

파일이 하는 일

engine_trades.csv는 한 번의 백테스트가 끝난 뒤의 표 형식 트레이드 목록입니다. 각 행은 한 번의 fill—포지션 진입이나 청산. Trade #로 진입과 청산을 묶어 왕복을 복원합니다.

형식은 TradingView «List of Trades» 내보내기를 의도적으로 닮았습니다. 차이는 PineForge가 항상 MFEMAE를 넣는다는 점—TV는 Premium에서만 해당 열을 줍니다. 나머지 헤더는 맞춰 두었습니다.

열별 설명

열 이름은 TradingView 내보내기와 줄 단위 diff를 맞추기 위해 영어로 둡니다. 설명만 한국어입니다.

ColumnType설명
Trade #정수왕복 트레이드 ID. 진입과 청산이 같은 번호를 공유.
Type문자열Entry long / Exit long / Entry short / Exit short 중 하나.
Date and timeUTCYYYY-MM-DD HH:MM. 타임존 접미사 없음.항상 UTC.
Pricefloat체결 시점의 fill 가격(호가 통화).
Qtyfloat체결 수량. 항상 양수.방향은 Type.
Net PnLfloat해당 청산 거래의 손익.청산 행에만. 진입 행은 비었거나 0.
Net PnL %float진입 노셔널 대비 Net PnL 비율.
MFEfloat트레이드 생애 중 최대 유리 excursion——청산 전 도달한 최선의 미실현 이익.
MAEfloat트레이드 생애 중 최대 불리 excursion——청산 전 최악의 미실현 손실.
Cumulative PnLfloat첫 행부터 현재 청산 행까지의 Net PnL 누적합.

Trade #

왕복 ID. 피라미딩이면 같은 번호가 두 줄 이상 나올 수 있습니다. 이 키로 묶어 읽으세요.

Type

네 가지 문자열만. 홀드 행은 없습니다.

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.

행 순서 ≠ 트레이드 순서.

크로스 엔진

TV 내보내기와 기본 헤더는 같습니다. MFE/MAE는 TV 플랜에 따라 없을 수 있고 PineForge는 항상 냅니다.

다음 단계

  • 갤러리 — 공개 백테스트 167개. 카드에서 «Download trades CSV» 사용 가능할 때 다운로드.
  • MCPbacktest_pine은 단독 Docker와 같은 JSON을 돌려줍니다. CSV를 디스크에 쓰지 않고 목록 분석 가능.