Files
PineSript/Analysis
2026-10-20 17:57:28 +09:00
..
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00
2026-10-20 17:57:28 +09:00

Analysis 프로젝트

Pine Script 트레이딩 전략의 파라미터 최적화 도구. Data 폴더의 SQLite .db 캔들 데이터를 읽어 PineScript 엔진(PineScriptV6)으로 전략을 실행하고, 4개 파라미터 조합별 월간/연간 수익률을 계산한다.


1. 프로젝트 개요

.db 캔들 데이터 → PineScript 엔진 실행 → 시그널 수집 → 수익률 계산 → 콘솔/CSV 출력
  • 대상 전략: Script/example.pine — SMA4 밴드 + 일목균형표 구름대 + 횡보(브레이크아웃) 감지 전략
  • 최적화 대상 파라미터 4개:
변수 기본값 역할 중요도
lengthWindow 12 longRatio 계산 시 최근 N봉 최저가 참조 창 ★★
rangePeriod 240 longRatio의 SMA 기간 → Long 진입 임계값 결정 ★★★
shortLengthWindow 4 shortRatio 계산 시 최근 N봉 최고가 참조 창 ★★
shortRangePeriod 40 shortRatio의 SMA 기간 → Short 진입 임계값 결정 ★★★

2. 폴더 구조

Analysis/
├─ Analysis.csproj
├─ appsettings.json          ← 설정 (DB 경로, 대상 종목, 파라미터 범위)
├─ Program.cs                ← 커맨드 라우팅 + 결과 출력
├─ CandleDbReader.cs         ← .db 파일 탐색/필터/로드
├─ GridSearchRunner.cs       ← 조합 생성, 순차 실행, 파라미터 치환
├─ ProfitCalculator.cs       ← 거래 매칭, 월/연 수익률 집계
├─ Script/
│   └─ example.pine          ← 분석 대상 Pine Script 전략
├─ Tools/
│   ├─ CandleDbWriter.cs     ← 공통 DB 저장 (Saver와 동일 스키마)
│   ├─ TvCsvImporter.cs      ← TradingView CSV → .db 변환
│   └─ BitgetDownloader.cs   ← Bitget API → .db 다운로드
└─ Results/
    └─ grid_results.csv      ← grid 실행 시 생성

데이터 폴더 구조

c:\data\{거래소}\{종목유형}\{종목}\{연도}_{타임프레임}.db
예: c:\data\Bitget\USDT-FUTURES\XRPUSDT\2025_30m.db

현재 보유 데이터 (TradingView BITGET:XRPUSDT.P CSV에서 변환):

파일 캔들 수 기간
2025_30m.db 17,520개 2025-01-01 ~ 2025-12-31
2026_30m.db 7,610개 2026-01-01 ~ 2026-06-08

3. 실행 방법

cd C:\ProjetCode\PineSript
dotnet run --project Analysis -- <커맨드>

Visual Studio: Analysis를 시작 프로젝트로 설정 → Properties → Debug → Command line arguments 입력 → F5

커맨드 목록

커맨드 설명 예시
grid 그리드 서치 (기본) — appsettings.json 범위의 모든 조합 실행 Analysis grid
test [LW] [RP] [SLW] [SRP] 단일 파라미터 테스트 — 연간/월별/개별 거래 내역 상세 출력 Analysis test 12 240 4 40
import-csv <CSV경로> [타임프레임] TradingView CSV → .db 변환 Analysis import-csv "C:\Downloads\XRPUSDT.csv" 30m
download [타임프레임] [최대일수] Bitget API에서 캔들 다운로드 Analysis download 30m 62

출력 형식 (test / grid Top 10 공통)

── LW=12  RP=240  SLW=4  SRP=40 ──
  총 수익률: XX.XX%  |  거래: N건 (승 X / 패 Y)  |  승률: Z%

  [ 연간 수익률 ]
    년도    수익률%    거래    승    패   승률%
  [ 월별 수익률 ]
    년-월    수익률%    거래    승    패   승률%
  [ 개별 거래 내역 ]   ← test 모드에서만
    #  방향   진입시간   청산시간   진입가   청산가   수익%

4. 설정 — appsettings.json

