ํ๋ฅ 85~97% ๊ตฌ๊ฐ์ ๊ณ ํ๋ฅ outcome์, ์์ฒด ์ถ์ ํ 5๋ถ ์ค๋ ์ท ๊ธฐ๋ฐ momentum์ด ์์น ์ค์ผ ๋๋ง ๋งค์ํ๋ golden cross ์ ๋ต.
momentum = (์ต์ ํ๋ฅ - ๊ฐ์ฅ ์ค๋๋ ํ๋ฅ ) / ์ค๋
์ท ์ # 5๋ถ ์ฃผ๊ธฐ ์์ฒด ์ค๋
์ท, ๋์ ๊ธฐ์ธ๊ธฐ
short = momentum(์ต๊ทผ 3๊ฐ โ 15๋ถ), long = momentum(์ต๊ทผ 72๊ฐ โ 6์๊ฐ)
BUY : 0.85 โค p โค 0.97 (์ํ ํฌํจ)
AND ( short - long โฅ +0.02 AND long > 0 # golden cross
OR ์ค๋
์ท < 6๊ฐ AND short > 0 ) # cold-start fallback
SELL: p โฅ 0.97 โ P&L โค -10% โ P&L โฅ +7% โ short - long โค -0.02 (dead cross)Golden Banana๋ Polymarket์์ ํ๋ฅ 85~97% ๊ตฌ๊ฐ์ ๊ณ ํ๋ฅ outcome์ "๋ชจ๋ฉํ
์ด ์์น ์ค์ผ ๋๋ง" ๋งค์ํ๋ momentum ์ ๋ต ๋ด์ด๋ค. ๊ตฌ๋ฒ์ (golden-apple ๊ณ์ด)์ "80% ๋งค์ โ 90% ๋งค๋" ์ ์ ์๊ณ๊ฐ ์ ๋ต์ ๊ฐ์ ํ ๊ฒ์ผ๋ก, 5๋ถ ์ฃผ๊ธฐ์ Jenkins ์คํ๋ง๋ค ์ ์ฒด ์์ฅ ํ๋ฅ ์ SQLite market_snapshots ํ
์ด๋ธ์ ์์ฒด ์ถ์ ํ๊ณ , ์ด ์ค๋
์ท์ผ๋ก ๋จ๊ธฐ(15๋ถ=3 ์ค๋
์ท)ยท์ฅ๊ธฐ(6์๊ฐ=72 ์ค๋
์ท) momentum์ ๊ณ์ฐํด golden cross(๋จ๊ธฐ-์ฅ๊ธฐ โฅ +2%p/์ค๋
์ท) ๋ฐ์ ์ ์ง์
ํ๋ค.
์ฒญ์ฐ์ 4์ค ์กฐ๊ฑด(ํ๋ฅ 97% ๋๋ฌ, ์ง์ ๊ฐ ๋๋น +7% ์ด์ต์คํ, -10% ์์ , dead cross)์ผ๋ก ๋ค๋ณํํ๋ค. ์ฃผ๋ฌธ์ CLOB v2์ midpoint ๊ฐ๊ฒฉ์ GTC limit order๋ก ์คํ๋๋ฉฐ, ํ ๋ฒ ๊ฑฐ๋ํ ์์ฅ์ ์๊ตฌํ ์ฌ๊ฑฐ๋ํ์ง ์๋๋ค.
๊ฐ๊ฒฉ ์ด๋ ฅ ์์ง โ ํต์ฌ ๋ฉ์ปค๋์ฆ: ์ธ๋ถ price-history API๋ฅผ ์ฐ์ง ์๊ณ ๋ด์ด ์ค์ค๋ก ์ด๋ ฅ์ ๋ง๋ ๋ค. ๋งค ์ฌ์ดํด Phase 0์์ Gamma ์ ๋ ์กฐํ(100๊ฐ์ฉ ํ์ด์ง๋ค์ด์
, offset โฅ 5,000 ์์ ํ๋) ํ min_liquidity ์ด์ + ๋น์คํฌ์ธ ์์ฅ๋ง๋ค ๋์ ์ชฝ ํ๋ฅ ์ market_snapshots์ 1ํ INSERT(์ค์ธก ๋ก๊ทธ ๊ธฐ์ค ์ฌ์ดํด๋น ์ฝ 30~35ํ). ํ๋จ ์ ์ต์ 82๊ฐ(long_window+10)๋ฅผ ์กฐํํ๋ฉฐ, ์ค๋
์ท ๊ฐ๊ฒฉ = Jenkins cron ๊ฐ๊ฒฉ(5๋ถ ๊ฐ์ )์ด์ง๋ง timestamp ๊ฐ๊ฒฉ์ ๊ฒ์ฆํ์ง ์๊ณ ๊ฐ์ ๊ธฐ๋ฐ ์๋์ฐ๋ง ์ฌ์ฉํ๋ค. 7์ผ ์ง๋ ์ค๋
์ท์ Phase 4์์ ์ญ์ .
momentum ๊ณ์ฐ: (์ต์ ํ๋ฅ - ๊ฐ์ฅ ์ค๋๋ ํ๋ฅ ) / len(snapshots) โ ์ด๋ํ๊ท (MA) cross๊ฐ ์๋๋ผ ์ ๋์ ๊ธฐ์ธ๊ธฐ(rate of change) ๋น๊ต๋ค. ๋จ๊ธฐ๋ ์ต๊ทผ 3๊ฐ(3๊ฐ ๋ฏธ๋ง์ด๋ฉด ์ง์
๋ถ๊ฐ), ์ฅ๊ธฐ๋ ์ต๊ทผ 72๊ฐ(72๊ฐ ๋ฏธ๋ง์ด์ด๋ 6๊ฐ ์ด์์ด๋ฉด ์๋ ๋งํผ ์ฌ์ฉ, 6๊ฐ ๋ฏธ๋ง์ด๋ฉด None). ์ฅ๊ธฐ๊ฐ None์ด๋ฉด cold-start fallback์ผ๋ก ๋จ๊ธฐ momentum > 0 ๋ง์ผ๋ก ์ง์
์ ํ์ฉํ๋ฉฐ(short_momentum_positive), ์ค์ด์ ๋ก๊ทธ(20260205)์์ ์ค์ ๋งค์๋ ์ ๋ถ ์ด ๊ฒฝ๋ก์๋ค.
๋งค์ ํ์ดํ๋ผ์ธ โ ์กฐ๊ฑด ์ ๋ถ AND, ์์๋๋ก:
| # | ์กฐ๊ฑด | ๋น๊ณ |
|---|---|---|
| 1 | liquidity โฅ 50,000 | Gamma ์ ๋ ์กฐํ์์ ํํฐ |
| 2 | ์คํฌ์ธ ์๋ | tags + question/slug ํ
์คํธ์ SPORTS_KEYWORDS(์ฝ 50๊ฐ; "game", "match", "win the", "beat", "score" ๋ฑ) ์์ด์ผ ํจ |
| 3 | favorite ์ ํ | outcomePrices ๋ ๊ฐ ์ค ํฐ ์ชฝ + token_id ์กด์ฌ. Yes/No ์ค ๋์ ์ชฝ์ ์ฐ๋ค |
| 4 | 0.85 โค p โค 0.97 | ์ํ ํฌํจ |
| 5 | momentum ์ง์ ์๊ทธ๋ | golden_cross ๋๋ cold-start short_momentum_positive (momentum ๋นํ์ฑ ์ ๋ฌด์กฐ๊ฑด ํต๊ณผ) |
| 6 | ๋ฏธ๊ฑฐ๋ ์์ฅ | trades/skipped_markets์ ์์ผ๋ฉด ์๊ตฌ skip |
| 7 | max_positions ์ ํ | ๊ธฐ๋ณธ -1(๋ฌด์ ํ) |
| 8 | CLOB midpoint ์ฌ๊ฒ์ฆ | > 0.97 โ rapid_jump ์๊ตฌ skip / < 0.85 โ ์ด๋ฒ ์ฌ์ดํด๋ง skip |
| 9 | ์๋ = buy_amount รท midpoint โฅ 5์ฃผ | ์ต์ ์ฃผ๋ฌธ ์๋ |
| 10 | GTC limit BUY @ midpoint | 0.01 tick ๋ฐ์ฌ๋ฆผ, [0.01, 0.99] clamp. orderID ์๋ต ์ ์ฆ์ HOLDING ๊ธฐ๋ก(์ฒด๊ฒฐ ํ์ธ ์์). entry_reasonยทmomentum ๊ฐ ์ ์ฅ |
๋งค๋ ํ์ดํ๋ผ์ธ โ ๋ณด์ ํฌ์ง์ ๋ง๋ค ๋งค ์ฌ์ดํด, ์ฐ์ ์์ ์:
| ์ฐ์ ์์ | ์กฐ๊ฑด | exit_reason |
|---|---|---|
| 1 | CLOB midpoint โฅ 0.97 (sell_threshold) | threshold |
| 2 | (ํ์ฌ๊ฐ-์ง์ ๊ฐ)/์ง์ ๊ฐ โค -0.10 | stop_loss |
| 3 | โฅ +0.07 | take_profit |
| 4 | short - long โค -0.02 (์ค๋ ์ท ์ถฉ๋ถํ ๋๋ง) | dead_cross |
momentum ๋นํ์ฑ ์์๋ 2ยท3๋ง ๊ฒ์ฌ. ๋งค๋ ์ฃผ๋ฌธ๋ ํ์ฌ midpoint ๊ฐ๊ฒฉ GTC limit SELL์ด๋ฉฐ, ์ ์ ์ฆ์ COMPLETED + realized_pnl = (๋งค๋๊ฐ-๋งค์๊ฐ)ร์๋ ๊ธฐ๋ก. exit_reasonยท๋งค๋ ์์ momentum ๊ฐ ์ ์ฅ.
ํ๋ผ๋ฏธํฐ ์ดํ (์ฐ์ ์์: env var > config.yaml > ์ฝ๋ ๊ธฐ๋ณธ๊ฐ)
| ํ๋ผ๋ฏธํฐ | yaml ๊ฐ | ์ฝ๋ ๊ธฐ๋ณธ๊ฐ | env var | ์๋ฏธ |
|---|---|---|---|---|
buy_threshold | 0.85 | 0.85 | POLYBOT_BUY_THRESHOLD | ๋งค์ ์ต์ ํ๋ฅ |
sell_threshold | 0.97 | 0.97 | POLYBOT_SELL_THRESHOLD | ๋งค์ ์ํ์ด์ ํ๋ฅ ๊ธฐ์ค ๋งค๋ ํธ๋ฆฌ๊ฑฐ |
buy_amount_usdc | 5.0 | 10.0 | POLYBOT_BUY_AMOUNT | 1ํ ๋งค์ ๊ธ์ก (USDC) |
min_liquidity | 50000 | 50000.0 | POLYBOT_MIN_LIQUIDITY | ์ต์ ์ ๋์ฑ ํํฐ ($) |
max_positions | -1 (๋ฌด์ ํ) | -1 | POLYBOT_MAX_POSITIONS | ๋์ ๋ณด์ ํฌ์ง์ ์ํ |
take_profit_percent | 0.07 | 0.07 | POLYBOT_TAKE_PROFIT | ์ง์ ๊ฐ ๋๋น ์ด์ต์คํ (+7%) |
stop_loss_percent | -0.10 | -0.10 | POLYBOT_STOP_LOSS | ์ง์ ๊ฐ ๋๋น ์์ (-10%) |
momentum.enabled | true | true | POLYBOT_MOMENTUM_ENABLED | momentum ํํฐ on/off |
momentum.short_window | 3 | 3 | POLYBOT_MOMENTUM_SHORT_WINDOW | ๋จ๊ธฐ ์๋์ฐ (3 ์ค๋ ์ท โ 15๋ถ) |
momentum.long_window | 72 | 72 | POLYBOT_MOMENTUM_LONG_WINDOW | ์ฅ๊ธฐ ์๋์ฐ (72 ์ค๋ ์ท โ 6์๊ฐ) |
momentum.golden_cross_threshold | 0.02 | 0.02 | POLYBOT_GOLDEN_CROSS_THRESHOLD | ์ง์ : ๋จ๊ธฐ-์ฅ๊ธฐ โฅ ์ด ๊ฐ |
momentum.dead_cross_threshold | -0.02 | -0.02 | POLYBOT_DEAD_CROSS_THRESHOLD | ์ฒญ์ฐ: ๋จ๊ธฐ-์ฅ๊ธฐ โค ์ด ๊ฐ |
momentum.require_positive_long_momentum | true | true | POLYBOT_REQUIRE_POSITIVE_LONG_MOMENTUM | golden cross์ฌ๋ ์ฅ๊ธฐ momentum โค 0์ด๋ฉด ์ง์ ๊ฑฐ๋ถ |
excluded_categories | Sports ๊ณ์ด 10์ข | ๋์ผ | (env ์์) | ์ ์ธ ์นดํ ๊ณ ๋ฆฌ |
simulation_mode | false | false | (CLI --simulate๋ก๋ง override) | ์ค์ฃผ๋ฌธ ์ฌ๋ถ |
(์์) MIN_ORDER_SIZE | - | 5.0 | - | ์ต์ ์ฃผ๋ฌธ ์๋ 5์ฃผ |
(์์) DEFAULT_TICK_SIZE | - | 0.01 | - | ๊ฐ๊ฒฉ tick ๋ฐ์ฌ๋ฆผ, [0.01, 0.99] clamp |
ํ์ credential์ POLYMARKET_PRIVATE_KEYยทPOLYMARKET_FUNDER_ADDRESS(์์ผ๋ฉด ์ฆ์ ์ข
๋ฃ, private key์ hex prefix๋ ์๋ ์ ๊ฑฐ). SLACK_WEBHOOK_URL์ ํ์ฌ ์ฌ์ดํด์ ๋ฏธ์ฐ๊ฒฐ.
momentum.py ํ ๊ณณ์ ์์ด sibling ๋ด์์ ์ด ํ์ผ๋ง ๊ต์ฒดํ๋ฉด ๋๋ค (golden-cherry๊ฐ ์ค์ ๋ก ์ด ๋ฐฉ์์ผ๋ก ํ์๋จ).entry_reason/exit_reason/momentum ์ปฌ๋ผ์ผ๋ก ์ฌํ ์ ๋ต ๋ถ์(SQL)์ด ๊ฐ๋ฅ.execute_sell ์๊ตฌ ์คํจ. ์จ์ฒด์ธ redeem์ด ๋์ด๋ DB realized_pnl ๋ฏธ๋ฐ์์ผ๋ก ํต๊ณ ์๊ณก.condition_id๋น ํ์ 1ํ. rapid_jump๋ก ํ ๋ฒ skip๋๋ฉด ์๊ตฌ ์ฐจ๋จ โ ์๊ฐ์์ง๋ฆฌ ์์ฅ์ ์ ๋นํ ์ฌ์ง์
๊ธฐํ ์์ค.max_positions=-1 + ๊ณ ์ 5 USDC. ์๊ณ ํ์ธยท์ผ์ผ ๋งค์ ํ๋ยท๋ณ๋์ฑ ๊ธฐ๋ฐ sizing ์์.scripts/simulate.py DB ๊ฒฝ๋ก ๋ฒ๊ทธ: sim ๊ฑฐ๋๊ฐ trades_sim.db๊ฐ ์๋ ํด๋น job์ trades.db์ ๊ธฐ๋ก๋๋ค (polybot run --simulate๋ ์ ์).DataAPIClientยทSlackNotifier๋ dead code, data_api_client์ User-Agent๊ฐ GoldenApple-PolyBot/1.0์ผ๋ก ์์กด, excluded_categories๋ env override ์์.โ ์๋ฎฌ๋ ์ด์
: polybot run --simulate๋ ์ค๊ฑฐ๋์ ๋์ผ ๊ฒฝ๋ก์์ ์ฃผ๋ฌธ๋ง mock(trades_sim.db ๋ถ๋ฆฌ). ๋จ, midpoint 100% ์ฒด๊ฒฐ ๊ฐ์ ์ด๋ผ sim P&L์ ๋๊ด ํธํฅ(์ฝ์ 14)์ด ์๊ณ , scripts/simulate.py๋ DB ๊ฒฝ๋ก ๋ฒ๊ทธ(์ฝ์ 12)๊ฐ ์์ผ๋ฏ๋ก --simulate ํ๋๊ทธ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ๋ค. โก ์์ก ์ค๊ฑฐ๋: yaml buy_amount_usdc: 5.0์ผ๋ก ๊ฑด๋น ๋
ธ์ถ ์ ํ. โข ํ๋จ ํ ์ฆ์ก: ๋งค ์ฌ์ดํด ๋ก๊ทธ์ momentum ๋ถ์ ์์ฝ ํ(์ง์
/์ ์ธ ์ฌ์ , ๋จ๊ธฐ/์ฅ๊ธฐ diff, ์ค๋
์ท ์)์ entry_reason/exit_reason ์ปฌ๋ผ ์ง๊ณ๋ก "golden cross ๊ฒฝ๋ก ๋๋น cold-start ๊ฒฝ๋ก"์ ์ค์ ์ ๋น๊ตํด ์๊ณ๊ฐ ์ฌ๋ณด์ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค.
# Jenkins cron (5๋ถ ์ฃผ๊ธฐ, one-shot โ ๋ด ๋ด๋ถ ๋ฃจํ ์์)
cd ./golden-banana
export POLYMARKET_PRIVATE_KEY=<Jenkins credential>
export POLYMARKET_FUNDER_ADDRESS=<Jenkins credential>
uv sync --frozen
uv run polybot run # ์ํ๋ data/{job}/trades.db ์ ๊ฒฉ๋ฆฌ