### Install Dependencies Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/README.md Run this command after cloning the repository to install all necessary Node.js dependencies. ```bash npm install ``` -------------------------------- ### Start Market Making with Logging Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/README.md This command starts the market making process using the CLI. It includes logging to provide output and insights into the process. ```bash npm run start:cli ``` -------------------------------- ### Authorize Contract for Predict Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/README.md Run this script for the initial setup of Predict to authorize smart contracts. This is a one-time setup for new Predict accounts. ```bash npx tsx src/setup-approvals.ts ``` -------------------------------- ### Configure Environment Variables Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/README.md Copy the example environment file and edit it to include your API keys and other required credentials. Ensure all necessary fields like API_KEY, PRIVATE_KEY, and PREDICT_ACCOUNT_ADDRESS are filled. ```bash cp .env.example .env # Edit .env to fill in API_KEY, PRIVATE_KEY, PREDICT_ACCOUNT_ADDRESS, etc. ``` -------------------------------- ### Initialize and Use UnifiedMarketMakerStrategy Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Configure UnifiedMarketMakerStrategy with parameters like tolerance, hedge size limits, and offset settings. Use analyzeAndRecommend to get action suggestions, getOrdersToPlace to determine necessary orders, and classifyState to understand the current position status. ```typescript import { UnifiedMarketMakerStrategy, UnifiedState } from './src/strategies/unified-market-maker-strategy.js'; import type { Position } from './src/types.js'; const strategy = new UnifiedMarketMakerStrategy({ enabled: true, tolerance: 0.05, // 5% imbalance tolerance before hedging minHedgeSize: 10, // minimum 10 shares per hedge maxHedgeSize: 500, asyncHedging: true, // hedge immediately on fill, keep other orders live dualTrackMode: true, // simultaneously earn points on both buy and sell rails dynamicOffsetMode: true, // place at second-level price offset buyOffsetBps: 100, // 1% inside best bid sellOffsetBps: 100, // 1% inside best ask hedgeSlippageBps: 250, }); const position: Position = { yes: 120, no: 80 }; // net long 40 YES // Analyse current state and get a recommended action const action = strategy.analyzeAndRecommend(position, orderbook); // => { // needsAction: true, // type: 'BUY_NO', // hedge by buying 40 NO to reach 1:1 // shares: 40, // reason: 'Async hedge: YES surplus 40, buy NO to balance', // priority: 'URGENT' // } // Determine what orders to place given current state const orders = strategy.getOrdersToPlace(position, orderbook); // => [ // { side: 'BUY', outcome: 'YES', price: 0.44, shares: 50 }, // { side: 'BUY', outcome: 'NO', price: 0.54, shares: 50 }, // ] // Query current state classification const state = strategy.classifyState(position); // => UnifiedState.DUAL_TRACK (1:1 position, actively quoting both sides) // Possible values: EMPTY | HEDGED | DUAL_TRACK ``` -------------------------------- ### Get Recommended Markets Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/README.md This script helps identify recommended markets based on specified criteria. Use the --venue and --top flags to filter results. ```bash npx tsx scripts/market-recommender.ts --venue predict --top 10 ``` -------------------------------- ### Start Market Maker API Call Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/public/index.html Initiates the market maker process by sending a POST request to the /api/start endpoint. Updates the running status and logs the outcome. ```javascript async function startMarketMaker() { try { addLog('info', '正在启动做市商...'); const response = await fetch('/api/start', { method: 'POST' }); const result = await response.json(); if (result.success) { isRunning = true; startTime = Date.now(); updateStatus(); addLog('success', '✅ 做市商启动成功!'); } else { addLog('error', '❌ 启动失败: ' + result.message); } } catch (error) { addLog('error', '❌ 连接失败: ' + error.message); } } ``` -------------------------------- ### Initialize and Run Predict.fun Market Maker Bot Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Instantiate and start the Predict.fun market maker bot. Reads configuration from environment variables. Handles initialization, market selection, and the main quoting loop. Supports graceful shutdown and emergency cancellation. ```typescript import { PredictMarketMakerBot } from './src/index.js'; // Instantiate and start the bot (reads all config from .env / environment) const bot = new PredictMarketMakerBot(); // Initialize: connects to API, auto-fetches JWT, selects markets, sets up WebSocket await bot.initialize(); // Expected log output: // 🚀 Initializing Predict.fun Market Maker Bot... // 🔐 Wallet: 0xAbC... // 🔍 Scanning markets... // 📘 Predict orderbooks fetched: 24/36 // ✅ Selected 10 markets for market making // 📡 Market Maker WS enabled (wss://ws.predict.fun/ws) — cancel-on-dirty active // Run the main quoting loop (blocks until stopped) await bot.run(); // Get live status at any point const status = bot.getStatus(); // => { openOrders: 18, positions: 5, sessionPnL: 12.40, markets: 10 } // Graceful stop: cancels all open orders before exiting await bot.stop(); // Expected log: // 🛑 Stopping bot... // ✅ 所有挂单已撤销 // SIGINT / SIGTERM are also handled automatically; or trigger emergency cancel: // touch emergency-cancel.flag (the bot detects this file each loop iteration) ``` -------------------------------- ### Initialize and Run Polymarket Market Maker Bot Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Instantiate and start the Polymarket market maker bot. This bot mirrors the Predict.fun bot but targets the Polymarket CLOB and includes Polymarket-specific reward gate logic. Configuration is driven by `MM_VENUE=polymarket` in `.env`. ```typescript import { PolymarketMarketMakerBot } from './src/index.js'; // Driven by MM_VENUE=polymarket in .env const bot = new PolymarketMarketMakerBot(); await bot.initialize(); // 🚀 Initializing Polymarket Market Maker Bot... // 🔐 Wallet: 0xDef... // 🔧 Polymarket preflight: signer=0xDef... funder=0xDef... sigType=0 creds=ready openOrders=4 // 📘 Polymarket orderbooks fetched: 40/48 // ✅ Selected 12 tokens for market making // 📡 Polymarket WS enabled — cancel-on-dirty active await bot.run(); // The reward gate is evaluated per-market per-iteration: // If crowding multiple > 12x → market paused for rewardPauseMs (default 3 min) // If event within 30 min → market skipped (blocked) // If hourly risk score ≥ 6 → market skipped this hour await bot.stop(); // ✅ Polymarket所有挂单已撤销 ``` -------------------------------- ### Update Uptime Display Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/public/index.html Calculates and displays the elapsed time since the market maker started in minutes and seconds. Updates every second. ```javascript function updateUptime() { if (!startTime) { document.getElementById('uptime').textContent = '0分 0秒'; return; } const elapsed = Math.floor((Date.now() - startTime) / 1000); const minutes = Math.floor(elapsed / 60); const seconds = elapsed % 60; document.getElementById('uptime').textContent = `${minutes}分 ${seconds}秒`; } ``` -------------------------------- ### Get JWT Token for Predict Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/README.md Execute this command to obtain a JWT token, which is specifically required for Predict. This is typically needed for authentication. ```bash npx tsx src/auth-jwt.ts ``` -------------------------------- ### Initialize and Use MarketSelector Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Instantiate MarketSelector with specific thresholds for liquidity, volume, spread, and order count. Use selectMarkets to get a scored list of markets and printAnalysis to display a detailed table. The constructor accepts optional parameters for Polymarket reward fit. ```typescript import { MarketSelector } from './src/market-selector.js'; import type { Market, Orderbook } from './src/types.js'; // Constructor: (minLiquidity, minVolume24h, maxSpread, minOrders, options?) const selector = new MarketSelector( 1000, // min $1000 liquidity 500, // min $500 24h volume 0.06, // max 6% spread 4, // min 4 resting orders { polymarketRewardRequireFit: true, polymarketRewardMinFitScore: 0.6, polymarketRewardMinDailyRate: 10, polymarketRewardMinEfficiency: 0.0015, } ); // markets: Market[] orderbooks: Map const scored = selector.selectMarkets(markets, orderbooks); // => [{ market: {...}, score: 87.3, reasons: ['spread ok (4.2%)', 'reward fit 82%', ...] }, ...] // Print detailed analysis table to console selector.printAnalysis(scored); // Market | Score | Spread | Liquidity | Volume | Reasons // -------+-------+--------+-----------+--------+-------- // ... // Select top N markets const top10 = selector.getTopMarkets(scored, 10); // => Market[] // Evaluate Polymarket reward fit for a single market const fit = selector.evaluatePolymarketRewardFit(market, orderbook); // => { enabled: true, dailyRate: 45.2, efficiency: 0.0032, fitScore: 0.78, // crowdingMultiple: 3.4, targetQueueFactor: 0.85, ... } ``` -------------------------------- ### Initialize Market Maker State and Event Listeners Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/public/index.html Sets up initial state variables and attaches an event listener for DOM content loading to initialize the status and uptime updates. ```javascript let isRunning = false; let startTime = null; let stats = { totalOrders: 0, successOrders: 0, failedOrders: 0, markets: 0, activeOrders: 0 }; // Initialize document.addEventListener('DOMContentLoaded', () => { loadStatus(); setInterval(updateUptime, 1000); }); ``` -------------------------------- ### Get OrderManager Approval Diagnostic Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Retrieve detailed approval diagnostics from the OrderManager for debugging purposes. This includes signer and maker addresses, chain ID, native balance, and the status of auto-approvals. ```typescript // Get full approval diagnostic for debugging const diag = await manager.getApprovalDiagnostic(); // => { signerAddress, makerAddress, chainId, nativeBalance: '0.012345', autoSetApprovals: true } ``` -------------------------------- ### PredictMarketMakerBot - Main Bot Entry Point Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt The `PredictMarketMakerBot` class is the primary entry point for the Predict.fun market-making workflow. It handles configuration loading, API client and wallet initialization, JWT acquisition, market selection, and the continuous quoting loop with WebSocket support and graceful shutdown. ```APIDOC ## PredictMarketMakerBot - Main Bot Entry Point (Predict.fun Venue) ### Description The top-level class that orchestrates the entire Predict.fun market-making workflow: loading config, initialising the API client and wallet, auto-acquiring a JWT, selecting markets, and running the continuous quoting loop with WebSocket-backed orderbook updates and graceful shutdown. ### Usage ```typescript import { PredictMarketMakerBot } from './src/index.js'; // Instantiate and start the bot (reads all config from .env / environment) const bot = new PredictMarketMakerBot(); // Initialize: connects to API, auto-fetches JWT, selects markets, sets up WebSocket await bot.initialize(); // Expected log output: // 🚀 Initializing Predict.fun Market Maker Bot... // 🔐 Wallet: 0xAbC... // 🔍 Scanning markets... // 📘 Predict orderbooks fetched: 24/36 // ✅ Selected 10 markets for market making // 📡 Market Maker WS enabled (wss://ws.predict.fun/ws) — cancel-on-dirty active // Run the main quoting loop (blocks until stopped) await bot.run(); // Get live status at any point const status = bot.getStatus(); // => { openOrders: 18, positions: 5, sessionPnL: 12.40, markets: 10 } // Graceful stop: cancels all open orders before exiting await bot.stop(); // Expected log: // 🛑 Stopping bot... // ✅ 所有挂单已撤销 // SIGINT / SIGTERM are also handled automatically; or trigger emergency cancel: // touch emergency-cancel.flag (the bot detects this file each loop iteration) ``` ### Methods - **`initialize()`**: Connects to the API, fetches JWT, selects markets, and sets up WebSocket connections. - **`run()`**: Starts the main market-making quoting loop. This method blocks until the bot is stopped. - **`getStatus()`**: Returns the current status of the bot, including open orders, positions, P&L, and active markets. - **`stop()`**: Gracefully stops the bot by cancelling all open orders before exiting. ``` -------------------------------- ### Initialize and Use PredictAPI Client Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Instantiate the PredictAPI client with API keys and JWT tokens for authentication. Use it to fetch market data, orderbooks, and manage orders. Requires API_KEY and optionally JWT_TOKEN environment variables. ```typescript import { PredictAPI } from './src/api/client.js'; const api = new PredictAPI( 'https://api.predict.fun', process.env.API_KEY, process.env.JWT_TOKEN // accepts raw token or "Bearer " ); // Test connectivity const connected = await api.testConnection(); // => true // Fetch all open markets (returns Market[]) const markets = await api.getMarkets({ status: 'OPEN' }); // => [{ token_id: '0xabc...', question: 'Will X happen?', best_bid: 0.42, best_ask: 0.46, ... }, ...] // Fetch level-2 orderbook for a specific outcome token const book = await api.getOrderbook('0xabc123...tokenId'); // => { token_id: '0xabc...', best_bid: 0.42, best_ask: 0.46, mid_price: 0.44, // spread: 0.04, spread_pct: 9.09, // bids: [{ price: '0.42', shares: '150' }, ...], // asks: [{ price: '0.46', shares: '200' }, ...] // } // Fetch open orders for a maker address (requires JWT) const orders = await api.getOrders('0xMakerAddress'); // => [{ id: 'ord_001', token_id: '0xabc...', side: 'BUY', price: 0.42, size: 50, status: 'OPEN' }, ...] // Fetch current positions (requires JWT) const positions = await api.getPositions('0xMakerAddress'); // => [{ token_id: '0xabc...', size: 75, avg_price: 0.43, unrealized_pnl: 2.25 }, ...] // Cancel a specific order (requires JWT) await api.cancelOrder('ord_001'); // Cancel all open orders (requires JWT) await api.cancelAllOrders('0xMakerAddress'); // Place a signed limit order payload (built by OrderManager) const result = await api.placeOrder(signedPayload); // => { id: 'ord_002', status: 'ACCEPTED' } ``` -------------------------------- ### Initialize OrderManager for On-Chain Orders Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Create an OrderManager instance using configuration including private key, chain ID, and RPC URL. This manager handles USDT collateral checks and order signing. It requires a PRIVATE_KEY environment variable and optionally PREDICT_ACCOUNT_ADDRESS. ```typescript import { OrderManager } from './src/order-manager.js'; import type { Config } from './src/types.js'; const config: Config = { privateKey: process.env.PRIVATE_KEY!, // hex private key predictAccountAddress: process.env.PREDICT_ACCOUNT_ADDRESS, // optional Predict smart-account predictChainId: 56, // 56 = BNB Mainnet rpcUrl: 'https://bsc-dataseed.binance.org', predictAutoSetApprovals: true, }; // Factory method — async because it queries chain state const manager = await OrderManager.create(config); console.log(manager.getSignerAddress()); // => '0xYourWallet...' console.log(manager.getMakerAddress()); // => predictAccountAddress ?? signerAddress ``` -------------------------------- ### Score Markets and Optimize Orders with PointsOptimizerEngine Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Use `evaluateMarket` to score a market's points potential and `adjustOrder` to ensure orders comply with platform constraints. Batch scoring is available via `rankMarkets`. ```typescript import { pointsOptimizerEngine } from './src/mm/points/points-optimizer.js'; // Evaluate a market's points value const score = pointsOptimizerEngine.evaluateMarket( market, // Market with liquidity_activation fields currentSpreadBps, orderbook ); // => { // marketId: '0xabc...', // pointsValue: 8.4, // 0–10 scale // profitability: 6.1, // priority: 7.2, // recommendedSpread: 570, // bps — 5.7 cents (just under 6c limit) // recommendedSize: 105, // shares (+5% buffer over min_shares) // reasons: ['High daily rate: $124', 'Low crowding: 2.1x', 'Good spread room'] // } // Adjust a planned order to comply with points eligibility rules const adj = pointsOptimizerEngine.adjustOrder(market, proposedSpreadBps, proposedSize); // => { // adjustedSpread: 560, // adjustedSize: 110, // meetsMinShares: true, // withinMaxSpread: true, // pointsEligible: true, // warnings: [] // } // Batch-score and sort multiple markets const rankings = pointsOptimizerEngine.rankMarkets(markets, orderbookMap); // => PointsMarketScore[] sorted by priority descending ``` -------------------------------- ### PolymarketMarketMakerBot - Main Bot Entry Point Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt The `PolymarketMarketMakerBot` class is a variant of the main bot designed for the Polymarket venue. It incorporates Polymarket-specific logic such as reward-gate evaluation, event-risk windows, and risk penalties, while sharing core functionalities with `PredictMarketMakerBot`. ```APIDOC ## PolymarketMarketMakerBot — Main Bot Entry Point (Polymarket Venue) ### Description Mirrors `PredictMarketMakerBot` but targets the Polymarket CLOB. Adds Polymarket-specific reward-gate logic (crowding multiplier, queue efficiency checks), event-risk windows, per-hour risk penalties, and pattern-memory cooldowns. Configured by setting `MM_VENUE=polymarket` in `.env`. ### Usage ```typescript import { PolymarketMarketMakerBot } from './src/index.js'; // Driven by MM_VENUE=polymarket in .env const bot = new PolymarketMarketMakerBot(); await bot.initialize(); // 🚀 Initializing Polymarket Market Maker Bot... // 🔐 Wallet: 0xDef... // 🔧 Polymarket preflight: signer=0xDef... funder=0xDef... sigType=0 creds=ready openOrders=4 // 📘 Polymarket orderbooks fetched: 40/48 // ✅ Selected 12 tokens for market making // 📡 Polymarket WS enabled — cancel-on-dirty active await bot.run(); // The reward gate is evaluated per-market per-iteration: // If crowding multiple > 12x → market paused for rewardPauseMs (default 3 min) // If event within 30 min → market skipped (blocked) // If hourly risk score ≥ 6 → market skipped this hour await bot.stop(); // ✅ Polymarket所有挂单已撤销 ``` ### Methods - **`initialize()`**: Initializes the Polymarket bot, including connecting to the API, fetching credentials, and setting up orderbooks. - **`run()`**: Executes the main market-making loop for Polymarket, applying venue-specific logic for reward gates and risk management. - **`stop()`**: Gracefully shuts down the Polymarket bot, ensuring all open orders are cancelled. ``` -------------------------------- ### Aggregate Market Data Across Platforms with CrossPlatformAggregator Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Initialize `CrossPlatformAggregator` with configuration for various platforms. Use `getAllPlatformMarkets` to fetch unified market data, `onWsUpdate` to subscribe to WebSocket updates, and `getOrderbook` to retrieve specific orderbooks. ```typescript import { CrossPlatformAggregator } from './src/external/aggregator.js'; const aggregator = new CrossPlatformAggregator(config); // config must include: // polymarketGammaUrl, polymarketClobUrl, polymarketWsEnabled, ... // opinionOpenApiUrl, opinionApiKey (optional) // Fetch unified market list across all configured platforms const platformMarkets = await aggregator.getAllPlatformMarkets(); // => [ // { // platform: 'Polymarket', // tokenId: '0xpoly...', // question: 'Will X happen by Dec?', // bestBid: 0.41, bestAsk: 0.45, // mappedPredictTokenId: '0xpred...' // if cross-platform match found // }, // { platform: 'Opinion', tokenId: 'op-123', ... }, // ... // ] // Register a callback that fires when a WebSocket update arrives for any platform aggregator.onWsUpdate((platform, tokenId) => { console.log(`WS update: ${platform} ${tokenId}`); }); // Retrieve the current orderbook for a specific platform token const book = await aggregator.getOrderbook('Polymarket', '0xpoly...'); // => { bestBid: 0.41, bestAsk: 0.45, bids: [...], asks: [...] } ``` -------------------------------- ### PointsOptimizerEngine Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Scores markets by points reward potential, calculates optimal spreads and order sizes within platform constraints, and flags order eligibility for reward accrual. ```APIDOC ## `PointsOptimizerEngine` — Predict.fun Points Maximiser Scores each market by its points reward potential, calculates the optimal spread and order size that stay within the platform's `max_spread` and `min_shares` constraints, and flags whether a given order configuration qualifies for reward accrual. ### `evaluateMarket` Evaluates a market's points value. **Parameters** - `market` (Market) - Market with liquidity_activation fields - `currentSpreadBps` (number) - Current spread in basis points - `orderbook` (Orderbook) - Current orderbook data **Returns** - `PointsMarketScore` - An object containing market ID, points value, profitability, priority, recommended spread, recommended size, and reasons. ### `adjustOrder` Adjusts a planned order to comply with points eligibility rules. **Parameters** - `market` (Market) - The market object - `proposedSpreadBps` (number) - The proposed spread in basis points - `proposedSize` (number) - The proposed order size **Returns** - `OrderAdjustment` - An object detailing the adjusted spread, adjusted size, and eligibility flags (meetsMinShares, withinMaxSpread, pointsEligible), along with any warnings. ### `rankMarkets` Batch-scores and sorts multiple markets. **Parameters** - `markets` (Market[]) - An array of market objects - `orderbookMap` (OrderbookMap) - A map of orderbooks for the markets **Returns** - `PointsMarketScore[]` - An array of points market scores, sorted by priority descending. ``` -------------------------------- ### Check and Ensure Collateral for Orders Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Use OrderManager to check USDT collateral requirements for buy orders and ensure sufficient allowance is available, automatically calling setApprovals if necessary. This is crucial before building and placing orders. ```typescript // Check USDT collateral before placing a buy order const collateral = await manager.getBuyCollateralState(market, 0.45, 100); // => { required: '45.000000', balance: '200.000000', allowance: '999999.000000', ... } // Ensure allowance is sufficient (calls setApprovals if needed) await manager.ensureBuyCollateralReady(market, 0.45, 100, 50 /* bufferBps */); ``` -------------------------------- ### Detect Statistical Value Mismatches with ValueMismatchDetector Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt Instantiate `ValueMismatchDetector` with thresholds for confidence and edge. Use `analyzeMarket` to estimate fair probability and identify mispricing opportunities after accounting for fees and slippage. ```typescript import { ValueMismatchDetector } from './src/arbitrage/value-detector.js'; const detector = new ValueMismatchDetector( 0.65, // confidence threshold — only act when model confidence ≥ 65% 0.04, // edge threshold — minimum 4% edge after costs 0.01, // estimated fee rate (1%) 0.002 // estimated slippage (0.2%) ); const analysis = detector.analyzeMarket(market, orderbook); // Returns null if insufficient data or edge below threshold. // Otherwise: // => { // outcome: 'YES', // midPrice: 0.44, // impliedYes: 0.44, // fairYes: 0.52, // model's estimated fair probability // fairTokenPrice: 0.52, // assessment: 'UNDERVALUED', // action: 'BUY_YES', // edge: 0.072, // 7.2% net edge after costs // confidence: 0.71, // reasoning: 'Fair value 0.52 > ask 0.46; edge 7.2% exceeds threshold' // } ``` -------------------------------- ### Render Market List and Score Markets (renderMarkets) Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/launcher/index.html Renders the market list in the UI and calculates a score for each market based on filtering results and various metrics like spread, depth, and share threshold. Handles loading states and displays market actions. ```javascript function renderMarkets() { const list = document.getElementById('marketList'); const actionBar = document.getElementById('marketActionBar'); const markets = currentMarketVenue === 'predict' ? (cachedPredictMarkets || []) : (cachedPolyMarkets || []); if (markets.length === 0) { list.innerHTML = `
点击"刷新市场"加载${currentMarketVenue === 'predict' ? 'Predict.fun' : 'Polymarket'}市场
`; actionBar.style.display = 'none'; return; } actionBar.style.display = 'flex'; const mode = getModeParams(); const scored = markets.map(m => { const screen = screenMarketUI(m); let score = 0; const { reasons, warnings, canTrade, bufferPerSide, screenFail } = screen; const maxSpread = m.max_spread_cents || 0; const minShares = m.min_shares || 100; const bookSpread = (m.best_bid && m.best_ask) ? (m.best_ask - m.best_bid) * 100 : 999; const bufferUtilization = maxSpread > 0 ? bookSpread / maxSpread : 1; const vol = m.volume_24h || 0; let pointsEfficiency = 0; // 只有可挂单的市场才添加评分和正面标签 if (canTrade) { score += 40; score += Math.min(25, Math.floor(bufferPerSide * 4)); // ===== Points Efficiency Scoring ===== pointsEfficiency = (bufferPerSide / Math.max(minShares, 1)) * 1000; score += Math.min(20, Math.floor(pointsEfficiency * 2)); // min_shares门槛评分 if (minShares <= 50) { score += 12; reasons.push('低门槛(' + minShares + '股)'); } else if (minShares <= 100) { score += 8; reasons.push('门槛低(' + minShares + '股)'); } else if (minShares <= 200) { score += 4; } else { score -= 3; warnings.push('门槛高(' + minShares + '股)'); } // max_spread奖励 if (maxSpread >= 8) { score += 6; reasons.push('宽价差(' + maxSpread + 'c)'); } else if (maxSpread >= 6) { score += 3; } // Buffer utilization scoring if (bufferUtilization < 0.3) { score += 8; reasons.push('盘口宽松'); } else if (bufferUtilization > 0.7) { score -= 3; warnings.push('盘口拥挤'); } // ===== L1+L2 Depth scoring (核心新增) ===== // L1+L2 深度越大,挂第3/4档越安全(吃单者先吃前面档位) const l1Depth = (m.best_bid_size || 0) + (m.best_ask_size || 0); const minFrontDepth = mode.minFrontDepth || 6000; if (l1Depth === 0) { // API 不返回 size 数据,不加分不扣分,由后端确认 warnings.push('盘口深度待确认'); } else if (l1Depth >= minFrontDepth * 3) { score += 25; reasons.push('L1+L2极深(' + Math.floor(l1Depth) + ')'); } else if (l1Depth >= minFrontDepth * 2) { score += 18; reasons.push('L1+L2很深(' + Math.floor(l1Depth) + ')'); } else if (l1Depth >= minFro ``` -------------------------------- ### OrderManager SDK Source: https://context7.com/ccjingeth/predict-fun-marketmaker/llms.txt The OrderManager SDK helps construct EIP-712 typed-data limit and market orders, signs them with an ethers.js Wallet, and handles collateral checks and approvals. ```APIDOC ## OrderManager — On-Chain Order Builder and Signer ### Description Wraps `@predictdotfun/sdk`'s `OrderBuilder` to construct EIP-712 typed-data limit and market orders signed by an ethers.js `Wallet`. Handles USDT collateral balance/allowance checks, automatic `setApprovals()` on first run, and Wei-precision arithmetic for price and quantity. ### Initialization ```typescript import { OrderManager } from './src/order-manager.js'; import type { Config } from './src/types.js'; const config: Config = { privateKey: process.env.PRIVATE_KEY!, // hex private key predictAccountAddress: process.env.PREDICT_ACCOUNT_ADDRESS, // optional Predict smart-account predictChainId: 56, // 56 = BNB Mainnet rpcUrl: 'https://bsc-dataseed.binance.org', predictAutoSetApprovals: true, }; // Factory method — async because it queries chain state const manager = await OrderManager.create(config); ``` ### Methods #### `getSignerAddress()` Gets the signer's wallet address. * **Returns**: `string` - The signer's address. ```typescript console.log(manager.getSignerAddress()); // => '0xYourWallet...' ``` #### `getMakerAddress()` Gets the maker address, which is either the `predictAccountAddress` from config or the signer address. * **Returns**: `string` - The maker address. ```typescript console.log(manager.getMakerAddress()); // => predictAccountAddress ?? signerAddress ``` #### `getBuyCollateralState(market: Market, price: number, shares: number)` Checks the USDT collateral state required for a buy order. * **Parameters**: * `market` (Market) - The market object. * `price` (number) - The price of the order. * `shares` (number) - The number of shares. * **Returns**: `object` - An object containing collateral state details (e.g., `required`, `balance`, `allowance`). ```typescript const collateral = await manager.getBuyCollateralState(market, 0.45, 100); // => { required: '45.000000', balance: '200.000000', allowance: '999999.000000', ... } ``` #### `ensureBuyCollateralReady(market: Market, price: number, shares: number, bufferBps?: string)` Ensures that the collateral is sufficient for a buy order, calling `setApprovals` if necessary. * **Parameters**: * `market` (Market) - The market object. * `price` (number) - The price of the order. * `shares` (number) - The number of shares. * `bufferBps` (string, optional) - Buffer in basis points to add to the required collateral. * **Returns**: `Promise` ```typescript await manager.ensureBuyCollateralReady(market, 0.45, 100, 50 /* bufferBps */); ``` #### `buildLimitOrderPayload(params: { market: Market, side: 'BUY' | 'SELL', price: number, shares: number })` Builds a signed limit order payload ready for the REST API. * **Parameters**: * `params` (object) * `market` (Market) - Market object with token_id, fee_rate_bps, is_neg_risk, etc. * `side` ('BUY' | 'SELL') - The side of the order. * `price` (number) - The price of the order (0 < price < 1). * `shares` (number) - The number of shares. * **Returns**: `Promise` - The signed limit order payload. ```typescript const payload = await manager.buildLimitOrderPayload({ market, side: 'BUY', price: 0.45, shares: 100, }); // payload is ready to pass to api.placeOrder(payload) ``` #### `buildMarketOrderPayload(params: { market: Market, side: 'BUY' | 'SELL', shares: number, orderbook: Orderbook, slippageBps?: string })` Builds a signed market order payload, filling against existing book levels with a slippage guard. * **Parameters**: * `params` (object) * `market` (Market) - The market object. * `side` ('BUY' | 'SELL') - The side of the order. * `shares` (number) - The number of shares. * `orderbook` (Orderbook) - The current orderbook. * `slippageBps` (string, optional) - Tolerated slippage in basis points (e.g., '250' for 2.5%). * **Returns**: `Promise` - The signed market order payload. ```typescript const mktPayload = await manager.buildMarketOrderPayload({ market, side: 'SELL', shares: 50, orderbook: currentBook, slippageBps: '250', // tolerate up to 2.5% slippage }); ``` #### `getApprovalDiagnostic()` Gets full approval diagnostic information for debugging. * **Returns**: `Promise` - An object containing approval diagnostic details. ```typescript const diag = await manager.getApprovalDiagnostic(); // => { signerAddress, makerAddress, chainId, nativeBalance: '0.012345', autoSetApprovals: true } ``` ``` -------------------------------- ### Load Market Maker Status from API Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/public/index.html Fetches the current status and statistics of the market maker from the /api/status endpoint. Updates the application's state based on the response. ```javascript async function loadStatus() { try { const response = await fetch('/api/status'); const data = await response.json(); isRunning = data.running || false; stats = data.stats || stats; updateStatus(); updateStats(); } catch (error) { console.error('加载状态失败:', error); } } ``` -------------------------------- ### Debug Statistics Generation Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/launcher/index.html Generates and displays a summary of market filtering statistics, including counts for passed markets and various failure reasons. Useful for understanding market data distribution. ```javascript // Debug stats const total = scored.length; const pass = scored.filter(s => s.canTrade).length; const noPoints = scored.filter(s => !s.canTrade && s.screenFail === '无积分规则').length; const noBook = scored.filter(s => !s.canTrade && (s.screenFail === '无盘口' || s.screenFail === '无盘口数据')).length; const bigSpread = scored.filter(s => !s.canTrade && s.screenFail === '盘口价差过大').length; const lowBuffer = scored.filter(s => !s.canTrade && s.screenFail === '缓冲不足').length; const lowDepth = scored.filter(s => !s.canTrade && s.screenFail === '深度不足').length; const otherFail = total - pass - noPoints - noBook - bigSpread - lowBuffer - lowDepth; const debugHTML = `
筛选统计: 共${total}个 | 通过${pass} | 无积分${noPoints} | 无盘口${noBook} | 价差大${bigSpread} | 缓冲低${lowBuffer} | 深度不足${lowDepth} | 其他${otherFail}
`; ``` -------------------------------- ### Update UI Status Badge and Buttons Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/public/index.html Modifies the text and class of the status badge and enables/disables start/stop buttons based on the market maker's running state. ```javascript function updateStatus() { const badge = document.getElementById('statusBadge'); const startBtn = document.getElementById('startBtn'); const stopBtn = document.getElementById('stopBtn'); if (isRunning) { badge.textContent = '运行中'; badge.className = 'status-badge status-running'; startBtn.disabled = true; stopBtn.disabled = false; } else { badge.textContent = '已停止'; badge.className = 'status-badge status-stopped'; startBtn.disabled = false; stopBtn.disabled = true; } } ``` -------------------------------- ### Market Item Rendering Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/launcher/index.html Renders individual market items for display in an HTML list, including score, question, and trade status. Handles conditional styling and selection states. Use this to populate the UI with market data. ```javascript list.innerHTML = debugHTML + scored.slice(0, 100).map(item => { const { m, score, reasons, warnings, canTrade, bufferPerSide, vol, minShares, pointsEfficiency } = item; const isSelected = selectedTokenIds.has(m.token_id); const scoreClass = canTrade ? (score >= 70 ? 'good' : score >= 45 ? 'ok' : 'bad') : 'bad'; const tradeTag = canTrade ? '' : '不可挂单'; const volStr = vol ? '$' + (vol/1000).toFixed(1) + 'K' : ''; const endDate = m.end_date ? new Date(m.end_date).toLocaleDateString() : ''; const maxSpread = m.max_spread_cents || 0; const allReasons = reasons.concat(warnings); // 显示积分资金效率标签 const efficiencyTag = canTrade && pointsEfficiency > 0 ? `效率${pointsEfficiency.toFixed(1)}` : ''; return `
${canTrade ? '
' + (isSelected ? '✓' : '') + '
' : ''}
${score}
${escHtml(m.question)} { // date: '2025-01-15', // makerVolume: 4500, makerCount: 100, // fillVolume: 225, fillCount: 5, // fillLossUsd: 6.0, hedgeCostUsd: 2.0, // pointsEarned: 17.5, // netPnl: 9.5, // uptimeSeconds: 7200, // lastUpdated: '2025-01-15T14:32:00.000Z' // } // Print formatted report to console (also returns the stats object) printDailyReport(); // 📊 Daily Report 2025-01-15 // Maker volume: $4,500 (100 orders) // Fill loss: $6.00 (5 fills) // Hedge cost: $2.00 // Points: 17.5 // Net PnL: $9.50 ``` -------------------------------- ### Periodic Status Refresh Source: https://github.com/ccjingeth/predict-fun-marketmaker/blob/main/public/index.html Sets an interval to periodically call loadStatus if the market maker is currently running, ensuring the UI reflects the latest state every 5 seconds. ```javascript setInterval(() => { if (isRunning) { loadStatus(); } }, 5000); ```