Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Hedge Lab — delta-neutral funding arbitrage across 7 perpetual venues
A research and execution-support tool for delta-neutral funding arbitrage. It normalises live
funding rates from seven perpetual venues, finds pairs where the same asset pays materially
different funding on two of them, and sizes the position against the constraint that actually
binds.
Live demo: — the dashboard is open to everyone; the
scanner, ranking, position and journal screens ask for a Telegram sign-in.README 전문 보기 ↗A research and execution-support tool for delta-neutral funding arbitrage. It normalises live funding rates from seven perpetual venues, finds pairs where the same asset pays materially different funding on two of them, and sizes the position against the constraint that actually binds.
Live demo: https://hedge-lab-demo.vercel.app — the dashboard is open to everyone; the scanner, ranking, position and journal screens ask for a Telegram sign-in.
A perpetual future pays funding — a periodic transfer between longs and shorts that keeps the contract near spot. Venues arrive at different rates for the same asset. Long one, short the other, and price movement cancels: the position is delta-neutral and the funding difference is the return.
Finding those pairs is easy. Deciding which are actually tradeable is not.
| Venue | Funding interval | Rate published as | Leverage cap derived from |
|---|---|---|---|
| Variational | 4h / 8h per asset | annualised, RFQ-quoted | not published (RFQ model) |
| Ethereal | 1h | hourly | maxLeverage |
| Nado | 1h | x18 fixed-point | long_weight_initial_x18 → 1/(1−w) |
| Lighter | 1h settlement | 8h-equivalent rate | min_initial_margin_fraction → 10000/f |
| Lighter (Robinhood Chain) | 1h | same | same |
| Aster | 1h / 2h / 4h / 8h per symbol | per-interval | requiredMarginPercent → 100/pct |
| edgeX | 4h | per-interval | riskTierList[0].maxLeverage |
Get any of these wrong and you get a plausible-looking number that is off by 8×. Aster alone
publishes four different intervals across its symbols, so the interval must be read per symbol
from /fundingInfo or every APR on that venue is wrong. Verifying Lighter's convention against
Hyperliquid's hourly rate gave a ratio of exactly 8.000 — the published rate is 8h-equivalent
even though settlement is hourly.
An eighth venue, Phoenix (Solana), is wired in as a Variational cross only — it is not in
the combined matrix. It ticks hourly, fundingRate × 87.6 gives the annual percentage
(calibrated against Hyperliquid), and its public API has no 24h volume, so that column shows
open interest instead.
Raw spread is a poor signal alone. Three derived columns encode what the measurements showed:
Rés (gap) — the price difference between venues, not the funding difference. A
delta-neutral round's basis P&L is exactly the change in this number while the position is open.
On thin books it moves further in an hour than the funding pays in a day, which makes it the
binding constraint rather than the spread.
Egyirány (aligned) — whether the gap and the funding pull the same way: does the funding
want you to short the more expensive leg? When aligned, a narrowing gap pays on top of the
carry. When opposed, they fight. Two live rounds on consecutive days, same method, differing
only in this flag: +$12.73 and −$4.61.
Ítélet (verdict) — reads each venue's own measured history rather than the current tick:
| meaning | |
|---|---|
⇄ | reversed — the 7-day average points the opposite way. One asset read −703.9% average against +1914.3% current, and turned back within hours |
⚠ | spike — far above its own average; it will revert |
✓ | structural — 72h+ in one direction, safe to size against the average |
~ | young — a real direction, under three days old |
Funding series span orders of magnitude — one asset ran between 11% and −17520% with most readings sitting at 11%. On a linear axis one spike sets the range and everything else collapses onto the zero line. The vertical axis is symlog: linear near zero, logarithmic further out, negatives handled, unit set per series from its own median absolute value.
Six screens, plus a deep dive that opens from any row:
Sign-in is optional for whoever deploys it, and the app behaves differently in each case:
| Dashboard, deep dive | Pairs Scanner, Best Pairs, Gap Watch, Position, History | Where state lives | |
|---|---|---|---|
| No Telegram bot configured | open | open | server memory, one shared session |
| Bot configured, visitor not signed in | open | behind a sign-in card | — |
| Signed in | open | open | Supabase, per Telegram account |
A signed-in user's configuration, open round (entry price, entry gap, opening time, funding accrued so far) and journal are stored per account, so a round follows them between devices and survives a restart.
The gate is in the page, not in the API: the market-data endpoints below stay public. Journal writes are the exception — the server refuses them without a session.
The repository ships 99 hourly snapshots taken 16–20 August 2026 across ~700 pairs. Each snapshot holds funding rate and price per venue per symbol. Nothing else is recorded.
While it runs, the server adds at most one snapshot per hour, taken when a scan runs, and
keeps 30 days. With Supabase configured each snapshot is also written to a shared
lab_snapshot table and read back on boot.
Two consequences:
GET / → landing page (overview, conventions, signals)
GET /app → the app
GET /api/scan → full computed scanner payload (cached 60 s)
GET /api/dive/<symbol> → per-asset detail, series, book depth (?leg=<usd>)
GET /api/series/<symbol> → that asset's series from the stored history only
GET /api/archive → days that have snapshots
GET /api/archive/<day> → that day's hourly snapshots
GET /api/me → whether sign-in is enabled and who is signed in
npm start # http://localhost:8879
No API keys, no database, no build step, no dependencies. Node 18+. Without any environment
variables there is no sign-in, nothing is gated, and everything — settings, open round,
journal — lives in memory and resets on restart. PORT changes the port.
One service, one domain. The same Node process serves the landing page (/), the app
(/app) and the API, so there is no second origin, no CORS and no proxy layer.
Vercel serverless landing + app + API
Supabase free project users, journal, settings, history, login (recommended on Vercel)
Telegram login only one "signed in" reply per login (optional, needs Supabase)
server.js runs two ways from the same code: locally it starts a real, always-on
http.createServer (node server.js); on Vercel, api/index.js re-exports the same
request handler as a serverless function, and vercel.json rewrites every path — /,
/app, /api/* — to it, so the whole app stays on one origin without a second service or a
proxy layer. The rewrite passes the original path along as ?__p=…, because Vercel hands
the function the rewrite target rather than the path the visitor asked for.
The tradeoff of serverless is state. A serverless function has no persistent memory between requests — a different one (or a fresh cold start) can serve the next call. Concretely, on Vercel:
/api/scan request may land on
a cold instance and re-run the full venue fetch (~5s) instead of hitting a warm
60-second cache. Slower under load, never broken.None of this needs any setup to deploy — vercel deploy or connecting the repo on
vercel.com works with zero configuration. Every environment
variable below is optional and the server degrades cleanly without them, which is also
what makes git clone && npm start work locally with zero setup.
| Variable | Effect when unset |
|---|---|
SUPA_URL, SUPA_KEY | everything falls back to memory (unreliable on Vercel, fine locally). SUPA_KEY is the service key; it stays on the server |
TG_BOT_TOKEN, TG_BOT_NAME | no sign-in and no gate; the app is fully usable anonymously |
SESSION_SECRET | random per boot — on Vercel, set this explicitly, or every cold start invalidates existing sessions |
Set the Telegram variables only together with the Supabase ones. The sign-in flow stores its one-time codes in Supabase, so a bot without a database switches the gate on with no way through it.
For persistence, run schema.sql once in the Supabase SQL editor. Row-level
security is on with no policies, so only the server's service key can reach the tables.
render.yaml is also in the repo: a persistent Node server has none of the tradeoffs
above, at the cost of a real server to run. It works standalone if you'd rather use it.
Sign-in goes through the bot's deep link. Telegram's Login Widget stopped working in
September 2026 — its oauth.telegram.org/auth popup now answers deprecated — so the
button it drew led nowhere.
t.me/<bot>?start=<code> link./start <code> to the bot's webhook, which records who pressed
it and replies with a one-line confirmation.Setup:
schema.sql in Supabase (it creates the login_nonce table).TG_BOT_TOKEN, TG_BOT_NAME, SESSION_SECRET and the Supabase variables on Vercel.https://<your-domain>/api/tg/setup once. It registers
https://<your-domain>/api/tg/webhook with Telegram and prints Telegram's answer.What keeps it honest:
The old widget callback (/api/auth/telegram, HMAC-SHA256 over the sorted fields keyed by
SHA256(bot_token)) is still in the code but nothing calls it any more.
This is a public demo built from a private system that trades real capital. Nothing here can place an order: there are no private keys, no signing and no exchange credentials anywhere in the code. The optional wallet field takes a public address and only reads that address's open positions on Nado and Lighter, to compare them with the round you are tracking. The private system's own trade history is not part of this repository, and every journal starts empty.
Advisory only. Not financial advice.