🍇

golden-grape — Cascade Rider

정보 폭포 편승 — "소폭이지만 일관된 24h 드리프트 + 거래량 가속"이 확인된 시장에 편승해, 정보가 대중 전체에 확산되기 전 구간의 추가 이동을 수확한다.

유형 편승상태 신규 · 검증 대기핵심 편향 정보 폭포 · 과소반응

핵심 수식

# 매수 토큰 기준 가격 p (YES 상승 드리프트 → YES 매수, YES 하락 → NO 매수)
drift_24h = p_now − p_24h_ago
ENTER iff 0.40 ≤ p_now ≤ 0.80
      AND +0.04 ≤ drift_24h ≤ +0.10            # 소폭·일관 드리프트만 (10%+는 mean-revert)
      AND nonneg_buckets(4h 버킷 × 6) ≥ 70%    # 버킷 일관성 게이트
      AND vol24h_now ≥ 1.2 × avg(vol24h, 24h)  # 거래량 가속 게이트

왜 이 전략인가

예측시장 참가자는 동시에 정보를 얻지 않는다. 정보에 가까운 소수가 먼저 베팅하면 가격이 소폭 움직이고, 그 가격 변화 자체가 신호가 되어 나머지 대중이 뒤따라 베팅한다(정보 폭포, information cascade). 이 확산이 완료되기 전까지 가격은 새 정보를 부분적으로만 반영한 상태이므로, 초기 드리프트에 편승하면 잔여 이동을 수확할 수 있다. 반대로 급격한 대형 움직임은 이미 확산이 끝났거나 과잉반응이므로 편승 가치가 없다.

레포 공유 리서치(docs/polymarket-strategy-momentum.md, banana/cherry 레포)는 "2-3% 일일 변화는 같은 방향으로 추가 이동할 확률이 6-8% 상승(가장 강한 모멘텀)", "10%+ 일일 변화는 모멘텀 약화, 평균회귀 가능성 높음"을 보고한다. grape의 드리프트 밴드 [+0.04, +0.10]은 이 발견을 그대로 구현한 것이다 — 하한 0.04는 노이즈(±1~2%p 일상 변동)를 걸러내고, 상한 0.10은 mean-revert 영역을 배제한다.

또 하나의 축은 banana 골든크로스 전략 실패의 교정이다. banana STRATEGY_ANALYSIS.md에서 확인된 실패 원인 5가지를 grape는 다음과 같이 고쳤다.

#banana의 실패 원인grape의 교정
1도달 불가 threshold: golden cross 임계값 0.02가 "스냅샷당 기울기" 단위여서 15분에 약 6%p 급등해야 발화 — 실로그 diff는 ±0.007 이하로 사실상 무전략으로 퇴화임계값을 윈도우 전체 변화량(%p)으로 재정의. 24h에 +4~10%p는 리서치가 실측한, 실제로 도달 가능한 밴드
2count 기반 윈도우: "최신 N개 스냅샷"이라 Jenkins 중단 시 "15분 윈도우"가 몇 시간을 커버해도 그대로 계산timestamp 기반 윈도우(ts ≥ now − 24h) + 커버리지 검증(포인트 ≥ 5개 AND 커버 시간 ≥ lookback의 50%)
3관대한 cold-start 폴백: 스냅샷 6개 미만이면 "단기 momentum > 0"만으로 진입 — 실운영 매수의 전부가 이 우회 경로폴백 제거. invalid → /prices-history 백필 시도 → 그래도 invalid면 진입하지 않는다
4양 끝점 2개 값만 사용: 끝점 노이즈에 민감, 중간 경로 무시버킷 일관성 게이트: 24h를 4h 버킷 6개로 나눠 70% 이상이 비음(≥ 0) 변화여야 진입
5확인 신호 부재: 가격 기울기 하나로만 판단거래량 가속 게이트: volume24hr가 24h 평균의 1.2배 이상 — "가격이 오르는데 거래량도 붙는다"는 이중 확인

기존 봇 공통 버그도 함께 수정했다: 영구 one-shot 거래 제한 → 24h 쿨다운 재진입, rapid_jump 영구 skip → timestamp 기반 skip, 해결된 시장의 HOLDING 영구 잔류 → EXPIRED 처리, take_profit 도달 불가 → 목표가 0.99 캡, LOG_LEVEL env 지원.

진입 규칙

모든 조건 AND. 드리프트 방향 토큰 기준 가격 p로 판정한다.

