한산 시간대 복원 매수 — 미 동부 새벽·주말에 뉴스 없이 발생한 가격 이탈(dislocation)을 복원 방향으로 매수한다.
quiet = UTC 06–13시 ([start, end)) or 주말(토/일 UTC) # 아니면 사이클 전체 skip
median = median(최근 24h YES 스냅샷)
dev = p_yes_now − median
ENTER iff quiet
AND |dev| ≥ 0.05 # 유의미한 이탈
AND avg(vol24h, 3h) < 1.5 × avg(vol24h, 24h) # 거래량 급증 = 진짜 뉴스 → 배제
AND 매수 토큰 가격 ∈ [0.30, 0.90]
방향: dev < 0 → YES 매수(반등 기대) · dev > 0 → NO 매수(페이드)Polymarket 참여자 대다수는 미국 시간대의 인간이다. UTC 06:00-13:00(미 동부 01-08시)와 주말에는 orderbook이 얇아지고, 정보가 아닌 유동성 요인만으로도 가격이 밀린다. 주의(attention)가 없는 시간의 가격 변화는 "정보"가 아니라 "노이즈"일 확률이 높고, 노이즈는 평균으로 회귀한다. 반대로 거래량이 급증하며 움직이는 가격은 진짜 뉴스일 가능성이 크므로 거래량 급증 시장은 배제한다.
레포 리서치(golden-cherry/docs/polymarket-strategy-momentum.md 계열)의 "10%+ 급변은 mean-revert" — 단기 과잉 이동의 회귀 성향은 이 레포에서 반복적으로 확인된 관찰이다. Night Watch는 그 회귀를 "정보가 없는 시간대"로 한정해 신호 대 잡음비를 높인다. 구조적 우위도 있다: 봇은 Jenkins로 24/7, 3-5분 간격으로 돈다. 사람은 이 시간대에 깨어있을 수 없다 — 이 전략은 그 인프라 우위를 정면으로 수익화한다.
기존 봇(STRATEGY_ANALYSIS.md)에서 배운 교정도 반영했다: banana의 스냅샷 "개수" 기반 윈도우 → timestamp 기반 윈도우 + 커버리지 검증(is_window_valid), 과도하게 관대한 cold-start 폴백 → invalid 윈도우면 백필 시도 후에도 부족하면 진입 안 함, cherry/banana의 condition_id당 영구 1회 거래 → 재진입 쿨다운(기본 24h), 해결된 시장의 영구 HOLDING 좀비 → EXPIRED 마감 + 수동 redeem 경고, take_profit 목표가 1.0 초과 → 0.99 캡, LOG_LEVEL env 지원, Gamma 전량 sweep 2회/사이클 → 1회(Phase 0/2 공유), 그리고 트레일링 스탑이 손절을 사실상 대체하는 whipsaw → 빠른 회전 전략이므로 trailing 자체를 제거.
모든 조건을 충족해야 매수한다.
| # | 조건 | 값 (기본) | 이유 |
|---|---|---|---|
| 1 | 한산 시간대 | UTC quiet.hours_utc(기본 06-13시, [start, end)) 또는 주말(토/일 UTC, quiet.weekends=true일 때). 사이클당 1회 판정 — 아니면 스캔 전체 skip | 주의 희소 구간에서만 노이즈 가설이 성립 |
| 2 | 유동성 / 시간 | liquidity ≥ $15,000 · 해결까지 ≥ 24h (min_volume_24h는 기본 0=비활성) | 체결 가능성 + 복원 시간 확보 |
| 3 | 편차 | 24h 스냅샷(YES 가격)의 median(statistics.median) 대비 |현재 YES 가격 − median| ≥ 0.05 | 유의미한 이탈만 선별 |
| 4 | 뉴스 배제 | 최근 3h 스냅샷의 volume24hr 평균 < 24h 윈도우 평균 × 1.5 | 급증 = 진짜 뉴스 → skip |
| 5 | 복원 방향 | dev < 0 → YES 매수(반등 기대), dev > 0 → NO 매수(페이드, 매수가는 실제 NO 가격 outcomePrices[1] 기준) | 복원 방향으로만 베팅 |
| 6 | 가격 밴드 | 매수할 토큰 가격 ∈ [0.30, 0.90] (양끝 포함) | 극단 가격의 왜곡 배제 |
| 7 | 윈도우 유효성 | 포인트 ≥ 5개 AND 커버 시간 ≥ lookback의 50%. 부족하면 prices-history 백필 후 재평가, 그래도 부족하면 진입 안 함 | 데이터 없이는 베팅하지 않는다 |
| 8 | 재진입 쿨다운 | HOLDING 존재, 24h 내 COMPLETED 청산, 24h 내 skip 기록 중 하나라도 있으면 skip | 과잉 재진입 방지 |
매수 실행 직전 CLOB midpoint로 재검증한다: 가격이 밴드 상한(0.90) 초과면 rapid_jump로 skip 기록(쿨다운 동안만 차단 — 기존 봇의 영구 밴 아님), 하한(0.30) 미만이면 기록 없이 skip.
우선순위 순으로 매 사이클 검사한다.
| 순위 | 조건 | 파라미터 | exit_reason |
|---|---|---|---|
| 1 | P&L ≤ -6% | stop_loss_percent=-0.06 | stop_loss |
| 2 | 현재가 ≥ min(매수가 × 1.06, 0.99) | take_profit_percent=0.06 | take_profit |
| 3 | 보유 ≥ 24h (복원 실패 → 회전) | max_holding_hours=24 | max_holding |
| 4 | 해결까지 < 12h | exit_hours=12 | time_exit |
| - | midpoint 조회 실패 + endDate 24h 경과 | - | resolved_unredeemed (status=EXPIRED, 수동 redeem 필요) |
trailing stop 없음 — 목표 수익폭(+6%)이 작은 빠른 회전 전략이라, trailing이 손절을 대체해버리는 cherry/banana의 whipsaw 문제를 원천 차단한다.
우선순위: 환경변수 > config.yaml > 코드 기본값.
| env | yaml 키 | 기본값 | 의미 |
|---|---|---|---|
POLYBOT_QUIET_HOURS_UTC | trading.quiet.hours_utc | "6-13" | 진입 허용 UTC 시간대. 자정 넘는 "22-4" 지원 |
POLYBOT_QUIET_WEEKENDS | trading.quiet.weekends | true | 주말(토/일 UTC) 전체 진입 허용 |
POLYBOT_MEDIAN_LOOKBACK_HOURS | trading.signal.median_lookback_hours | 24 | median 계산 윈도우 (시간) |
POLYBOT_DEV_MIN | trading.signal.dev_min | 0.05 | 최소 편차 |현재가 − median| |
POLYBOT_VOL_SPIKE_BLOCK | trading.signal.vol_spike_block | 1.5 | 거래량 급증 차단 배수 |
POLYBOT_ENTRY_PROB_MIN | trading.signal.entry_prob_min | 0.30 | 매수 토큰 가격 하한 |
POLYBOT_ENTRY_PROB_MAX | trading.signal.entry_prob_max | 0.90 | 매수 토큰 가격 상한 |
POLYBOT_ENTRY_HOURS_MIN | trading.time_based.entry_hours_min | 24 | 해결까지 최소 잔여 시간 |
POLYBOT_MAX_HOLDING_HOURS | trading.time_based.max_holding_hours | 24 | 최대 보유 시간 |
POLYBOT_EXIT_HOURS | trading.time_based.exit_hours | 12 | 해결 N시간 전 청산 |
POLYBOT_TAKE_PROFIT | trading.take_profit_percent | 0.06 | 익절 (+6%, 목표가 0.99 캡) |
POLYBOT_STOP_LOSS | trading.stop_loss_percent | -0.06 | 손절 (-6%) |
POLYBOT_BUY_AMOUNT | trading.buy_amount_usdc | 5.0 | 1회 매수 USDC |
POLYBOT_MIN_LIQUIDITY | trading.min_liquidity | 15000 | 최소 유동성 $ |
POLYBOT_MIN_VOLUME_24H | trading.min_volume_24h | 0 | 최소 24h 거래량 $ (0=비활성) |
POLYBOT_MAX_POSITIONS | trading.max_positions | -1 | 최대 동시 포지션 (-1=무제한) |
POLYBOT_REENTRY_COOLDOWN_HOURS | trading.reentry_cooldown_hours | 24 | 재진입 쿨다운 |
POLYBOT_HISTORY_BACKFILL | trading.history_backfill | true | prices-history 백필 |
POLYBOT_EXCLUDED_CATEGORIES | trading.excluded_categories | "" | 제외 카테고리 (comma 구분, 기본 비활성) |
LOG_LEVEL | - | INFO | 로그 레벨 (--verbose가 최우선) |
POLYBOT_QUIET_HOURS_UTC로 조정 가능하지만 가정 자체는 검증 대상이다.uv run python main.py run --simulate --job sim-test를 Jenkins에 3-5분 간격으로 등록. data/sim-test/trades_sim.db에 기록 축적.POLYBOT_BUY_AMOUNT=5 수준으로 실전 전환. 다른 골든 봇들과 동일한 대시보드 계정 체계(GOLDEN-HONEYDEW)로 잔고 추적.exit_reason 분포: max_holding 비중이 50%를 넘으면 복원 가설 자체가 약한 것deviation_at_buy 버킷별(0.05-0.07 / 0.07-0.10 / 0.10+) 승률 비교로 dev_min 조정, deviation_at_exit로 복원 완료/미완료 청산 구분strategy_name("honeydew") / mode("live"/"sim") / volume_24h_at_buy로 UNION 쿼리 (A/B 포스트모템 공통 계약)#!/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_QUIET_HOURS_UTC="6-13" export POLYBOT_DEV_MIN=0.05 export POLYBOT_MAX_HOLDING_HOURS=24 cd ./golden-honeydew uv sync uv run python ./main.py run
3-5분 간격 cron 트리거를 권장한다. 한산 시간대(UTC 06-13시/주말)가 아니면 봇이 스스로 진입 스캔을 skip하므로 24시간 내내 돌려도 된다 (스냅샷 축적을 위해 오히려 계속 돌려야 한다).