{
  "Analysis": {
    "DbFolder": "c:/data",                      // 캔들 DB 루트 폴더
    "ScriptPath": "./Script/example.pine",      // 분석 대상 Pine Script
    "OutputCsv": "./Results/grid_results.csv",  // grid 결과 저장 경로
    "WarmupBars": 300,                          // 지표 안정화용 워밍업 봉 수

    "Target": {
      "Exchange": "Bitget",
      "ProductType": "USDT-FUTURES",
      "Symbol": "XRPUSDT"
    },

    "Parameters": {
      "lengthWindow":      { "Min": 4,  "Max": 24,  "Step": 4  },   // 6개
      "rangePeriod":       { "Min": 60, "Max": 480, "Step": 60 },   // 8개
      "shortLengthWindow": { "Min": 2,  "Max": 12,  "Step": 2  },   // 6개
      "shortRangePeriod":  { "Min": 10, "Max": 80,  "Step": 10 }    // 8개
    }
  }
}

현재 범위 기준 조합 수: 6 × 8 × 6 × 8 = 2,304개


5. 소스코드 구성

Program.cs

  • 커맨드 라우팅 (grid / test / import-csv / download)
  • LoadTargetCandles() — DB 탐색 → 필터 → 로드 → 시간순 정렬 (grid/test 공통)
  • PrintDetailedResult() — 연간/월별/개별거래 테이블 출력
  • SaveResultsCsv() — 총 수익률 + 월간 상세 + 연간 상세 3개 섹션으로 CSV 저장 (데이터 기간 헤더 포함)