#조건값 (기본)이유
1유동성 / 거래량 / 잔여시간liquidity ≥ $20,000 · volume24hr ≥ $10,000 · 해결까지 ≥ 48h신호 신뢰성 + 러닝룸 확보
2윈도우 유효성24h 윈도우 포인트 ≥ 5개, 커버리지 ≥ 12h. invalid면 /prices-history 백필 시도, 그래도 invalid면 진입 금지banana 교정 #2, #3 — 데이터 없이는 베팅하지 않는다
3방향 결정YES 상승 드리프트 → YES 매수, YES 하락(= NO 상승) → NO 매수. 이하 조건은 매수 토큰 기준Polymarket에 숏 없음
4가격 밴드p ∈ [0.40, 0.80]러닝룸 있는 중간 구간
524h 드리프트+0.04 ≤ (현재가 − 24h 전 가격) ≤ +0.10리서치: 소폭 모멘텀 지속, 10%+ 회귀
6일관성4h 버킷 6개 중 ≥ 70%가 비음(≥ 0) 변화. 판정 가능 버킷이 절반 미만이면 데이터 부족으로 진입 금지banana 교정 #4 — 끝점 노이즈 배제
7거래량 가속현재 volume24hr ≥ 24h 윈도우 평균의 1.2배banana 교정 #5 — 정보 확산의 이중 확인
8재진입HOLDING 없음 + 마지막 청산/skip 후 24h 경과영구 one-shot 제거

매수 직전 CLOB midpoint로 재검증한다: 밴드 상한(0.80) 초과 급등이면 skip(rapid_jump, 쿨다운 후 재평가), 하한(0.40) 미만 하락이면 이번 사이클만 skip.

청산 규칙

우선순위 순으로 매 사이클 검사한다.

순위조건exit_reason
1손절P&L ≤ -8%stop_loss
2익절현재가 ≥ min(진입가 × 1.15, 0.99)take_profit
3드리프트 소멸최근 6h 매수 토큰 가격 변화 ≤ 0 (포인트 2개 미만이면 판단 보류)drift_death
4트레일링 스탑최고가 대비 -6%trailing_stop
5시간 청산해결까지 < 24htime_exit
-해결 시장midpoint 조회 실패 + end_date 24h 경과 → EXPIRED 마감 (수동 redeem 필요)resolved_unredeemed

파라미터 (환경변수)

우선순위: env > config.yaml > 코드 기본값.

전략 파라미터

env var기본값의미
POLYBOT_PROB_MIN0.40매수 토큰 가격 하한
POLYBOT_PROB_MAX0.80매수 토큰 가격 상한
POLYBOT_DRIFT_LOOKBACK_HOURS24드리프트 판정 윈도우 (h)
POLYBOT_DRIFT_MIN0.04드리프트 하한 (+4%p)
POLYBOT_DRIFT_MAX0.10드리프트 상한 (mean-revert 배제)
POLYBOT_BUCKET_HOURS4일관성 버킷 크기 (h)
POLYBOT_CONSISTENCY_MIN0.70비음 버킷 비율 하한
POLYBOT_VOL_ACCEL_MIN1.2거래량 가속 배수 하한
POLYBOT_DEATH_WINDOW_HOURS6드리프트 소멸 판정 윈도우 (h)
POLYBOT_ENTRY_HOURS_MIN48해결까지 최소 잔여시간 (h)
POLYBOT_EXIT_HOURS24시간 청산 기준 (h)
POLYBOT_TRAILING_STOP_ENABLEDtrue트레일링 스탑 on/off
POLYBOT_TRAILING_STOP_PERCENT0.06트레일링 스탑 %

공통 파라미터 (전 봇 동일 이름)

env var기본값의미
POLYBOT_BUY_AMOUNT5.01회 매수 USDC
POLYBOT_MIN_LIQUIDITY20000최소 유동성 $
POLYBOT_MIN_VOLUME_24H10000최소 24h 거래량 $
POLYBOT_TAKE_PROFIT0.15익절 % (목표가 0.99 캡)
POLYBOT_STOP_LOSS-0.08손절 %
POLYBOT_MAX_POSITIONS-1최대 동시 포지션 (-1 무제한)
POLYBOT_REENTRY_COOLDOWN_HOURS24재진입 쿨다운 (h)
POLYBOT_HISTORY_BACKFILLtrueprices-history 백필
POLYBOT_EXCLUDED_CATEGORIES""제외 카테고리 (comma 구분, 기본 비활성)
LOG_LEVELINFO로그 레벨

이 전략이 실패하는 경우

A/B 검증 계획

-- 검증 쿼리 (data/{job}/trades.db) — status는 enum 이름으로 저장됨 (COMPLETED/EXPIRED)
SELECT exit_reason, COUNT(*) cnt, ROUND(AVG(realized_pnl), 4) avg_pnl,
       SUM(CASE WHEN realized_pnl > 0 THEN 1 ELSE 0 END) * 1.0 / COUNT(*) win_rate
FROM trades WHERE status = 'COMPLETED' GROUP BY exit_reason;

실행 (Jenkins)

#!/bin/bash
export POLYBOT_BUY_AMOUNT=20
export POLYMARKET_PRIVATE_KEY=<Jenkins credential>
export POLYMARKET_FUNDER_ADDRESS=<Jenkins credential>
export LOG_LEVEL=INFO
# 전략 파라미터 예시 (선택)
export POLYBOT_DRIFT_MIN=0.04
export POLYBOT_CONSISTENCY_MIN=0.70
export POLYBOT_VOL_ACCEL_MIN=1.2

cd ./golden-grape
uv sync
uv run python ./main.py run

3~5분 주기 cron 트리거를 권장한다 (스냅샷 축적 주기 = 드리프트 판정 해상도).