공개 WebSocket 피드에 연결하고 Polymarket에서 가격이 잘못 책정된 토큰을 발견했습니다

발행: (2026년 3월 19일 오전 07:35 GMT+9)
7 분 소요
원문: Dev.to

Source: Dev.to

위에 제공된 링크 외에 번역할 텍스트가 포함되어 있지 않습니다. 번역을 원하는 본문을 알려주시면 한국어로 번역해 드리겠습니다.

개요

두 개의 WebSocket 피드를 연결했습니다: 하나는 Polymarket의 15분 암호화폐 시장을 정산하는 Chainlink 오라클에, 또 다른 하나는 Polymarket 주문서에 연결했습니다. 두 피드를 나란히 관찰한 결과 일관된 지연이 발견되었습니다. 오라클은 1초 미만에 업데이트되는 반면, 주문서는 동일한 움직임을 반영하는 데 약 55 초가 걸립니다. 거의 1분에 가까운 시간 동안 토큰은 오래된 데이터에 머물게 됩니다. 정산 소스는 공개되어 있어 누구나 연결할 수 있으며, 정산 대상 시장보다 거의 1분 앞서 지속적으로 작동합니다. 이는 버그가 아니라 시장이 작동하는 방식이지만, 이렇게 깔끔하게 측정할 수 있는 경우는 드뭅니다.

전략

핵심 논리는 간단합니다:

  1. 매 오라클 가격 틱마다 세 가지 조건을 확인합니다:

    • 가격이 시장 개시 시점 대비 > 0.07 % 이동했는지
    • 남은 시간이 > 5 분인지
    • 토큰 가격이 < $0.62인지
  2. 세 조건 모두 충족되면, 저가 측을 매수하고 정산을 기다린 뒤 $1을 회수합니다 (또는 스테이크를 잃을 수 있습니다).

흥미로운 점은 전략 자체가 아니라 이를 안정적으로 실행하도록 만든 것이었습니다.

Source:

Implementation

Architecture

단일 프로세스가 열려 있는 WebSocket을 통해 초단위 업데이트를 수신하고, 16개의 겹치는 시장을 추적하며, 매 틱마다 신호를 평가하고, 가격 피드를 차단하지 않고 주문을 실행하고, Telegram 알림을 전송하며, 충돌 복구를 위해 상태를 영구 저장하고, 자체 건강 상태를 모니터링합니다—모두 동시에 수행됩니다.

asyncio가 명백한 선택이었습니다: 거의 CPU 작업이 없고, 모든 것이 I/O‑바운드이기 때문입니다. 하나의 이벤트 루프에서 7개의 동시 작업이 실행됩니다:

tasks = [
    oracle.run(shutdown),
    market_lifecycle_loop(...),
    signal_evaluation_loop(...),
    telegram.run(shutdown),
    state_persist_loop(...),
    redeem_loop(...),
    sanity_check_loop(...),
]
await asyncio.gather(*tasks)

스레드도, 락도, 멀티프로세싱도 없습니다.

Handling Zombie WebSocket Connections

가장 까다로운 버그는 좀비 WebSocket이었습니다: 연결은 살아 있었고 ping/pong은 정상 작동했으며 예외도 발생하지 않았지만, 가격 데이터가 조용히 흐르지 않게 된 것이었습니다. 심장박동 프레임은 계속 도착했기 때문에 단순히 recv 타임아웃을 설정해도 도움이 되지 않았습니다.

해결책: 단조 시계(monotonic clock)를 사용해 마지막 실제 가격 업데이트 시점을 추적하고, 매 타임아웃마다 이를 확인합니다. 설정한 임계값 내에 실제 데이터가 도착하지 않으면 연결을 종료하고 강제로 재연결합니다.

Verifying External Credentials

또 다른 미묘한 문제: 봇은 시작되었고 로그는 완벽해 보였지만, 20분이 지나면 Telegram 채팅 ID가 잘못되어 모든 알림이 조용히 실패했습니다.

해결책: 메인 루프에 들어가기 전에 모든 외부 자격 증명을 검증합니다:

# Verify Telegram
telegram.get_me()
telegram.send_message(test_chat_id, "test")
# Verify Polymarket API keys
polymarket.verify_keys()

무언가 잘못되면 봇은 첫 2초 이내에 명확한 오류와 함께 종료됩니다. 예시:

ERROR: Telegram chat_id=123456 is invalid.
Tip: send any message to @your_bot first, then use getUpdates to find your chat_id.

백테스트 결과

  • 평가된 시장: 8,876개의 해결된 시장
  • 가격 포인트: 146,000
  • 플래그된 거래: 5,017
  • 승률: BTC, ETH, XRP, SOL 전반에 걸쳐 61.4 %

나는 시스템을 깨기 위해 날짜 분할, 파라미터 그리드 서치, 수수료 두 배, 일일 분해 등 일곱 가지 다른 방법을 시도했다. 그 중 어느 것도 시스템을 파괴하지 못했지만, 실제 환경은 더 어려울 것이다: 주문서가 얇아지고, 슬리피지가 커지며, 시간이 지남에 따라 지연이 감소한다. 이것은 은퇴 계획이 아니다.

오픈 소스

전체 프로젝트는 오픈 소스이며, API 키 없이 실시간 데이터와 페이퍼 트레이드에 연결되는 데모 모드를 포함합니다.

https://github.com/JonathanPetersonn/oracle-lag-sniper

협업 요청

비슷한 실시간 asyncio 시스템을 구축한 경험이 있다면, 구조를 어떻게 설계했는지 알려주세요. 이 “많은 동시 장기 실행 작업이 상태를 공유하는” 패턴은 흔한 것 같지만, 이를 구현하면서 좋은 오픈‑소스 참고 자료를 찾지 못했습니다.

0 조회
Back to Blog

관련 글

더 보기 »

파일 시스템이 디버깅하기 어려운 이유

동기 부여 나는 파일 시스템을 처음부터 구축하고 있다—필요해서가 아니라, 보이지 않는 것을 디버깅하는 것이 추측에 불과하기 때문이다. 파일 시스템을 이해하는 l...

블루 틱이 표시된 메시지, 그러나 도착하지 않음

소개 WhatsApp에서 메시지가 전달 및 읽음으로 표시되지만 AI 에이전트가 해당 메시지를 전혀 확인하지 못한다면, 이는 무음 메시지 손실 문제입니다. 이 기사에서는 이러한 문제에 대한 전문적인 해결책을 제시합니다.