CandleDbReader.cs

  • FindAllDbFiles() — {거래소}/{종목유형}/{종목}/*.db 3단계 구조 재귀 탐색 (루트 직속 .db도 호환 수집)
  • Filter() — 거래소/종목유형/종목 필터 (대소문자 무시)
  • LoadAll() — 캔들 전체 로드. WAL 모드 DB를 ReadOnly로 열면 오류가 나므로 ReadWrite로 열고 PRAGMA journal_mode=DELETE 전환 (트러블슈팅 §8 참고)

GridSearchRunner.cs

  • GenerateCombinations() — 4중 루프로 모든 파라미터 조합 생성
  • RunAll() — 조합별 순차 실행. PineScript 엔진이 static 기반이라 멀티스레드 불가 → 순차 실행
  • 실행 흐름: Regex로 파라미터 치환 → 임시 .pine 파일 생성 → PineScriptExecutor 실행 → TradingSignal.Results 수집 → 임시 파일 삭제
  • 치환 패턴: ^(lengthWindow\s*=\s*)\d+ (Multiline) — 4개 변수 동일 방식
  • 10개 조합마다 진행률/ETA 출력

ProfitCalculator.cs

  • MatchTrades() — 시그널 순회하며 Buy→Sell (Long), Short→Cover (Short) 쌍 매칭
  • 수익률 공식: 롱 (청산가-진입가)/진입가×100, 숏 (진입가-청산가)/진입가×100
  • 월간/연간 집계는 청산 시각(ExitTime) 기준 그룹화
  • 총 수익률 = 개별 거래 수익률의 단순 합산

Tools/CandleDbWriter.cs

  • Saver 프로젝트와 동일 스키마로 저장:
    CREATE TABLE candles (
        open_time INTEGER PRIMARY KEY,   -- Unix milliseconds
        open REAL, high REAL, low REAL, close REAL, volume REAL
    );
    
  • 연도별로 파일 분리 ({year}_{interval}.db, 1m은 {year}.db)
  • ON CONFLICT(open_time) DO UPDATE — 중복 시 덮어쓰기 (upsert)

Tools/TvCsvImporter.cs

  • TradingView 내보내기 CSV 파싱 → CandleDbWriter로 저장
  • 시간 포맷 자동 감지: Unix seconds / Unix milliseconds(13자리 이상) / ISO 8601 / 커스텀 포맷
  • 헤더 컬럼 자동 매핑 (time/timestamp/date, open, high, low, close, volume)

Tools/BitgetDownloader.cs

  • Bitget REST API 2개 엔드포인트 조합:
    • /api/v2/mix/market/candles — 최근 캔들 최대 1,000건 (30분봉 기준 약 20일)
    • /api/v2/mix/market/history-candles — 요청당 200건 페이징
  • 30분봉 기준 현실적 최대 약 62일
  • 레이트 리밋 100ms 간격, 중복 제거 후 저장

6. Pine Script 전략 분석

핵심 아이디어

isSidewaysLong / isSidewaysShort는 이름과 달리 "횡보를 벗어나는 순간(브레이크아웃)" 을 감지한다. 즉, "평소보다 변동폭이 커지면 진입을 허용" 하는 구조.

변수 흐름

■ Long 측
longRatio = (high - ta.lowest(low, lengthWindow)) / ta.lowest(low, lengthWindow) * 100
            └ 매 봉의 "현재 상승폭 비율" (최근 12봉 최저가 대비)

rangeThresholdLongPercent = ta.sma(longRatio, rangePeriod)
            └ 240봉(30분봉 기준 5일) 평균 변동폭 = "보통 변동폭" 기준선

isSidewaysLong = priceRangeLong > (lowestLow × rangeThresholdLongPercent / 100)
                 and sma4 > 구름대 상단

■ Short 측 (동일 구조, 더 짧은 창)
shortRatio = (ta.highest(high, shortLengthWindow) - low) / ta.highest(high, shortLengthWindow) * 100
rangeThresholdShortPercent = ta.sma(shortRatio, shortRangePeriod)   // 40봉 ≈ 20시간

isSidewaysShort = priceRangeShort > (highestHigh × rangeThresholdShortPercent / 100)
                  and sma4 < 구름대 상단
  • Short 창이 Long보다 짧은 이유: 하락이 상승보다 빠르기 때문 — 기준선이 더 빠르게 변해야 함
  • 고정 임계값(과거의 rangeThresholdPercent = 2, 1.7)이 아니라 시장 상황에 따라 기준선이 자동으로 변함:
    • 변동성 큰 시기 → 기준 상승 → 진입 까다로움
    • 조용한 시기 → 기준 하락 → 작은 움직임에도 진입 허용

예시 계산

high = 2.10, 최근 12봉 최저가 = 2.00
→ longRatio = (2.10 - 2.00) / 2.00 × 100 = 5.0%

최근 240봉의 longRatio 평균이 3.3%라면
→ 현재 가격 움직임이 3.3%를 넘는 순간 브레이크아웃 → 롱 진입 허용

기타 변수

변수 값 비고
rangeLookback 12 현재 가격범위(highestHigh − lowestLow) 측정 창. 그리드서치 대상 아님 (★ 보조)
rangeThresholdPercent 2 미사용 — 예전 고정 임계값, ta.sma 동적 계산으로 대체됨
rangeShortThresholdPercent 1.7 미사용 — 동일

진입/청산 조건 (요약)

  • 롱 진입: 12봉 최고가 갱신 + 양봉 + 최근 10봉 내 sma4Low 터치 + isSidewaysLong + sma4 상승 + sma4Middle > sma72 + 구름대 위
  • 롱 청산: sma4Middle이 sma72 하향 돌파 또는 sma4 == sma4Low
  • 숏 진입: 구름대 아래 + sma4 < sma72 + isSidewaysShort 등 2가지 OR 조건
  • 숏 청산: sma4High ≤ sma4 또는 sma4 > sma72 등 4가지 OR 조건
  • 상태 변수 inLong / inShort로 중복 진입 방지

7. 데이터 수집 방법

방법 A — TradingView CSV (권장, 1년치 이상 가능)

  1. TradingView(Premium)에서 BITGET:XRPUSDT.P 30분봉 차트 열기
    • .P = Perpetual(무기한 선물) = Bitget USDT-FUTURES XRPUSDT와 동일 계약
    • Premium은 30분봉 최대 20,000개 바 (약 416일) 제공
  2. 차트 우클릭 → 테이블 보기 → CSV 다운로드
    • 시간 포맷: Unix Timestamp 권장 (ISO도 자동 감지되지만 Unix가 시간대 혼동 없음)
  3. 변환 실행:
    dotnet run --project Analysis -- import-csv "C:\Downloads\BITGET_XRPUSDT.csv" 30m
    

방법 B — Bitget API 직접 다운로드 (최대 약 62일)

dotnet run --project Analysis -- download 30m 62

8. 트러블슈팅 이력

증상 원인 해결
SQLite Error 8: attempt to write a readonly database WAL 모드 DB를 SqliteOpenMode.ReadOnly로 열면 -shm 파일 생성이 필요해 실패 CandleDbReader에서 ReadWrite로 열고 PRAGMA journal_mode=DELETE 전환
SQLite Error 1: no such table: candles 이전 변환 과정에서 DB 파일 손상 (0바이트 / 불완전 데이터) CSV에서 재변환. journal_mode=DELETE로 생성, -wal/-shm 잔여 파일 정리
샌드박스 환경에서 SQLite disk I/O error 마운트 폴더에 직접 DB 생성 불가 /tmp에 먼저 생성 후 대상 폴더로 복사

9. 의존 프로젝트

  • PineScriptV6 — Pine Script 실행 엔진 (PineScriptExecutor, TradingSignal.Results, CandleData, TradeSignalEvent)
    • static 기반이므로 그리드서치는 순차 실행만 가능 (멀티스레드 불가)
  • Saver — 실시간 캔들 수집 프로젝트. CandleDbWriter가 동일한 DB 스키마/폴더 구조를 따름