mirror of
https://github.com/theodore-song/polymarket-analyst.git
synced 2026-07-27 16:07:46 +00:00
Add live money configuration setup
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
# Cloud state
|
||||||
|
BLOB_READ_WRITE_TOKEN=
|
||||||
|
PMA_STATE_PATH=shared/state.json
|
||||||
|
|
||||||
|
# Live-money feature gate
|
||||||
|
# Keep false until legal/compliance approval, provider credentials, wallet signing,
|
||||||
|
# payment rails, and audit logging are production-ready.
|
||||||
|
LIVE_TRADING_ENABLED=false
|
||||||
|
|
||||||
|
# Eligibility / compliance provider
|
||||||
|
KYC_PROVIDER=
|
||||||
|
KYC_API_KEY=
|
||||||
|
KYC_WEBHOOK_SECRET=
|
||||||
|
RESTRICTED_JURISDICTIONS=US,CA-NY,CA-ON
|
||||||
|
|
||||||
|
# Wallet / deposit-wallet provider
|
||||||
|
WALLET_PROVIDER=
|
||||||
|
WALLET_PROJECT_ID=
|
||||||
|
WALLET_API_KEY=
|
||||||
|
DEPOSIT_WALLET_ADDRESS=
|
||||||
|
POLYMARKET_SIGNATURE_TYPE=3
|
||||||
|
|
||||||
|
# Payments / deposits / withdrawals
|
||||||
|
PAYMENTS_PROVIDER=
|
||||||
|
PAYMENTS_API_KEY=
|
||||||
|
PAYMENTS_WEBHOOK_SECRET=
|
||||||
|
SETTLEMENT_ASSET=pUSD
|
||||||
|
SETTLEMENT_CHAIN=polygon
|
||||||
|
|
||||||
|
# Polymarket CLOB credentials
|
||||||
|
POLYMARKET_CLOB_HOST=https://clob.polymarket.com
|
||||||
|
POLYMARKET_CHAIN_ID=137
|
||||||
|
POLYMARKET_CLOB_API_KEY=
|
||||||
|
POLYMARKET_CLOB_SECRET=
|
||||||
|
POLYMARKET_CLOB_PASSPHRASE=
|
||||||
|
|
||||||
|
# Audit / monitoring
|
||||||
|
AUDIT_LOG_STORE=
|
||||||
|
ADMIN_ALERT_EMAIL=
|
||||||
|
RISK_ADMIN_WALLET=
|
||||||
@@ -3,3 +3,4 @@ node_modules/
|
|||||||
.vercel
|
.vercel
|
||||||
.claude/
|
.claude/
|
||||||
.env*
|
.env*
|
||||||
|
!.env.example
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
# 📊 Polymarket Analyst — standalone website
|
# Polymarket Analyst
|
||||||
|
|
||||||
A **single-file website**. Everything (fetching live Polymarket data, the
|
A Vercel-hosted Polymarket agent arena with shared paper-trading state, agent
|
||||||
analysis engine, and the ten AI paper-trading agents) runs in your browser. The
|
return charts, paper accounts, market browsing, and live-money readiness rails.
|
||||||
paper portfolio is saved in your browser's local storage. No server, no keys.
|
|
||||||
|
|
||||||
## Just look at it now
|
## Just look at it now
|
||||||
Double-click **`index.html`** — it opens in your browser and works immediately.
|
|
||||||
On first open it fetches live markets, generates today's suggestions, and the
|
Open the deployed site:
|
||||||
agents run a seven-day backtest, then begin live tracking. It auto-refreshes
|
|
||||||
once per day; the **Run cycle** button forces a refresh anytime.
|
https://polymarket-site-eta.vercel.app
|
||||||
|
|
||||||
|
The site fetches live Polymarket markets, generates agent suggestions, lets you
|
||||||
|
run hourly paper cycles, and syncs the shared arena state through the Vercel API
|
||||||
|
when `BLOB_READ_WRITE_TOKEN` is configured.
|
||||||
|
|
||||||
## Put it online (free) so you can reach it from any device
|
## Put it online (free) so you can reach it from any device
|
||||||
|
|
||||||
@@ -28,8 +31,20 @@ Pick one — all give you a public URL:
|
|||||||
1. <https://vercel.com> → Add New → Project → import this GitHub repo under the
|
1. <https://vercel.com> → Add New → Project → import this GitHub repo under the
|
||||||
`theodore_song` Vercel account (or use the `vercel` CLI in this folder) → Deploy.
|
`theodore_song` Vercel account (or use the `vercel` CLI in this folder) → Deploy.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Use `.env.example` as the setup template.
|
||||||
|
|
||||||
|
- `BLOB_READ_WRITE_TOKEN` enables cross-device shared state.
|
||||||
|
- `/api/live` reports whether KYC, payments, wallet/deposit-wallet, Polymarket
|
||||||
|
CLOB, audit, and monitoring providers are configured.
|
||||||
|
- `LIVE_TRADING_ENABLED` should stay `false` until legal review, provider setup,
|
||||||
|
wallet signing, reconciliation, and dry-run testing are complete.
|
||||||
|
- See `REAL_MONEY_ROADMAP.md` for the launch requirements before any real funds
|
||||||
|
or live order execution are enabled.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
- Paper trading only — no real money, nothing places real orders.
|
- Paper trading only right now — no real money, nothing places real orders.
|
||||||
- The analysis is a transparent heuristic, **not financial advice**.
|
- The analysis is a transparent heuristic, **not financial advice**.
|
||||||
- Because the portfolio lives in your browser, each browser/device keeps its
|
- The shared arena uses cloud state when configured. Individual paper accounts
|
||||||
own portfolio. Clearing site data resets it (so does the **Reset** button).
|
still use local browser storage unless a backend account database is added.
|
||||||
|
|||||||
+53
-1
@@ -4,6 +4,17 @@ This app is currently paper trading only. The Live Money tab and `/api/live`
|
|||||||
endpoint are readiness scaffolding: they make the required product and backend
|
endpoint are readiness scaffolding: they make the required product and backend
|
||||||
interfaces visible without moving funds or placing orders.
|
interfaces visible without moving funds or placing orders.
|
||||||
|
|
||||||
|
## What is configured now
|
||||||
|
|
||||||
|
- `.env.example` lists the environment variables the production app needs.
|
||||||
|
- `/api/live` reports which live-money providers are configured or missing.
|
||||||
|
- `/api/live` accepts order intents only as dry-runs and returns an audit event.
|
||||||
|
- The Live Money tab shows launch checks, wallet/deposit settings, agent risk
|
||||||
|
limits, a dry-run order console, and an audit preview.
|
||||||
|
|
||||||
|
The app still refuses to place live orders. That is intentional until the legal,
|
||||||
|
provider, wallet-signing, reconciliation, and monitoring steps below are done.
|
||||||
|
|
||||||
## Required before live deposits or trading
|
## Required before live deposits or trading
|
||||||
|
|
||||||
1. Legal and eligibility
|
1. Legal and eligibility
|
||||||
@@ -42,15 +53,56 @@ interfaces visible without moving funds or placing orders.
|
|||||||
|
|
||||||
## Environment variables expected by `/api/live`
|
## Environment variables expected by `/api/live`
|
||||||
|
|
||||||
|
Copy `.env.example` into your local environment for development, then add the
|
||||||
|
same variables in Vercel Project Settings -> Environment Variables for
|
||||||
|
production.
|
||||||
|
|
||||||
- `KYC_PROVIDER`
|
- `KYC_PROVIDER`
|
||||||
|
- `KYC_API_KEY`
|
||||||
|
- `KYC_WEBHOOK_SECRET`
|
||||||
- `PAYMENTS_PROVIDER`
|
- `PAYMENTS_PROVIDER`
|
||||||
|
- `PAYMENTS_API_KEY`
|
||||||
|
- `PAYMENTS_WEBHOOK_SECRET`
|
||||||
- `WALLET_PROVIDER`
|
- `WALLET_PROVIDER`
|
||||||
|
- `WALLET_PROJECT_ID`
|
||||||
|
- `WALLET_API_KEY`
|
||||||
|
- `DEPOSIT_WALLET_ADDRESS`
|
||||||
|
- `POLYMARKET_SIGNATURE_TYPE=3`
|
||||||
|
- `POLYMARKET_CHAIN_ID=137`
|
||||||
|
- `SETTLEMENT_ASSET=pUSD`
|
||||||
|
- `SETTLEMENT_CHAIN=polygon`
|
||||||
- `POLYMARKET_CLOB_API_KEY`
|
- `POLYMARKET_CLOB_API_KEY`
|
||||||
- `POLYMARKET_CLOB_SECRET`
|
- `POLYMARKET_CLOB_SECRET`
|
||||||
- `POLYMARKET_CLOB_PASSPHRASE`
|
- `POLYMARKET_CLOB_PASSPHRASE`
|
||||||
- `AUDIT_LOG_STORE`
|
- `AUDIT_LOG_STORE`
|
||||||
- `LIVE_TRADING_ENABLED=true`
|
- `ADMIN_ALERT_EMAIL`
|
||||||
|
- `LIVE_TRADING_ENABLED=true` only after final approval and end-to-end testing
|
||||||
|
|
||||||
Even when all variables are present, live order placement remains intentionally
|
Even when all variables are present, live order placement remains intentionally
|
||||||
unimplemented until wallet signing, compliance approval, and safe order routing
|
unimplemented until wallet signing, compliance approval, and safe order routing
|
||||||
are completed.
|
are completed.
|
||||||
|
|
||||||
|
## Polymarket integration notes
|
||||||
|
|
||||||
|
Polymarket's public docs describe trading as non-custodial. Orders are signed
|
||||||
|
and matched through the CLOB, and new API users generally use the deposit-wallet
|
||||||
|
flow with signature type `3`.
|
||||||
|
|
||||||
|
Useful official docs:
|
||||||
|
|
||||||
|
- Trading overview: https://docs.polymarket.com/trading/overview
|
||||||
|
- Trading quickstart: https://docs.polymarket.com/trading/quickstart
|
||||||
|
- Deposit wallets: https://docs.polymarket.com/trading/deposit-wallets
|
||||||
|
|
||||||
|
## Final setup checklist
|
||||||
|
|
||||||
|
1. Choose and contract the KYC / eligibility provider.
|
||||||
|
2. Choose the deposit and withdrawal provider.
|
||||||
|
3. Choose the wallet or embedded-wallet provider and create a deposit wallet.
|
||||||
|
4. Derive or create Polymarket CLOB credentials for the approved signing flow.
|
||||||
|
5. Create durable append-only audit storage.
|
||||||
|
6. Add all environment variables in Vercel.
|
||||||
|
7. Run dry-runs against `/api/live` and verify audit events.
|
||||||
|
8. Complete legal review, terms, restricted jurisdiction rules, and support
|
||||||
|
procedures.
|
||||||
|
9. Only then set `LIVE_TRADING_ENABLED=true`.
|
||||||
|
|||||||
+34
-3
@@ -1,11 +1,22 @@
|
|||||||
const REQUIRED_ENV = [
|
const REQUIRED_ENV = [
|
||||||
["KYC_PROVIDER", "KYC / eligibility provider"],
|
["KYC_PROVIDER", "KYC / eligibility provider"],
|
||||||
|
["KYC_API_KEY", "KYC provider API key"],
|
||||||
|
["KYC_WEBHOOK_SECRET", "KYC webhook secret"],
|
||||||
["PAYMENTS_PROVIDER", "Deposit and withdrawal provider"],
|
["PAYMENTS_PROVIDER", "Deposit and withdrawal provider"],
|
||||||
|
["PAYMENTS_API_KEY", "Payments provider API key"],
|
||||||
|
["PAYMENTS_WEBHOOK_SECRET", "Payments webhook secret"],
|
||||||
["WALLET_PROVIDER", "Wallet or deposit-wallet provider"],
|
["WALLET_PROVIDER", "Wallet or deposit-wallet provider"],
|
||||||
|
["WALLET_PROJECT_ID", "Wallet provider project ID"],
|
||||||
|
["WALLET_API_KEY", "Wallet provider API key"],
|
||||||
|
["DEPOSIT_WALLET_ADDRESS", "Polymarket deposit-wallet address"],
|
||||||
|
["POLYMARKET_SIGNATURE_TYPE", "Polymarket signature type"],
|
||||||
["POLYMARKET_CLOB_API_KEY", "Polymarket CLOB API key"],
|
["POLYMARKET_CLOB_API_KEY", "Polymarket CLOB API key"],
|
||||||
["POLYMARKET_CLOB_SECRET", "Polymarket CLOB API secret"],
|
["POLYMARKET_CLOB_SECRET", "Polymarket CLOB API secret"],
|
||||||
["POLYMARKET_CLOB_PASSPHRASE", "Polymarket CLOB passphrase"],
|
["POLYMARKET_CLOB_PASSPHRASE", "Polymarket CLOB passphrase"],
|
||||||
|
["SETTLEMENT_ASSET", "Settlement asset"],
|
||||||
|
["SETTLEMENT_CHAIN", "Settlement chain"],
|
||||||
["AUDIT_LOG_STORE", "Durable audit log store"],
|
["AUDIT_LOG_STORE", "Durable audit log store"],
|
||||||
|
["ADMIN_ALERT_EMAIL", "Admin alert destination"],
|
||||||
];
|
];
|
||||||
|
|
||||||
function providerStatus() {
|
function providerStatus() {
|
||||||
@@ -13,23 +24,43 @@ function providerStatus() {
|
|||||||
key,
|
key,
|
||||||
label,
|
label,
|
||||||
configured: Boolean(process.env[key]),
|
configured: Boolean(process.env[key]),
|
||||||
|
expected: key === "POLYMARKET_SIGNATURE_TYPE" ? "3 for new deposit-wallet API users" : undefined,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function liveTradingReady() {
|
function liveTradingReady() {
|
||||||
return providerStatus().every((x) => x.configured) && process.env.LIVE_TRADING_ENABLED === "true";
|
const requiredConfigured = providerStatus().every((x) => x.configured);
|
||||||
|
const liveFlagEnabled = process.env.LIVE_TRADING_ENABLED === "true";
|
||||||
|
const signatureTypeOk = String(process.env.POLYMARKET_SIGNATURE_TYPE || "") === "3";
|
||||||
|
const chainOk = String(process.env.POLYMARKET_CHAIN_ID || "137") === "137";
|
||||||
|
return requiredConfigured && liveFlagEnabled && signatureTypeOk && chainOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
function baseStatus() {
|
function baseStatus() {
|
||||||
const providers = providerStatus();
|
const providers = providerStatus();
|
||||||
|
const liveFlagEnabled = process.env.LIVE_TRADING_ENABLED === "true";
|
||||||
|
const signatureTypeOk = String(process.env.POLYMARKET_SIGNATURE_TYPE || "") === "3";
|
||||||
|
const chainOk = String(process.env.POLYMARKET_CHAIN_ID || "137") === "137";
|
||||||
|
const missing = providers.filter((x) => !x.configured).map((x) => x.label);
|
||||||
|
if (!liveFlagEnabled) missing.push("LIVE_TRADING_ENABLED=true after final approval");
|
||||||
|
if (!signatureTypeOk) missing.push("POLYMARKET_SIGNATURE_TYPE=3 for deposit-wallet users");
|
||||||
|
if (!chainOk) missing.push("POLYMARKET_CHAIN_ID=137");
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
live_trading_enabled: liveTradingReady(),
|
live_trading_enabled: liveTradingReady(),
|
||||||
|
live_flag_enabled: liveFlagEnabled,
|
||||||
|
signature_type_ok: signatureTypeOk,
|
||||||
|
chain_ok: chainOk,
|
||||||
locked_reason: liveTradingReady()
|
locked_reason: liveTradingReady()
|
||||||
? null
|
? null
|
||||||
: "Live trading is locked until KYC, payments, wallet signing, CLOB credentials, audit storage, and LIVE_TRADING_ENABLED=true are configured.",
|
: "Live trading is locked until eligibility, payments, wallet/deposit-wallet signing, Polymarket CLOB credentials, audit storage, monitoring, and LIVE_TRADING_ENABLED=true are configured.",
|
||||||
providers,
|
providers,
|
||||||
next_required: providers.filter((x) => !x.configured).map((x) => x.label),
|
next_required: missing,
|
||||||
|
docs: {
|
||||||
|
polymarket_overview: "https://docs.polymarket.com/trading/overview",
|
||||||
|
polymarket_quickstart: "https://docs.polymarket.com/trading/quickstart",
|
||||||
|
deposit_wallets: "https://docs.polymarket.com/trading/deposit-wallets",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -2259,8 +2259,9 @@ function renderLiveBackendStatus(){
|
|||||||
const root=$("liveBackendStatus");if(!root)return;
|
const root=$("liveBackendStatus");if(!root)return;
|
||||||
const s=LIVE_BACKEND_STATUS;
|
const s=LIVE_BACKEND_STATUS;
|
||||||
if(!s){root.innerHTML="Checking backend readiness...";return;}
|
if(!s){root.innerHTML="Checking backend readiness...";return;}
|
||||||
const providers=(s.providers||[]).map(p=>`<div class="leader-row"><span>${esc(p.label)}</span><b class="${p.configured?"pos-val":"neg-val"}">${p.configured?"configured":"missing"}</b></div>`).join("");
|
const providers=(s.providers||[]).map(p=>`<div class="leader-row"><span>${esc(p.label)}${p.expected?`<div class="small muted">${esc(p.expected)}</div>`:""}</span><b class="${p.configured?"pos-val":"neg-val"}">${p.configured?"configured":"missing"}</b></div>`).join("");
|
||||||
root.innerHTML=`<b>${s.live_trading_enabled?"Live trading unlocked":"Live trading locked"}</b><div class="small muted" style="margin:6px 0">${esc(s.locked_reason||"All required backend providers are configured.")}</div>${providers}`;
|
const next=(s.next_required||[]).slice(0,8).map(x=>`<li>${esc(x)}</li>`).join("");
|
||||||
|
root.innerHTML=`<b>${s.live_trading_enabled?"Live trading unlocked":"Live trading locked"}</b><div class="small muted" style="margin:6px 0">${esc(s.locked_reason||"All required backend providers are configured.")}</div>${providers}${next?`<div class="locked-panel" style="margin-top:10px"><b>Next setup items</b><ul>${next}</ul></div>`:""}<div class="small muted" style="margin-top:8px">Live execution stays disabled until every provider is configured and final approval flips LIVE_TRADING_ENABLED=true.</div>`;
|
||||||
}
|
}
|
||||||
async function dryRunLiveOrderIntent(){
|
async function dryRunLiveOrderIntent(){
|
||||||
const s=loadLiveState();
|
const s=loadLiveState();
|
||||||
|
|||||||
Reference in New Issue
Block a user