anthonydavalos/betsniper

GitHub: anthonydavalos/betsniper

基于逆向工程 API 与 WebSocket 流量分析的量化体育套利引擎,集成凯利公式风险管理与多策略实时扫描。

Stars: 1 | Forks: 0

# 🎯 BetSniper V3 - 量化体育套利引擎
**具备量化风险管理的自动化体育交易系统** [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/) [![React](https://img.shields.io/badge/React-18+-blue.svg)](https://reactjs.org/) [![License](https://img.shields.io/badge/License-ISC-yellow.svg)](LICENSE)
## 🔐 网络安全视角 本项目演示了以下实际应用技术: - WebSocket 流量分析 - 实时系统行为监控 - 事件驱动平台的逆向工程 ## 📖 目录 - [概述](#-descripción-general) - [最近更新 (最新 Commit)](#-cambios-recientes-último-commit) - [核心功能](#-características-principales) - [系统架构](#-arquitectura-del-sistema) - [交易策略](#-estrategias-de-trading) - [财务管理](#-gestión-financiera-portfolio-theory) - [预操作配置指南](#-guía-de-configuración-pre-operativa) - [安装与部署](#-instalación-y-despliegue) - [用户界面](#-interfaz-de-usuario-dashboard) - [API 端点](#-api-endpoints) - [高级配置](#-configuración-avanzada) - [脚本与命令指南](#-guía-de-scripts-y-comandos) - [故障排除](#-troubleshooting) - [路线图](#-roadmap) ## 🌟 概述 **BetSniper V3** 是一款基于量化金融原理设计的高频体育交易系统。该系统作为**算法套利者**,在“ Sharp Bookie ”(Pinnacle/Arcadia - 真实概率来源)和“ Soft Bookie ”(Altenar/DoradoBet - 目标市场)之间交叉比对实时数据,以识别市场低效并执行正期望值 (EV+) 策略。 ### 工作原理? 1. **数据接入:** 通过与 Pinnacle 的 WebSocket 连接获取“无利润加成”的公平赔率,代表事件的真实概率。 2. **市场扫描:** 持续分析 Altenar (DoradoBet) 的赔率,以检测其与真实概率的差异。 3. **数学计算:** 应用带有动态风险配置的凯利公式来确定每次投注的最佳规模。 4. **模拟执行:** 模拟交易系统,模拟投注的执行并实时追踪损益 (P&L)。 5. **持续监控:** 追踪活跃投注的状态,并根据真实结果进行自动清算。 ## 🆕 最近更新 (最新 Commit) 本节总结了自上次 commit 以来的实现内容,以提供技术和操作上的可追溯性。 ### 2026-04-01 更新 (v3.4.24) - **阶段 1 (ARBITRAGE 单腿半自动):** - `client/src/App.jsx` 现在允许在每条腿的 provider 为 Altenar 时,从套利卡片中执行单腿操作。 - 如果该腿为 Arcadia/Pinnacle,则显示为**参考**,在阶段 1 不进行自动发送。 - 增加了将套利腿 (`1x2` 和 `DC+opuesto`) 转换为半自动流程可执行机会的功能。 - **真实发送 前的强制试运行:** - 在真实的 `confirm` 之前,会强制执行 `POST /api/booky/real/dryrun/:id`。 - 如果 dry-run 失败,票据将被取消且不会发送 `placeWidget`。 - dry-run 的摘要 包含在 UI 可见的确认块中。 - **阶段 2 (Arcadia -> Altenar 顺序双重执行):** - ARBITRAGE 选项卡中的每个机会新增了 `Ejecutar Dual` 按钮。 - 操作顺序:Arcadia (`prepare -> dryrun -> confirm-fast`),然后是 Altenar (`prepare -> dryrun -> confirm-fast`)。 - 根据 provider (Arcadia 和 Altenar) 自动选择腿,优先选择每侧 stake 最大的。 - UI 中的明确结果: - `CONFIRMED` (双腿均已确认), - `REJECTED` (Altenar 执行前 Arcadia 失败), - `HEDGE_REQUIRED` (Arcadia 已确认且 Altenar 被拒绝或状态不确定)。 - **并发执行控制:** - 为每张套利卡片设置锁,以防止在双重序列期间同时触发。 ### 2026-04-01 更新 (v3.4.23) - Sprint A.1 套利的 `Double Chance + opuesto 1x2` 管道现已投入运行。 - 增强了 DC 市场在摄入、缓存优先和扫描器之间的持久性,以防止数据丢失: - `scripts/ingest-pinnacle.js` 现在持久化从 1x2 派生的 `odds.doubleChance`。 - `src/services/prematchScannerService.js` 在从 prematch 缓存中补充 `upcomingMatches` 时保留了 `doubleChance`。 - `scripts/ingest-altenar.js` 和 `src/services/altenarPrematchScheduler.js` 现在根据 Altenar 的真实结构 (`desktopOddIds/mobileOddIds`,`typeId` 9/10/11) 映射 DC。 - 调整后的操作验证: - `upcomingMatches=63`,`pinnacleWithDC=59` - `altenarUpcoming=81`,`altenarWithDC=79` - `linked=30`,`linkedAltWithDc=30` - 结果:双方均已为 2 腿套利机会启用了 DC 技术覆盖;如果在特定快照中没有机会,原因在于定价/市场,而不是缺乏 DC 数据。 ### 2026-03-29 更新 (v3.4.22) - Pinnacle 现在具备完整的历史恢复和本地对账功能: - `GET /api/pinnacle/history` 同步 Arcadia 的远程投注,并通过 `providerBetId` 与 `portfolio` 进行交叉比对。 - `GET /api/pinnacle/account` 支持用于操作快照的可选刷新/历史记录。 - 新增了锚定到外部现金流 (`/transactions`) 的 Pinnacle 真实 PnL 计算: - 资本基数基于存款/取款, - 显示的 PnL = 当前余额 - 外部基数, - 避免将 Pinnacle 余额与 Booky PnL 混淆。 - 强化的自动投放置 UI: - 运行时手动选择 provider (`BOOKY`/`PINNACLE`), - PINNACLE 徽章/按钮,支持历史记录手动同步 (悬停时显示 `SYNC PINNACLE`,进行中显示 `SYNC...`), - 响应式布局以避免卡片溢出。 - 改进的已结束投注,带有来源可追溯性: - 来源徽章 (`BOOKY`/`PINNACLE`/`SIM`) 和 provider 过滤器 (`ALL/BOOKY/PINNACLE/SIM`)。 - 新增 Pinnacle 操作/诊断脚本: - `npm run capture:pinnacle:account` - `npm run capture:pinnacle:account:headless` - `scripts/debug-pinnacle-history-endpoints.js` 完整技术详情请见 [CHANGELOG.md](CHANGELOG.md),条目 `v3.4.22`。 ### 快速操作 SOP (v3.4.22) 发布后日常操作的推荐检查清单: 1. 验证 Pinnacle 账户: - `GET /api/pinnacle/account?refresh=1` - 确认 `balance`、`pnl.total`、`pnl.baseCapital` 和 `pnl.baseCapitalSource`。 2. 验证历史同步: - `GET /api/pinnacle/history?refresh=1&status=settled&days=180&limit=500` - 确认 `success=true` 并检查 `reconcileStats.touchedCount`。 3. 验证 UI: - 在 Auto Placement 中,选择 `PINNACLE`。 - 确认蓝色徽章 (`PINNACLE`) 和同步操作 (悬停时显示 `SYNC PINNACLE`)。 - 执行手动同步并验证状态 `SYNC...` + 成功消息。 4. 验证财务一致性: - Pinnacle 显示的 PnL 应遵循:`PnL = 当前余额 - 外部资本基数`。 5. 最低监控: - 每日进行 1 次手动控制同步。 - 检查 `transactions` 或 `history` 中是否有 `error`。 建议在生产环境中调整的变量: - `PINNACLE_PNL_WINDOW_DAYS` - `PINNACLE_PNL_BASE_CAPITAL` (仅备用) - `PINNACLE_HISTORY_DEFAULT_DAYS` - `PINNACLE_HISTORY_DEFAULT_STATUS` ### 2026-03-29 更新 (v3.4.21) - `scannerService` 中的运行时自动投放置 provider 选择器 (`booky` 或 `pinnacle`)。 - 新增查询端点:`GET /api/opportunities/live/placement-provider`。 - 新增热切换端点:`POST /api/opportunities/live/placement-provider`。 - 启动/实时决策诊断现在显示活动 provider 和允许的选项。 ### 2026-03-29 更新 (v3.4.20) - 自动投放置现在通过配置 (`AUTO_SNIPE_ALLOWED_TYPES`) 支持多种策略,默认激活 `LIVE_SNIPE`、`LA_VOLTEADA` 和 `LIVE_VALUE`。 - 移除了将 `LIVE_VALUE` 排除在自动引擎之外的硬编码限制。 - 改进的运行时诊断:`GET /api/opportunities/live/diagnostics` 现在包含 `scanner.autoPlacementAllowedTypes`。 - 丢弃原因从 `not-snipe` 演变为 `type-not-enabled`,当类型未启用时。 - 再次扩展了 `src/utils/dynamicAliases.json` 以加强国际匹配 (队伍/球队/选项的名称变体)。 - 完整详情请见 [CHANGELOG.md](CHANGELOG.md),条目 `v3.4.20`。 ### 2026-03-26 更新 (v3.4.19) - 已结束投注现在可以正确区分执行来源: - `BOOKY` 代表远程, - `REAL` 代表本地真实, - `SIM` 仅代表模拟。 - 修复了通过 `eventId`/`match` 进行比分回退导致的同一比赛行中比分视觉不一致的问题 (`1-1` vs `?-?`)。 - 在已结束选项卡中,现在也为本地真实行 (`isRealHistory`) 显示 `Ticket `。 - 使用额外的别名扩展了 `src/utils/dynamicAliases.json` 以改善匹配 (拼写变体、小联盟和 U21)。 - 完整详情请见 [CHANGELOG.md](CHANGELOG.md),条目 `v3.4.19`。 ### 2026-03-22 更新 (v3.4.17) - 真实已结束现在支持完整历史记录,不受短窗口截断限制 (`historyLimit=0`),并在 FINISHED 选项卡中进行强制初始数据填充。 - 修复了前端轮询中的陈旧关闭问题,以便间隔在决定历史记录限制时尊重当前的选项卡/模式。 - 强化了远程同步,具有部分缓存检测 (`limitBound`) 和在需要 `fetchAll` 时的自动旁路。 - Auto-snipe 添加了明确的 SIM 确认和在重新报价时的单次重试。 - Booky 确认中的赔率漂移现在可通过环境配置 (`BOOKY_LIVE_MAX_ODD_DRIFT`,`BOOKY_PREMATCH_MAX_ODD_DRIFT`)。 - 完整详情请见 [CHANGELOG.md](CHANGELOG.md),条目 `v3.4.17`。 ### 2026-03-24 更新 (v3.4.18) - 新的实时诊断端点:`GET /api/opportunities/live/diagnostics`,包含管道 (`raw/dedup/stable/final`)、聚合原因和最近事件。 - LIVE_SNIPE 现在暴露了机会前原因 (例如 `ev_non_positive`、`stake_below_1`、`real_prob_invalid`),用于审计信号为何未进入的真实原因。 - Provider requote (`providerCode=4`) 端到端已修复: - 后端保留 `BOOKY_PLACEWIDGET_REQUOTE_REQUIRED`。 - 前端显示特定的 re-quote 消息并允许引导的即时重试。 - 监视器中的记分牌完整性得到加强: - 消除了虚假的 `0-0`, - 分数标准化, - `DESYNC` 标签, - 在短暂的数据断线期间回退到 `STALE`。 - 完整详情请见 [CHANGELOG.md](CHANGELOG.md),条目 `v3.4.18`。 ### 1) Arcadia Gateway:稳定的自动刷新且无循环 - `server.js` 现在可以自动启动 `services/pinnacleGateway.js` (`PINNACLE_GATEWAY_AUTOSTART=true`)。 - 添加了重新启动的冷却时间 (`PINNACLE_GATEWAY_AUTOSTART_MIN_INTERVAL_MS`),以避免重复打开 Puppeteer/login。 - 具有可配置频率的陈旧触发器看门狗 (`PINNACLE_GATEWAY_TRIGGER_CHECK_INTERVAL_MS`)。 - 新的操作脚本:`npm run pinnacle:gateway`。 ### 2) LIVE 中精确的陈旧检测 - `src/services/liveValueScanner.js` 结合了 Pinnacle 与 Altenar 的时钟去同步保护,具有可配置的阈值 (`PINNACLE_STALE_TIME_DIFF_MINUTES`)。 - 陈旧触发器仅在具有持久性 (每个事件 >= 2 次命中) 时发出,并遵循冷却时间 (`PINNACLE_STALE_TRIGGER_MIN_INTERVAL_MS`)。 - 视觉时钟对齐调整仅针对较小的漂移 (<= 1 分钟),避免掩盖冻结的 sockets。 ### 3) 带有可选自动登录的 Pinnacle Gateway - `services/pinnacleGateway.js` 添加了尽力而为的自动登录 (框架 + 常见选择器),由以下参数控制: - `PINNACLE_AUTO_LOGIN_ENABLED` - `PINNACLE_LOGIN_USERNAME` - `PINNACLE_LOGIN_PASSWORD` - 新的陈旧检查/宽限期控制: - `PINNACLE_STALE_CHECK_INTERVAL_MS` - `PINNACLE_STALE_RELOAD_ALLOW_DURING_GRACE` - Arcadia 的最小 sockets 数量可配置,从 1 开始运行 (`PINNACLE_ARCADIA_MIN_SOCKETS=1`)。 ### 4) 更具可观察性和稳定性的 LIVE 管道 - `src/services/scannerService.js` 现在记录 `raw/dedup/stable/final` 管道,以解释为什么内部检测可能未到达端点的最终 payload。 - 修复了当 `QUOTE_STABILITY_MIN_HITS <= 1` 时的稳定性过滤器,不再要求不必要的额外确认。 ### 5) 更具弹性的 Booky token UX - `client/src/App.jsx` 改进了 Booky token 的静默自动续订: - 如果 `/api/booky/token/renew` 失败或未启动,则缩短下次重试的时间 (无需等待整个长冷却期)。 - 如果后端响应 `busy`,则遵循正常的冷却时间,以免向续订请求发送垃圾信息。 ### 6) 配置和匹配 - `.env.example` 已使用所有新的 Arcadia/Gateway/autologin 旋钮进行了更新。 - `src/utils/dynamicAliases.json` 添加了新别名,以加强具有变体名称的联赛中的匹配。 ### 7) 具有最终结果和可审计原因的 AUTO_SNIPE - `src/services/scannerService.js` 现在按尝试保留最终结果,状态如下: - `CONFIRMED` - `REJECTED` - `UNCERTAIN` - 如果 `LIVE_SNIPE` 机会保持手动,则记录 `reason=...` 以避免静默丢弃。 - auto-snipe 引擎的启动记录了有效参数。 ### 8) LIVE_SNIPE 的安全重入策略 - 结合重入保护,以避免在没有价格改善的情况下几乎相同的条目: - `AUTO_SNIPE_REENTRY_MIN_ODD_IMPROVEMENT_PCT` - `AUTO_SNIPE_REENTRY_MIN_ODD_POINTS` - `AUTO_SNIPE_MAX_ENTRIES_PER_PICK` - 如果没有实质性改善或超过了每次选择的限制,流程会标记明确的原因 (`reentry-no-improvement`,`reentry-cap`)。 ### 9) 高置信度匹配器 (手动辅助) - `client/src/components/ManualMatcher.jsx` 结合了带有综合分数的建议引擎。 - 用于受控批次的新操作: - `SUGERIR` - `APLICAR` - `APLICAR TOP 20` - 分数结合了主/客队相似度、交换风险、时间窗口和联赛/国家背景。 ### 10) 在 Booky 拒绝中保留的 provider 证据 - `src/services/bookySemiAutoService.js` 在包装 `placeWidget` 错误时保留 `providerStatus/providerBody/requestId`。 - 这改善了对明确拒绝 (`BOOKY_PLACEWIDGET_REJECTED`) 的审计和真实投注的事后分析。 ### 11) Chrome 配置文件中 Arcadia 与 Booky 的分离 - `services/pinnacleGateway.js` 现在默认使用 Pinnacle 的专用配置文件 (`data/pinnacle/chrome-profile`)。 - 移除了与 Arcadia 中 `BOOK_PROFILE` 的默认耦合。 - 保留通过环境变量 `PINNACLE_CHROME_PROFILE_DIR` 的覆盖。 ### 12) 具有会话状态的更精确的 Arcadia 登录 - `services/pinnacleGateway.js` 明确检测 Pinnacle 中何时已有活动会话 (`Account-Menu`,bankroll/存款)。 - 仅当检测到真实的登录块 (`header-login-loginButton`,`Forms-Element-username/password`) 时才尝试自动登录。 - 加强了与 header 选择器的兼容性 (`input#username`,`input#password`,在 `header-login-loginButton` 中提交)。 ### 13) ACity 自动登录移至正确位置 (Booky 脚本) - `scripts/extract-booky-auth-token.js` 和 `scripts/capture-altenar-betslip.js` 实现了 ACity 流程: - 触发 `button#login` / `#login`, - 检测 `input[name="user"]`, - 健壮的提交 (`INICIAR SESION` / `INGRESAR` + 回退)。 - 如果已登录 (header 中包含 `MIS APUESTAS` + `DEPOSITAR`),则跳过自动登录。 ### 14) Pinnacle 的专用配置文件配置 - `.env.example` 记录了: - `PINNACLE_CHROME_PROFILE_DIR=data/pinnacle/chrome-profile` - 操作建议:将 Arcadia 和 Booky 保留在单独的配置文件中,以避免会话污染。 ### 15) Altenar token 自动同步到 Google Sheets - `scripts/extract-booky-auth-token.js` 捕获并持久化: - `ALTENAR_BOOKY_AUTH_TOKEN` (用于真实 `placeWidget` 流程的 JWT),以及 - `ALTENAR_WIDGET_AUTH_TOKEN` (用于 scanner/live/prematch 的 `api/widget` 原始 token)。 - 到 Google Sheets 的同步仅为 `ALTENAR_BOOKY_AUTH_TOKEN` 执行。 - 用于 webhook 的环境变量: - `GSHEETS_TOKEN_WEBHOOK_URL` - 安全政策: - `.env.example` 仅包含该变量的示例/注释。 - `.env` (本地,未版本化) 必须包含 Apps Script 的真实 URL。 - 操作行为: - 如果未定义 webhook,token 捕获将继续而不会失败。 - 如果 webhook 失败,会记录 warning/error 但不会阻止 token 续订。 确切的更新顺序: 1. Puppeteer 检测到带有有效 `Authorization` 的 Altenar 请求。 2. 脚本更新 `.env` (`ALTENAR_BOOKY_AUTH_TOKEN=Bearer ...` 和/或 `ALTENAR_WIDGET_AUTH_TOKEN=`)。 3. 在同一次执行的同一时刻,立即向 webhook 发送带有 `{ token: "Bearer ..." }` 的 `POST` 请求。 4. Apps Script (`doPost`) 接收 payload 并更新 `TOKEN!A1`。 5. 提取过程以成功结束。 注意:在 `.env` 中保存之前不会执行到 Sheets 的同步;它总是在 token 本地更新插入之后发生。 发送到 webhook 的预期 payload 示例: ``` { "token": "Bearer " } ``` ### 16) 带有防循环的 widget token 自动续订 (401/403) - 后端不按固定间隔续订;仅当 Altenar 在扫描器的关键端点 (`GetLivenow`、`GetEventDetails`、`GetUpcoming`) 中响应认证错误 (`401` 或 `403`) 时才被动续订。 - 检测到 `401/403` 时,会在后台触发使用 Puppeteer 的 token 捕获脚本以刷新 `ALTENAR_WIDGET_AUTH_TOKEN`。 - 为避免循环 (多个扫描器同时失败),续订遵循每个进程的全局冷却时间: - `ALTENAR_WIDGET_TOKEN_RENEW_COOLDOWN_MS` (建议默认值:`120000`)。 - 自动捕获的最长时间由以下参数控制: - `ALTENAR_WIDGET_TOKEN_RENEW_TIMEOUT_MS` (建议默认值:`90000`)。 操作行为: 1. 在扫描器的 Altenar 调用中出现 `401/403`。 2. 尝试启动自动续订 (如果未处于冷却期)。 3. 如果最近已有尝试,则抑制新尝试并记录剩余秒数的警告。 4. 如果捕获在 `.env` 中获取了新 token,建议重启后端以干净地重新加载环境。 调优指南: - 正常操作:`ALTENAR_WIDGET_TOKEN_RENEW_COOLDOWN_MS=60000` 到 `120000`。 - 高负载/数据流噪音:保持 `120000` 或提高到 `180000`。 - 特定调试:暂时设置为 `30000`。 - 避免过低的值 (`<15000`) 以免批量打开 Puppeteer 流程。 ### 17) 针对 401/403 和集成不匹配更具鲁棒性的真实投放置 - `src/services/bookySemiAutoService.js` 现在明确区分 auth failures (`401/403`) 和市场拒绝。 - 如果 `placeWidget` 返回 `401/403`,后端会响应 `BOOKY_TOKEN_RENEWAL_REQUIRED` (428) 并附带诊断和辅助续订触发。 - 验证 JWT (`payload.Integration`) 是否与 `ALTENAR_INTEGRATION` 匹配;如果不匹配,则阻止确认并给出明确的原因。 - `GET /api/booky/token-health` 暴露了额外的信号: - `tokenIntegration` - `tokenUserName` - `integrationMismatch` ### 18) 与 widget auth 对齐的真实投注准备 - 在真实投放置的准备中,`GetEventDetails` 使用统一的公共配置 (`getAltenarPublicRequestConfig`) 以避免 headers/auth 的不对齐。 - 如果 `GetEventDetails` 响应 `401/403`,则返回 `BOOKY_WIDGET_TOKEN_RENEWAL_REQUIRED` 以及 `eventId` 和自动续订状态。 ### 19) UI 不同步时的自动票据恢复 - `client/src/App.jsx` 添加了在确认时出现 `ticket no encontrado` 时的受控恢复: - 搜索同一机会 (`eventId + selection + market`) 的有效 `DRAFT`。 - 使用恢复的票据仅重试一次 `confirm`。 - 如果确认,则避免假阴性并热刷新状态。 ### 20) Arcadia Live:当 WS 正常时的 HTTP 节流 - `services/pinnacleLight.js` 在以下情况减少冗余的 HTTP live 轮询: - websocket 已打开, - 有最近的帧, - 最后一个 HTTP 快照仍然新鲜。 - 保持定期的 HTTP 刷新以保持一致性并清理孤立的市场。 - 新的可选旋钮: - `PINNACLE_LIVE_HTTP_MAX_STALE_MS` (内部默认值 `20000`) - `PINNACLE_LIVE_WS_FRESH_WINDOW_MS` (内部默认值 `8000`) ## 🚀 核心功能 ### 🧠 量化核心引擎 **带有对数阻尼的同步凯利公式** - 凯利公式的进阶实现,避免了“任意截断”。 - 使用指数饱和函数:`Stake = Cap × (1 - e^(-Kelly/Cap))`。 - 允许具有巨大优势的下注获得更多资金,而不会危及资金池安全。 - **破产风险 (ROR):** < 0.5%,通过渐近控制实现。 **动态风险配置** 系统根据每种策略固有的波动性自动调整下注的激进程度: | 策略 | 凯利分数 | 波动性 | 用例 | |------------|----------------|-------------|-------------| | `PREMATCH_VALUE` | 0.25 (1/4) | 低 | 拥有可靠历史数据的赛前赔率 | | `LIVE_VALUE` | 0.125 (1/8) | 中 | 带有市场噪音的实时套利 | | `LIVE_SNIPE` | 0.10 (1/10) | 高 | "La Volteada" - 高度不确定性事件 | **基于净资产价值的注额计算** - 基于 `可用余额 + 活跃风险` 计算仓位规模。 - 避免在拥有多笔同时进行的下注时出现系统性的“投资不足”。 - 示例:如果余额为 $1000 并且有 $200 的活跃下注,系统基于 NAV = $1200 进行计算。 ### 🕵️ 专业扫描器 **1. Arcadia Gateway (真实来源)** - 与 Pinnacle API 的低延迟 WebSocket 连接。 - 通过消除保证金提取“公平”赔率。 - 当 token 过期时通过 Puppeteer 自动续订会话。 - 冻结数据 检测和自动重启。 **2. 赛前扫描器** - 每日扫描即将举行的事件 (48小时窗口)。 - 交叉比对 Pinnacle 与 Altenar 的赔率,识别赛前机会。 - 结合模糊逻辑 + Levenshtein Distance 的智能匹配器,用于名称标准化。 **3. 实时扫描器** - 具有**自适应轮询** (~2 秒到 ~7 秒,取决于活动/错误) 的高频扫描。 - 实时检测两种类型的机会: - **Value Bets Live:** 进行中事件的赔率差异。 - **"La Volteada":** 专策略 (见策略部分)。 **4. 监视仪表板** - Pinnacle 与 Altenar 赔率的实时比较视图。 - 趋势视觉指示器 (上/下箭头) 和更新脉冲。 - “未链接”事件检测 (无 Pinnacle 匹配)。 ### 🛡️ 安全系统 **僵尸协议 (自动恢复)** - 检测从实时数据流中消失的事件 (暂停、提前结束)。 - 自动查询结果 API (`GetEventResults`) 以进行精确清算。 - 防止投注无限期地卡在 PENDING 状态。 **防止重复下注** - 内存中的锁机制 (`processingBets Set`) 以防止重复下注。 - 针对手动丢弃事件的持久黑名单过滤器。 - 在注册机会之前进行最低注额 (S/1.00) 验证。 **陈旧数据检测** - 比较 Pinnacle 和 Altenar 之间的比赛时间。 - 如果差异超过 3 分钟,触发 WebSocket 的自动重启。 - 触发文件 (`pinnacle_stale.trigger`) 用于进程间通信。 ### 🎨 用户界面 (React + TailwindCSS) **多选项卡仪表板** 1. **赛前:** 具有计算出的 EV 和 Kelly 的未来机会列表。 2. **实时:** 实时检测到的机会 ("La Volteada" + Value Bets)。 3. **活跃:** 正在进行的下注,带有实时比分和时间追踪。 4. **历史:** 具有损益和统计数据的已清算投注完整记录。 5. **监视器:** Pinnacle vs Altenar 赔率视觉比较器 (专业模式)。 6. **匹配器:** 用于手动链接系统未能自动关联的事件的工具。 ## 📊 交易策略 ### 1. 赛前价值下注 **描述:** 检测赛前赔率之间的差异。 **流程:** 1. 每日从 Pinnacle 摄入即将举行的事件 (“公平”赔率)。 2. 标准化球队和联赛名称 (模糊匹配)。 3. 与同一事件中 Altenar 的赔率进行比较。 4. 当以下条件成立时识别价值:`真实概率 × Altenar赔率 > 1`。 **优势:** - 数据稳定 (无波动)。 - 有更多时间进行手动分析。 - 突然变化的风险较低。 **风险:** 低 (0.25 Kelly)。 ### 2. 实时价值下注 **描述:** 正在进行的事件中的算法套利。 **流程:** 1. 使用**自适应轮询** (~2 秒到 ~7 秒,取决于活动和错误) 持续扫描实时比赛。 2. 实时比较更新的赔率。 3. 通过 Pinnacle Live 公平赔率检测正价值。 4. 如果 Kelly 建议 stake ≥ S/1.00 则执行。 **优势:** - 频繁的机会。 - 赔率波动更大 = 利润更高。 **风险:** 中 (0.125 Kelly)。 ### 3. "La Volteada" (实时狙击策略) **描述:** 检测潜在逆转的专有策略。 **入场条件:** 1. **事件特征:** 赛前热门 (真实概率 > 55%)。 2. **比赛状态:** 热门球队**恰好落后 1 球**。 3. **时间窗口:** 比赛第 15 - 80 分钟。 4. **统治力验证:** - 无红牌 (红牌 = 0)。 - 统计数据 (控球率,射门) 有利于热门球队 (可选)。 **数学逻辑:** - 使用 Pinnacle Live 赔率重新计算逆转概率。 - 由于高波动性,应用超保守的 Kelly (0.10)。 - 寻找 Altenar 虚高的赔率 (通常对于热门球队 > 2.5 倍)。 **真实示例:** ``` Tigres UANL (Favorito Pre-Match: ~70%) vs Pumas Score Actual: 0-1 (Tigres perdiendo) - Minuto 35' Cuota Pinnacle Live (Tigres): 1.50 → Prob Real: ~60% Cuota Altenar (Tigres): 2.20 → EV = 32% Kelly (0.10): Stake sugerido = $8 (NAV = $1200) ``` **优势:** - 利用市场恐慌 (Altenar 高估了弱队)。 - 在波动性联赛中出现频率高。 **风险:** 高 (0.10 Kelly)。需要快速清算。 ### 4. 下一个进球价值 (大小) **描述:** 检测大小盘市场的进攻压力。 **条件:** 1. 控球率 > 60% 的统治球队。 2. 射门差距 > 3。 3. 分钟 > 60'。 **目标:** 当比赛“激烈”时投注 "Over 2.5" 或 "Over 3.5"。 **状态:** 实验性 (需要校准)。 ## 💰 财务管理 (投资组合理论) ### 凯利公式:背后的数学原理 **凯利公式** 根据统计优势确定承担风险的资金的最优分数: $$f^* = \frac{bp - q}{b}$$ 其中: - `p` = 获胜的真实概率 (Pinnacle 公平赔率) - `q` = 失败的概率 (1 - p) - `b` = 每单位下注的净利润 (赔率 - 1) **纯凯利公式的问题:** 在其原始形式中,凯利公式在高优势情况下可能建议非常大的下注 (资金的 10-20%),使交易者暴露于高波动性中。 ### 已实施的改进 **1. 分数凯利** - 对纯凯利的保守乘数。 - 以较低的增长率换取较低的波动性。 - BetSniper 根据市场波动性使用自适应分数。 **2. 对数阻尼** 我们不是任意削减大额下注,而是应用: $$Stake_{Real} = Cap \times (1 - e^{-\frac{Stake_{Kelly}}{Cap}})$$ **效果:** - 小额下注 (< 2%):几乎呈线性增长 (不受惩罚)。 - 大额下注 (> 5%):向 Cap (3.5%) 渐近增长。 - **结果:** 利用巨大优势而不会冒破产风险。 **概念图:** ``` Stake Real (%) │ 3.5%├─────────────────────── (Asíntota) │ ╱─ │ ╱─ 2.0%│ ╱─ │ ╱─ 1.0%│ ╱─ │╱──────────────────────→ Kelly Crudo (%) 0 2 4 6 8 10 ``` ### NAV (净资产价值) **定义:** 总资产 = 可用余额 + 活跃下注的注额。 **为什么要使用它?** - 场景:你有 $1000 的余额和 5 笔各 $50 的活跃下注 ($250 在游戏中)。 - **常见错误:** 基于 $1000 计算 Kelly → 在新机会上投资不足。 - **NAV 解决方案:** 基于 $1250 (NAV) 计算 Kelly → 按比例分配真实资产的下注。 **实现:** ``` const currentNAV = portfolio.balance + portfolio.activeBets.reduce((sum, b) => sum + b.stake, 0); const kellyStake = calculateKellyStake(realProb, odd, currentNAV, strategy); ``` ### 风险控制 **执行前验证:** 1. **最低注额:** S/1.00 (避免不切实际的微型下注)。 2. **流动性:** 下注不得超过可用余额 (即使 NAV 建议)。 3. **重复检查:** 验证同一事件中不存在活跃下注。 4. **黑名单:** 过滤手动丢弃的事件。 **自动清算:** - **赛前:** 开始后 2.2 小时的缓冲区,然后验证结果。 - **实时:** 如果 `时间 >= 90'` 或事件从数据流中消失,立即清算。 - **僵尸投注:** 如果 `GetEventDetails` 失败,则查询结果 API。 ## 🛠️ 系统架构 ### 组件图 ``` ┌─────────────────────────────────────────────────────────────┐ │ FRONTEND (React) │ │ ┌──────────┬───────────┬──────────┬──────────┬──────────┐ │ │ │ Pre-Match│ En Vivo │ Activas │Historial │ Monitor │ │ │ └────┬─────┴─────┬─────┴─────┬────┴────┬─────┴────┬─────┘ │ │ │ │ │ │ │ │ └───────┼───────────┼───────────┼─────────┼──────────┼───────┘ │ │ │ │ │ └───────────┴───────────┴─────────┴──────────┘ ▼ ┌───────────────────────────────────────────────────┐ │ EXPRESS API (server.js) │ │ ┌─────────────────────────────────────────────┐ │ │ │ Background Scanner (Bucle Infinito) │ │ │ │ - Pre-Match Scan (cada 2 min) │ │ │ │ - Live Scan (polling adaptativo) │ │ │ │ - Active Bets Monitoring │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ API Routes │ │ │ │ /api/opportunities │ │ │ │ /api/portfolio │ │ │ │ /api/monitor │ │ │ │ /api/matcher │ │ │ │ /api/booky │ │ │ └─────────────────────────────────────────────┘ │ └──────────────┬──────────────────┬────────────────┘ │ │ ┌──────────────▼─────┐ ┌────────▼──────────────┐ │ LowDB (db.json) │ │ Axios Clients │ │ - Matches │ │ - Altenar API │ │ - Portfolio │ │ - Pinnacle (REST) │ │ - Blacklist │ └───────────────────────┘ └────────────────────┘ ┌───────────────────────┐ │ services/ │ │ pinnacleLight.js │ │ (Proceso Separado) │ │ │ │ ┌──────────────────┐ │ │ │ Puppeteer │ │ │ │ (Chrome Headless)│ │ │ └────────┬─────────┘ │ │ │ │ │ ▼ │ │ WebSocket Client │ │ (wss://arcadia) │ │ │ │ │ ▼ │ │ pinnacle_live.json │ └──────────────────────┘ ``` ### 数据流 (实时交易) 1. **摄入 (终端 2 - `pinnacleLight.js`):** - Puppeteer 导航到 Pinnacle 并提取认证 headers。 - 在 `wss://api.arcadia.pinnacle.com/ws` 打开 WebSocket。 - 大约每 500ms 接收一次帧,进行解析并写入 `data/pinnacle_live.json`。 2. **处理 (终端 1 - `server.js`)** - 后台扫描器以自适应轮询 (~2秒到 ~7秒) 读取 `pinnacle_live.json`。 - 查询 Altenar 中的实时事件 (`GetLivenow`)。 - 模糊匹配器链接 Pinnacle ↔ Altenar 事件。 - 评估策略条件 (价值、Volteada、下一个进球)。 - 计算 Kelly 并在缓存中注册机会。 3. **展示 (终端 3 - `client/`):** - 前端每 5 秒查询一次 `/api/opportunities`。 - 在“实时”选项卡中渲染机会。 - 用户可以执行手动下注 ("APOSTAR" 按钮)。 4. **执行 (模拟交易):** - `placeAutoBet()` 在 `db.json` 中注册下注。 - 从余额中扣除 stake。 - 添加到 `activeBets` 列表。 5. **监控:** - 在扫描器的每个周期,`updateActiveBetsWithLiveData()` 验证: - 事件是否仍在进行中 (更新比分/时间)。 - 是否已结束 (查询 `GetEventDetails` 或 `GetEventResults`)。 - 如果有官方结果则清算下注。 ## 🔧 预操作配置指南 在安装系统之前,您需要在 BetSniper 使用的外部服务中拥有活跃的账户。本节详细说明了**要开立哪些账户**、**从每个账户中提取哪些数据**以及**如何将它们放入 `.env`**。 ### 步骤 1:您需要订阅的服务 #### 1A. Pinnacle (必需 — 真实概率来源) | 字段 | 详情 | |---|---| | **Web** | [pinnacle.com](https://www.pinnacle.com) | | **类型** | Sharp Bookie — 极低利润率,接受赢家 | | **你需要什么** | 拥有对 "Sports" 部分 (可见的 Live Soccer) 访问权限的活动账户 | | **限制** | 并非在所有国家都可用。如有必要,请使用 VPN (推荐:NL 或 MT 服务器)。 | | **在 BetSniper 中的用途** | 仅作为赔率来源。**不在 Pinnacle 上下注。** | | **成本** | 免费 (您只需要账户即可访问实时赔率 API) | #### 1B. DoradoBet (live 模式必需 — 主要目标 bookie) | 字段 | 详情 | |---|---| | **Web** | [doradobet.com](https://doradobet.com) | | **平台** | Altenar (与 ACity 相同的后端) | | **你需要什么** | 具有真实余额的注册账户 | | **`.env` 中的配置文件** | `BOOK_PROFILE=doradobet` | | **在 BetSniper 中的用途** | Value bets 检测 + 真实下注 (如果您启用 `BOOKY_REAL_PLACEMENT_ENABLED`) | | **限制** | 主要在秘鲁可用。如果您从其他国家/地区操作,请验证可用性。 | #### 1C. Casino Atlantic City — ACity (备选 — 相同的 Altenar 引擎) | 字段 | 详情 | |---|---| | **Web** | [casinoatlanticcity.com/apuestas-deportivas](https://www.casinoatlanticcity.com/apuestas-deportivas) | | **平台** | Altenar (相同的 API,不同的 `integration` 和 `origin`) | | **你需要什么** | 具有真实余额的注册账户 | | **`.env` 中的配置文件** | `BOOK_PROFILE=acity` | | **在 BetSniper 中的用途** | DoradoBet 的替代品。您可以在单独的会话中同时操作两者。 | ### 步骤 2:`.env` 的详细配置 复制模板文件: ``` cp .env.example .env ``` 然后按照本指南逐个变量地编辑 `.env`: #### 🔧 系统变量 ``` NODE_ENV=development ``` ``` PORT=3000 ``` ``` TZ=America/Lima ``` ``` DISABLE_BACKGROUND_WORKERS=false DISABLE_LIVE_SCANNER=false DISABLE_PREMATCH_SCHEDULER=false DISABLE_PINNACLE_INGEST_CRON=false DISABLE_MONITOR_DASHBOARD=false # 实时调优 LIVE_VALUE_MIN_EV=0.02 LIVE_VALUE_MIN_DISPLAY_STAKE=0.10 LIVE_VALUE_NON_1X2_STAKE_FACTOR=1 LIVE_SNIPE_REQUIRE_PINNACLE_LIVE=true LIVE_VALUE_REQUIRE_SCORE_SYNC=true LIVE_VALUE_SCORE_SYNC_MAX_GOAL_DIFF=0 LIVE_VALUE_ENABLE_STABILITY_FILTER=true LIVE_VALUE_STABILITY_MIN_HITS=2 LIVE_VALUE_STABILITY_MIN_AGE_MS=4000 LIVE_GLOBAL_STABILITY_ENABLED=true LIVE_GLOBAL_STABILITY_MIN_HITS=2 # 投注时 prematch 热重算 PREMATCH_REFRESH_RECALCULATE_PINNACLE=true PREMATCH_PINNACLE_CACHE_TTL_MS=15000 # prematch 混合下载窗口(滑动 + 预加载) PREMATCH_WINDOW_PRIMARY_HOURS=6 PREMATCH_WINDOW_PREFETCH_HOURS=6 PREMATCH_WINDOW_OVERLAP_MINUTES=30 ``` #### 🎯 Altenar 配置文件变量 (目标 Bookie) 这些变量将通过 `npm run book:dorado` 或 `npm run book:acity` 自动写入。但是如果您更希望手动编辑它们: **对于 DoradoBet:** ``` BOOK_PROFILE=doradobet ALTENAR_INTEGRATION=doradobet ALTENAR_ORIGIN=https://doradobet.com ALTENAR_REFERER=https://doradobet.com/deportes-en-vivo ``` **对于 ACity:** ``` BOOK_PROFILE=acity ALTENAR_INTEGRATION=casinoatlanticcity ALTENAR_ORIGIN=https://www.casinoatlanticcity.com ALTENAR_REFERER=https://www.casinoatlanticcity.com/apuestas-deportivas ``` **通用项 (除非 bookie 更改国家/地区,否则请勿更改):** ``` ALTENAR_COUNTRY_CODE=PE # Código ISO del país de la cuenta ALTENAR_CULTURE=es-ES # Idioma de la API (no cambiar) ALTENAR_TIMEZONE_OFFSET=300 # UTC-5 (Perú). GMT-4=240, GMT-6=360 ALTENAR_NUM_FORMAT=en-GB # VITAL: garantiza decimales con punto (1.50 no 1,50) ALTENAR_DEVICE_TYPE=1 # 1=Desktop. No cambiar. ALTENAR_SPORT_ID=0 # 0=todos los deportes. 66=solo fútbol. ``` #### 🔐 Booky 认证变量 (用于真实下注) 这**仅在您希望执行真实下注时**才需要。在模拟交易模式下您可以跳过本节。 **步骤 1 — Bookie 访问 URL:** ``` # DoradoBet: ALTENAR_BOOKY_URL=https://doradobet.com/deportes-en-vivo # ACity: ALTENAR_BOOKY_URL=https://www.casinoatlanticcity.com/apuestas-deportivas#/overview ``` **步骤 2 — 您的账户凭据:** ``` ALTENAR_LOGIN_USERNAME=tu_email_o_usuario ALTENAR_LOGIN_PASSWORD=tu_contraseña ``` **步骤 3 — 捕获真实的 JWT:** 在 `.env` 中配置好凭据后,运行: ``` # 打开 Chrome,自动登录并等待你关闭窗口 npm run token:booky:wait-close # 备选方案:使用 90 秒 timeout 的 headless 模式 npm run token:booky:timeout ``` 该脚本会自动写入您的 `.env`: ``` ALTENAR_BOOKY_AUTH_TOKEN=Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXV... ``` #### 🛡️ 安全变量 — 真实投放置防护 ``` BOOKY_REAL_PLACEMENT_ENABLED=false ``` ``` BOOKY_TOKEN_MIN_REMAINING_MINUTES=2 ``` ``` BOOKY_MIN_EV_PERCENT=2 ``` ``` BOOKY_MAX_ODD_DROP=0.20 ``` ``` BOOKY_AUTO_TOKEN_REFRESH_ENABLED=true ``` ``` BOOKY_KEEP_REAL_PLACEMENT_ON_TOKEN_REFRESH=false ``` #### 🧮 Pinnacle ↔ Altenar 匹配器变量 ``` MATCH_DIAGNOSTIC_LOG=1 ``` ``` MATCH_FUZZY_THRESHOLD=0.77 ``` ``` MATCH_MIN_ACCEPT_SCORE=0.60 ``` ``` MATCH_TIME_TOLERANCE_MINUTES=5 ``` ``` MATCH_TIME_EXTENDED_TOLERANCE_MINUTES=30 ``` #### 🧹 内务处理变量 (可选) ``` BOOKY_BALANCE_REFRESH_MS=45000 ``` ``` BOOKY_HISTORY_REFRESH_MS=60000 ``` ``` BOOKY_HISTORY_RETENTION_DAYS=30 ``` ``` BOOKY_PROFILE_HISTORY_MAX_ITEMS=500 ``` ``` BOOKY_ORPHAN_ACTIVE_GRACE_MS=120000 ``` ### 步骤 3:摘要 — 哪些是必选项,哪些是可选项? | 变量 / 步骤 | 模拟交易 | 实时真实下注 | |---|:---:|:---:| | 活跃的 Pinnacle 账户 | ✅ | ✅ | | 具有余额的 DoradoBet 或 ACity 账户 | ❌ | ✅ | | `BOOK_PROFILE` + `ALTENAR_*` | ✅ | ✅ | | `ALTENAR_LOGIN_USERNAME` + `PASSWORD` | ❌ | ✅ | | `ALTENAR_BOOKY_AUTH_TOKEN` | ❌ | ✅ | | `BOOKY_REAL_PLACEMENT_ENABLED=true` | ❌ | ✅ | | 防护 (`BOOKY_MIN_EV_PERCENT` 等) | ❌ | ✅ 推荐 | | `MATCH_*` (匹配器调优) | 可选 | 可选 | ## 📦 安装与部署 ### 先决条件 - **Node.js:** v18.0.0 或更高版本 - **npm:** v8.0.0 或更高版本 - **操作系统:** Windows, macOS 或 Linux - **Chromium:** 由 Puppeteer 自动安装 (首次启动时) - **RAM:** 建议最少 4GB (Node.js 2GB + Chromium 2GB) ### 快速安装 ``` # 1. 克隆仓库 git clone https://github.com/tu-usuario/betsniper-v3.git cd betsniper-v3 # 2. 安装 Backend 依赖 npm install # 3. 安装 Frontend 依赖 cd client npm install cd .. # 4. 配置环境变量(可选) cp .env.example .env # 如果需要自定义端口或配置,请编辑 .env ``` ### 生成的文件结构 系统将在首次启动时自动创建这些目录和文件: ``` data/ ├── pinnacle_live.json # Feed en tiempo real de Pinnacle ├── pinnacle_token.json # Headers de autenticación (auto-renovado) └── pinnacle_stale.trigger # Flag para reinicio de socket (auto-generado) db.json # Base de datos local (creada por LowDB) ``` ### 执行模式:3终端架构 为了进行完整操作,请**并行**执行这些命令 (在 3 个不同的终端中): #### **终端 1:后端服务器 (必需)** 启动 REST API、数据库和后台扫描器。 ``` npm run dev ``` **它的作用是什么?** - 在 `http://localhost:3000` 上暴露 API - 每 2 小时执行一次 Pinnacle/Altenar 的自动摄入 - 循环执行 Live 机会扫描器 (根据活动自适应轮询) - 监控活跃下注并自动清算 **预期日志:** ``` 🚀 Servidor BetSniper V3 corriendo en http://localhost:3000 📝 Modo: development 🔄 Background Scanner Iniciado (Modo Seguro Anti-Ban) + AUTO-TRADING ACTIVO ⏰ [CRON] Ejecutando Ingesta Automática de Pinnacle... ``` #### **终端 2:Pinnacle 摄入 (Live 必需)** 保持与 Pinnacle 的 WebSocket 连接并保存实时赔率。 ``` node services/pinnacleLight.js ``` **首次启动 (身份验证):** - 如果不存在 `data/pinnacle_token.json`,脚本将自动打开一个 **Chrome 窗口**。 - **所需操作:** 在该窗口中手动登录 Pinnacle。 - 一旦您导航到 "Live Soccer" 部分,脚本将自动捕获 headers。 - 当您看到消息 `💾 Token actualizado en disco` 时,**关闭 Chrome 窗口**。 - 脚本将继续运行 WebSocket。 **自动续订:** - 如果 token 过期 (大约每 ~1 小时),脚本会检测到并再次打开 Chrome。 - 重复手动登录过程。 **预期日志:** ``` 🚀 Starting Pinnacle Auth Scraper (Direct WS)... ✅ Headers cargados y válidos (Generados: 14:32:15). 🔌 Conectando al WebSocket... ✅ WebSocket Conectado! (Esperando frames...) 📡 FRAME: Straight - Updates: 12 💾 Datos guardados en disco (6 eventos). ``` #### **终端 3:前端 (UI 必需)** 在开发模式下启动 React 界面。 ``` cd client npm run dev ``` **URL:** `http://localhost:5173` **预期日志:** ``` VITE v5.0.0 ready in 324 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help ``` ### 可选工具 #### Booky 流程 (配置文件、token、捕获、冒烟测试) ``` # 1) 选择操作配置文件 npm run book:acity # 或 npm run book:dorado # 2) 捕获真实 auth token(打开 Chrome) npm run token:booky:wait-close # 3) 捕获 placeWidget/betslip payloads npm run capture:booky # 4) 检查是否存在最新的捕获(在克隆新设备/新机器上为必填) # PowerShell / Bash (Git Bash) curl -sS --compressed http://localhost:3000/api/booky/capture/latest # 应返回:{"success":true,"found":true,...} # 4.1) placeWidget 的快速健康检查(无噪音输出) # 选项 A(如果有 jq): curl -sS --compressed http://localhost:3000/api/booky/token-health | jq.exe '{success,authenticated:.token.authenticated,jwtValid:.token.jwtValid,expired:.token.expired,remainingMinutes:.token.remainingMinutes,expIso:.token.expIso}' curl -sS --compressed "http://localhost:3000/api/booky/account?refresh=1" | jq.exe '{success,balance:.balance.amount,currency:.balance.currency,stale:.balance.stale,updatedAt:.balance.updatedAt,source:.balance.source}' curl -sS --compressed http://localhost:3000/api/booky/capture/latest | jq.exe '{success,found,profile,generatedAt,totalCaptured}' # 选项 B(如果 jq 不可用): curl -sS --compressed http://localhost:3000/api/booky/token-health | python -c "import sys,json; d=json.load(sys.stdin); t=d.get('token') or {}; print({'success':d.get('success'),'authenticated':t.get('authenticated'),'jwtValid':t.get('jwtValid'),'expired':t.get('expired'),'remainingMinutes':t.get('remainingMinutes'),'expIso':t.get('expIso')})" curl -sS --compressed "http://localhost:3000/api/booky/account?refresh=1" | python -c "import sys,json; d=json.load(sys.stdin); b=d.get('balance') or {}; print({'success':d.get('success'),'amount':b.get('amount'),'currency':b.get('currency'),'stale':b.get('stale'),'updatedAt':b.get('updatedAt'),'source':b.get('source')})" curl -sS --compressed http://localhost:3000/api/booky/capture/latest | python -c "import sys,json; d=json.load(sys.stdin); print({'success':d.get('success'),'found':d.get('found'),'profile':d.get('profile'),'generatedAt':d.get('generatedAt'),'totalCaptured':d.get('totalCaptured')})" # placeWidget 的最低健康标准: # - token:authenticated=true, jwtValid=true, expired=false, remainingMinutes > 2 # - wallet:success=true, stale=false, updatedAt 为近期时间 # - 捕获:found=true, totalCaptured > 0 且 generatedAt 为近期时间 # - payload 验证:POST /api/booky/real/dryrun/:id 必须返回 success=true # 5) 检查 token 健康状况及安全流程(非真实投注) npm run smoke:booky # 6) 手动清理孤立的进行中记录(如果 UI 显示幽灵 EN JUEGO 状态) npm run cleanup:booky:orphans ``` 对于受控的真实发送测试 (仅在您启用 `BOOKY_REAL_PLACEMENT_ENABLED=true` 时): ``` npm run smoke:booky:live ``` #### 快速检查清单:在 20 秒内激活真实交易 1. 确认 token 有效:`GET /api/booky/token-health` (无 `expired`,剩余分钟数 > 2)。 2. 确认捕获就绪:`GET /api/booky/capture/latest` 显示 `found: true`。 3. 在发送真实请求之前对机会执行 dry-run:`POST /api/booky/real/dryrun/:id`。 4. 然后启用 `BOOKY_REAL_PLACEMENT_ENABLED=true`。 5. 保持 `BOOKY_KEEP_REAL_PLACEMENT_ON_TOKEN_REFRESH=false` 以进行保守操作。 6. 会话结束时,恢复为 `BOOKY_REAL_PLACEMENT_ENABLED=false`。 有用的清理脚本选项: ``` # 仅输出 JSON npm run cleanup:booky:orphans -- --json # 清理特定的 profile npm run cleanup:booky:orphans -- --profile=acity # 使用远程 cache(不强制刷新) npm run cleanup:booky:orphans -- --refresh=false ``` #### 手动扫描器 (观察者模式) 如果您希望实时查看检测到的每个机会的详细日志**而不干扰服务器**: ``` node scripts/scan_live.js --dry-run ``` **重要提示:** 如果服务器已经在运行,`--dry-run` 标志是**必需的**。否则,两个进程将尝试同时注册下注 (存在重复风险)。 **输出:** ``` 🟢 INICIANDO LIVE SNIPER (Intervalo: 60s) [MODO: OBSERVADOR (Dry Run)]... 🛡️ Dry Run: No se ejecutarán apuestas, solo detección. 🎯 Pinnacle Live Found: Home=1.155, Away=11.83 -> RealProb(away)=7.7% 🔥 OPORTUNIDADES EN VIVO DETECTADAS 🔥 ┌─────┬──────────────────────┬───────┬──────┬──────────┬─────────┬─────┬──────────┬───────┐ │Match│ CS Constantine (F) │ Score │ Time │ Strategy │ Real % │ Odd │ Kelly $ │ EV │ ├─────┼──────────────────────┼───────┼──────┼──────────┼─────────┼─────┼──────────┼───────┤ │ ... │ Afak Relizane (F) │ 1-0 │ 62' │ LIVE_VAL │ 7.7% │37.0 │ $12.30 │185.9% │ └─────┴──────────────────────┴───────┴──────┴──────────┴─────────┴─────┴──────────┴───────┘ ``` #### 手动数据摄入 如果您希望强制更新赛前数据库而无需等待自动 cron 任务: ``` # 更新 Altenar 事件 (DoradoBet) node scripts/ingest-altenar.js # 更新 Pinnacle 事件 node scripts/ingest-pinnacle.js ``` **用法:** 每天执行一次或在赛前交易会话之前执行。 ## 🖥️ 用户界面 (仪表板) ### 概览 该仪表板专为专业交易者设计,拥有 6 个专门的选项卡: ``` ┌─────────────────────────────────────────────────────────────────┐ │ 🎯 BetSniper V3 |Balance: S/1,234.56| ROI: +12.3%| │ ├─────────────────────────────────────────────────────────────────┤ │ [Pre-Match] [En Vivo] [Activas] [Historial] [Monitor] [Matcher]│ ├─────────────────────────────────────────────────────────────────┤ │ │ │ [Contenido dinámico según pestaña seleccionada] │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 1. 赛前 (未来机会) **目的:** 检测尚未开始的事件中的 value bets。 **列:** - **比赛:** 事件名称 (主队 vs 客队)。 - **联赛:** 比赛和国家。 - **时间:** 开始的日期和时间 (调整为本地时区)。 - **PIN (Pinnacle):** 计算出的无利润加成的“公平”赔率。 - **ALT (Altenar):** DoradoBet 提供的赔率。 - **EV%:** 期望值。例如:`15.2%` = 每投注 S/1 的预期收益。 - **Kelly:** 建议的投注额 (S/)。 - **操作:** `APOSTAR` 按钮 (在模拟交易中注册)。 **过滤器:** - 最低 EV:仅显示 EV > 5% 的机会。 - 最长时间:未来 X 小时内的事件。 ### 2. 实时 (实时机会) **目的:** 正在进行的比赛中检测到的机会。 **特殊指示器:** - **🔥 红色徽章:** "La Volteada" (热门球队落后)。 - **⚡ 绿色徽章:** Value Bet Live (赔率差异)。 - **⚽ 蓝色徽章:** Next Goal (进攻压力)。 **附加信息:** - **当前比分:** `1-0` (实时更新)。 - **分钟:** `67'` (与 Pinnacle 同步)。 - **红牌:** 🟥 (如果有红牌,"La Volteada" 将被停用)。 **示例:** ``` ┌───────────────────────────────────────────────────────────────────────┐ │ 🔥 LIVE SNIPE │ Tigres UANL vs Pumas │ 0-1 │ 42' │ EV: 28% │ S/8 │ │ Favorito perdiendo. Prob Real: 62% | Cuota ALT: 2.20 │ │ [📊 VER STATS] [💰 APOSTAR] │ └───────────────────────────────────────────────────────────────────────┘ ``` ### 3. 活跃 (进行中的投注) **目的:** 实时监控待处理下注。 **列:** - **比赛:** 押注的事件。 - **选择:** `Home` / `Draw` / `Away` (如果是 Total,则为特定盘口)。 - **Stake:** 投注金额 (S/)。 - **赔率:** 下注时的 Odd。 - **当前比分:** 实时比分 (每 5 秒更新一次)。 - **时间:** 比赛分钟数。 - **状态:** - 🟢 `WINNING` (正在赢) - 🟡 `PENDING` (结果不确定) - 🔴 `LOSING` (正在输) - **潜在:** 赢的利润 / 输的损失。 **操作:** - 查看详情 (`🔍` 完整的比赛统计数据)。 - 手动兑现 (在模拟交易中禁用)。 ### 4. 历史记录 (已清算投注) **目的:** 历史表现分析。 **汇总指标 (Header):** ``` Total Apostado: S/1,234.00 | Ganado: S/1,421.30 | ROI: +15.2% | Win Rate: 58.3% ``` **投注表格:** - **日期:** 执行的时间戳。 - **比赛:** 事件。 - **策略:** `PREMATCH` / `LIVE_SNIPE` / `LIVE_VALUE`。 - **结果:** ✅ `WON` / ❌ `LOST`。 - **P&L:** 盈亏。 **过滤器:** - 按日期 (过去 7 天,30 天,全部)。 - 按策略。 - 按结果 (仅赢 / 仅输)。 **导出:** `📥 Exportar CSV` 按钮,用于外部分析。 ### 5. 监视器 (赔率比较器) **目的:** 所有实时比赛的专业实时视图。 **布局:** ``` ┌──────────────────────┬───────────────────────┬───────────────────────┐ │ PARTIDO / TIEMPO │ PINNACLE (Live & Pre) │ ALTENAR (Bookie) │ ├──────────────────────┼───────────────────────┼───────────────────────┤ │ Liverpool vs Man Utd │ 1 │ X │ 2 │ 1 │ X │ 2 │ │ PIN: 72' │ 2-1 │ 1.45 │ 4.5 │ 7.2 │ 1.38 │ 4.8 │ 8.5 │ │ ALT: 72' │ 2-1 │ ▲ │ ● │ ▼ │ ● │ ● │ ● │ └──────────────────────┴───────────────────────┴───────────────────────┘ ``` **指示器:** - **▲ 绿色:** 赔率上升 (潜在机会)。 - **▼ 红色:** 赔率下降。 - **● 蓝色:** 赔率稳定 (脉冲 = 新鲜数据)。 - **紫色徽章:** 赛前赔率供参考。 **额外列:** - **PIN Goals / ALT Goals:** 大小盘市场 (Over/Under 2.5, 1.5, 3.5)。 **用途:** 手动检测自动扫描器可能已过滤掉的机会。 ### 6. 匹配器 (手动链接) **目的:** 供用户强制在系统无法自动关联的 Pinnacle 和 Altenar 事件之间进行匹配的工具。 **用例:** - 名称差异非常大 (例如:"Man City" vs "Manchester City FC")。 - 具有歧义名称的联赛。 - 未能完全覆盖的小联赛事件。 **流程:** 1. 未匹配的 Altenar 事件列表。 2. 点击 `SUGERIR` 以生成 `High Confidence` 候选。 3. 检查建议并使用 `APLICAR` 或 `APLICAR TOP 20` 应用。 4. 对于特定情况,在 Pinnacle 列表中手动搜索并使用 `VINCULAR`。 5. 系统将映射保存在 `db.json` 中。 6. 未来的检测将使用此保存的匹配和后端的动态别名。 ## 🔌 API 端点 服务器暴露了以下 REST 端点: ### **机会** **`GET /api/opportunities/prematch`** - **描述:** 返回赛前 value bets。 - **响应:** ``` { "success": true, "data": [ { "eventId": 15234567, "match": "Real Madrid vs Barcelona", "league": "La Liga", "date": "2026-02-20T20:00:00.000Z", "pinnaclePrice": 2.15, "altenarPrice": 2.35, "realProb": 46.5, "ev": 9.3, "kellyStake": 12.50, "selection": "Home" } ] } ``` **`GET /api/opportunities/live`** - **描述:** 返回实时机会。 - **缓存:** 5 秒。 **`GET /api/opportunities/live/placement-provider`** - **描述:** 返回用于自动投放置的活动 provider。 - **响应:** `{ "success": true, "provider": "booky", "allowed": ["booky", "pinnacle"] }` **`POST /api/opportunities/live/placement-provider`** - **Body:** `{ "provider": "booky" }` 或 `{ "provider": "pinnacle" }` - **描述:** 热切换自动投放置 provider,无需重启后端。 **`POST /api/opportunities/discard`** - **Body:** `{ "eventId": 123456 }` - **描述:** 将事件添加到黑名单 (不再显示)。 ### **投资组合 (模拟交易)** **`GET /api/portfolio`** - **描述:** 资金池的当前状态。 - **响应:** ``` { "balance": 1234.56, "initialCapital": 1000.00, "activeBets": [ { "id": "1708176543210", "match": "Tigres vs Pumas", "selection": "Home", "stake": 8.00, "odd": 2.20, "status": "PENDING", "score": "0-1", "liveTime": "42'" } ], "history": [...] } ``` **`POST /api/portfolio/bet`** - **Body:** 完整的机会对象。 - **描述:** 执行手动下注 (模拟交易)。 **`POST /api/portfolio/reset`** - **描述:** 将投资组合重置为初始资本。 - **⚠️ 危险:** 删除所有历史记录。 ### **监视器** **`GET /api/monitor/live-odds`** - **描述:** Pinnacle 与 Altenar 的比较数据流。 - **格式:** 带有嵌套 odds 的事件数组。 - **更新:** 实时 (读取 `pinnacle_live.json` + 查询 Altenar)。 ### **匹配器** **`GET /api/matcher/unlinked`** - **描述:** 没有 Pinnacle 匹配的 Altenar 事件。 **`POST /api/matcher/link`** - **Body:** `{ "altenarId": 123, "pinnacleId": 456 }` - **描述:** 强制手动链接。 ### **Booky (半自动 + 受控真实交易)** **`GET /api/booky/tickets`** - 返回待处理票据 + booky 历史记录。 **`POST /api/booky/prepare`** - 从机会中准备草稿票据。 **`POST /api/booky/confirm/:id`** - 在半自动模式下确认票据 (在投资组合中镜像)。 **`POST /api/booky/cancel/:id`** - 取消草稿票据。 **`GET /api/booky/token-health`** - 真实 JWT 的状态 (`exp`,剩余分钟,认证)。 **`POST /api/booky/token/renew`** - 触发辅助 token 续订。 **`GET /api/booky/account?refresh=1&historyLimit=60`** - 按配置文件的真实账户快照 (余额 + 已对账的远程历史记录)。 **`GET /api/booky/capture/latest`** - `data/booky` 中的最新 payload 捕获。 **`POST /api/booky/real/dryrunid`** - 构建最终的 `placeWidget` payload,而不发送真实下注。 **`POST /api/booky/real/confirm/:id`** - 标准真实确认 (带有防护)。 **`POST /api/booky/real/confirm-fast/:id`** - 具有不确定状态处理和受控重试的快速真实确认。 ## ⚙️ 高级配置 ### 环境变量 (`.env`) ``` # 核心 NODE_ENV=development PORT=3000 TZ=America/Lima DISABLE_BACKGROUND_WORKERS=false # Altenar Profile (set-book-profile.js) BOOK_PROFILE=doradobet ALTENAR_INTEGRATION=doradobet ALTENAR_ORIGIN=https://doradobet.com ALTENAR_REFERER=https://doradobet.com/deportes-en-vivo ALTENAR_COUNTRY_CODE=PE ALTENAR_CULTURE=es-ES ALTENAR_TIMEZONE_OFFSET=300 ALTENAR_NUM_FORMAT=en-GB ALTENAR_DEVICE_TYPE=1 ALTENAR_SPORT_ID=0 # 可选 Overrides # ALTENAR_WIDGET_BASE_URL=https://sb2frontend-altenar2.biahosted.com/api/widget # ALTENAR_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 # ALTENAR_ACCEPT_LANGUAGE=es-ES,es;q=0.9,en;q=0.8 # Booky / Real Placement # ALTENAR_BOOKY_URL=https://www.casinoatlanticcity.com/apuestas-deportivas#/overview # ALTENAR_LOGIN_USERNAME=tu_usuario # ALTENAR_LOGIN_PASSWORD=tu_password # ALTENAR_BOOKY_AUTH_TOKEN=Bearer # BOOKY_REAL_PLACEMENT_ENABLED=false # BOOKY_KEEP_REAL_PLACEMENT_ON_TOKEN_REFRESH=false # BOOKY_AUTO_TOKEN_REFRESH_ENABLED=true # BOOKY_TOKEN_MIN_REMAINING_MINUTES=2 # BOOKY_MIN_EV_PERCENT=2 # BOOKY_MAX_ODD_DROP=0.20 # AUTO_SNIPE(受控推出) # AUTO_PLACEMENT_PROVIDER=booky # AUTO_SNIPE_ENABLED=false # AUTO_SNIPE_DRY_RUN=true # AUTO_SNIPE_MIN_EV_PERCENT=3 # AUTO_SNIPE_MIN_STAKE_SOL=2 # AUTO_SNIPE_MAX_BETS_PER_HOUR=4 # AUTO_SNIPE_COOLDOWN_PER_PICK_MS=120000 # AUTO_SNIPE_REQUIRE_REAL_PLACEMENT_ENABLED=true # AUTO_SNIPE_REENTRY_MIN_ODD_IMPROVEMENT_PCT=8 # AUTO_SNIPE_REENTRY_MIN_ODD_POINTS=0.30 # AUTO_SNIPE_MAX_ENTRIES_PER_PICK=2 # Matcher 诊断/调优 # MATCH_DIAGNOSTIC_LOG=1 # MATCH_FUZZY_THRESHOLD=0.77 # MATCH_MIN_ACCEPT_SCORE=0.60 # MATCH_TIME_TOLERANCE_MINUTES=5 # MATCH_TIME_EXTENDED_TOLERANCE_MINUTES=30 # booky 历史记录/账户清理(可选) # BOOKY_BALANCE_REFRESH_MS=45000 # BOOKY_HISTORY_REFRESH_MS=60000 # BOOKY_HISTORY_RETENTION_DAYS=30 # BOOKY_PROFILE_HISTORY_MAX_ITEMS=500 # prematch endpoint 性能(可选) # PREMATCH_CACHE_TTL_MS=20000 ``` #### 高负载模式 (Sabadazo) 要在比赛量激增时保持仪表板响应迅速: ``` DISABLE_BACKGROUND_WORKERS=false DISABLE_LIVE_SCANNER=false DISABLE_PREMATCH_SCHEDULER=true DISABLE_PINNACLE_INGEST_CRON=true DISABLE_MONITOR_DASHBOARD=true # 解锁 LIVE 的 profile(临时) LIVE_SNIPE_REQUIRE_PINNACLE_LIVE=false LIVE_VALUE_MIN_EV=0.01 LIVE_VALUE_REQUIRE_SCORE_SYNC=false LIVE_VALUE_SCORE_SYNC_MAX_GOAL_DIFF=1 LIVE_VALUE_STABILITY_MIN_HITS=1 LIVE_VALUE_STABILITY_MIN_AGE_MS=1500 LIVE_GLOBAL_STABILITY_MIN_HITS=1 ``` 然后,重启后端。在正常的日子,将两个标志都恢复为 `false`。 ### 自定义风险配置 编辑 `src/utils/mathUtils.js`: ``` const RISK_PROFILES = { 'PREMATCH_VALUE': 0.25, // Cambiar a 0.30 para ser más agresivo 'LIVE_VALUE': 0.125, 'LIVE_SNIPE': 0.10, // Cambiar a 0.05 para ser ultra-conservador }; ``` ### 调整过滤器 (扫描器) 编辑 `src/services/scannerService.js`: ``` // Línea ~135: Filtro de Stake Mínimo ops = ops.filter(op => op.kellyStake >= 1.00); // Cambiar a 0.50 para capturar más ops ``` ## 📋 脚本与命令指南 BetSniper 包含两种类型的脚本:**npm 命令** (在 `package.json` 中定义,使用 `npm run `) 和**直接脚本** (在 `scripts/` 中,使用 `node scripts/.js`)。本指南按功能对它们进行组织。 ### 🧩 npm 命令 (package.json) #### 主服务器 | 命令 | 描述 | |---|---| | `npm start` | 以生产模式启动服务器 (`node server.js`)。无热重载。 | | `npm run dev` | 使用 **nodemon** 以开发模式启动服务器 (保存文件时重新启动)。推荐用于开发。 | #### Booky 配置文件管理 | 命令 | 描述 | |---|---| | `npm run book:dorado` | 在 `.env` 中将活动配置文件更改为 **DoradoBet** (`BOOK_PROFILE`、`ALTENAR_INTEGRATION`、`ALTENAR_ORIGIN`、`ALTENAR_REFERER`)。无需重启服务器。 | | `npm run book:acity` | 在 `.env` 中将活动配置文件更改为 **ACity** (Casino Atlantic City)。无需重启服务器。 | #### JWT Token 提取 (Booky 认证) | 命令 | 模式 | 描述 | |---|---|---| | `npm run token:booky` | 有头模式 + 自动超时 | 打开带有可视化会话的 Chrome。在检测到登录后自动捕获 JWT。超时后自动关闭。 | | `npm run token:booky:wait-close` | 有头模式 + 手动等待 | 打开 Chrome,捕获 JWT 并**等待用户手动关闭窗口**。如果登录需要 2FA 或 captcha,则非常有用。 | | `npm run token:booky:dorado` | DoradoBet + 有头模式 | 与 `token:booky` 相同,但强制使用 DoradoBet 配置文件,即使 `.env` 另有指定。 | | `npm run token:booky:dorado:wait-close` | DoradoBet + 手动 | 组合:DoradoBet 配置文件 + 手动等待关闭。 | | `npm run token:booky:acity` | ACity + 有头模式 | 强制使用 ACity 配置文件。 | | `npm run token:booky:acity:wait-close` | ACity + 手动 | ACity + 手动等待。 | **它内部是如何工作的?** 1. 从 `.env` 中读取 `ALTENAR_BOOKY_URL`、`ALTENAR_LOGIN_USERNAME`、`ALTENAR_LOGIN_PASSWORD`。 2. 打开 Puppeteer,导航到 bookie,自动登录。 3. 拦截包含 JWT 的服务器响应。 4. 验证它是经过身份验证的用户 token (而非访客)。 5. 在您的 `.env` 中写入 `ALTENAR_BOOKY_AUTH_TOKEN=Bearer eyJ...`。 **预期输出:** ``` ✅ Login detectado. Capturando JWT... 🔑 JWT válido: usuario antho@ejemplo.com | Expira: 2026-03-03T14:22:00Z 💾 Token escrito en .env ``` #### 捕获 placeWidget Payload 为了理解当您下真实注时 bookie 发送了什么 (用于构建 `confirmRealPlacement` 的 payload) 所必需。 | 命令 | 模式 | 描述 | |---|---|---| | `npm run capture:booky` | 有头模式 + 当前配置文件 | 打开 Chrome,导航到 bookie,在点击投注时捕获 `placeWidget`/betslip payload。 | | `npm run capture:booky:headless` | 无头模式 | 相同但没有可见窗口。 | | `npm run capture:booky:dorado` | DoradoBet 有头模式 | 强制使用 DoradoBet 配置文件。 | | `npm run capture:booky:dorado:headless` | DoradoBet 无头模式 | 强制使用 DoradoBet 且无窗口。 | | `npm run capture:booky:acity` | ACity 有头模式 | 强制使用 ACity 配置文件。 | | `npm run capture:booky:acity:headless` | ACity 无头模式 | ACity 且无窗口。 | 捕获的 payload 保存在 `data/booky/capture-*.json` 中,并可通过 `GET /api/booky/capture/latest` 获取。 #### Pinnacle 投放置 Payload 捕获 (阶段 1) 在实现 `pinnacleSemiAutoService` 之前,发现 Pinnacle 的真实契约 (端点 + request body + 响应) 所必需。 | 命令 | 模式 | 描述 | |---|---|---| | `npm run capture:pinnacle:placement` | 有头模式 + 手动等待 | 使用专用配置文件打开 Pinnacle,捕获可能是 placement 的 `POST/PUT/PATCH` 请求,并等待手动关闭浏览器。 | | `npm run capture:pinnacle:placement:headless` | 无头模式 + 超时 180 秒 | 在时间窗口内执行自动捕获,无 UI。 | **捕获输出:** - `data/pinnacle/capture-placement-.json` - `data/pinnacle/capture-placement.latest.json` **推荐流程 (安全):** 1. 执行 `npm run capture:pinnacle:placement`。 2. 在 Pinnacle 窗口中,手动下注直到最后一次确认点击。 3. 关闭浏览器以完成并持久化捕获。 4. 检查 `capture-placement.latest.json` 并提取: - 确切的端点, - 必需的 headers, - payload schema, - 响应语义 (已确认/已拒绝/重新报价)。 提示:如果未出现任何候选,请使用以下命令重复: ``` node scripts/capture-pinnacle-placement.js --headed --wait-close --all-posts ``` #### 历史和配置文件侦察 | 命令 | 描述 | |---|---| | `npm run spy:altenar` | 通过拦截真实流量自动检测 bookie 的集成参数 (integration、countryCode、baseUrl)。如果 bookie 更改其配置,这很有用。保存在 `data/altenar-profile-*.json` 中。 | | `npm run spy:booky:history` | 打开 Chrome (有头模式),导航到 bookie 历史记录并捕获余额和历史记录端点的完整响应。保存在 `data/booky/spy-history-*.json` 中。 | | `npm run spy:booky:history:headless` | 与上一个相同,但为无头模式,超时为 120 秒。 | #### Booky 流程冒烟测试 | 命令 | 描述 | |---|---| | `npm run smoke:booky` | 以**安全**模式执行完整的 E2E 流程:`token-health` → `account snapshot` → `prepare ticket` → `confirm-fast`。**不发送任何真实投注**,即使 `BOOKY_REAL_PLACEMENT_ENABLED=true`。 | | `npm run smoke:booky:live` | 相同,但经过真实投放置路径 (需要 `BOOKY_REAL_PLACEMENT_ENABLED=true` 且 EV ≥ 0%)。仅用于在受控环境中验证完整流程。 | | `npm run health:latency` | 对关键端点 (`portfolio`、`live`、`prematch`、`booky/account`、`kelly-diagnostics`) 执行基于样本的延迟检查,以检测冻结/事件循环阻塞。 | ### 📥 手动摄入脚本 (`scripts/`) 服务器会自动执行这些摄入,但您可以手动强制执行: #### `node scripts/ingest-altenar.js` 更新 `db.json` 中 Altenar (DoradoBet) 的 prematch 事件缓存。 - **智能跳过:** 如果数据少于 100 分钟,则自动跳过摄入。 - **强制:** 通过将 `force=true` 更改为内部调用或删除 `db.json` 中的 `altenarLastUpdate` 来强制执行。 - **何时使用:** 在 prematch 交易会话之前,以确保数据新鲜。 #### `node scripts/ingest-pinnacle.js` 将 Pinnacle Arcadia (REST) prematch 事件下载并标准化到 `db.json` 中。 - 将美式赔率转换为小数。 - 计算公平概率 (无利润加成)。 - **何时使用:** 每天一次,或者每当您想刷新 Pinnacle prematch 缓存时。 推荐命令: ``` # 正常模式(带增量 flush) npm run ingest:pinnacle:force # OneDrive 安全模式(无增量 flush) npm run ingest:pinnacle:safe ``` ### 🔍 手动扫描器脚本 #### `node scripts/scan_live.js [--dry-run]` 以 60 秒循环的独立模式 (在服务器之外) 运行实时扫描器。 - **`--dry-run` / `-d`:** 观察者模式 — 检测机会但**不注册投注**。如果服务器已在运行,请务必使用。 - 无 `--dry-run`:在 `db.json` 中注册投注 (仅在服务器停止时使用)。 ``` # 观察者模式(在服务器运行时推荐) node scripts/scan_live.js --dry-run # 主动模式(仅在服务器停止时使用) node scripts/scan_live.js ``` #### `node scripts/run_linker.js` 以独立模式运行 prematch 扫描器。 - 读取 `db.json` (Pinnacle 和 Altenar 缓存)。 - 交叉比对事件并显示检测到的 prematch 机会。 - 不注册投注。仅用于诊断。 ``` node scripts/run_linker.js ``` ### 🦵 数据库诊断脚本 #### `node scripts/check_db.js` 显示 `db.json` 状态的快速摘要:每个集合中的记录数量 (pinnacle、matches、scanned_prematch 等)。 ``` node scripts/check_db.js # 输出:Keys: ['config','upcomingMatches','portfolio',...] # Pinnacle Count: 142 ``` #### `node scripts/find_match_in_db.js ` 在 `db.json` 和 `data/pinnacle_live.json` 中递归搜索球队或比赛。 ``` node scripts/find_match_in_db.js "Liverpool" node scripts/find_match_in_db.js "Tigres" ``` #### `node scripts/find_live_match.js` 在当前 Pinnacle 实时数据流 (`data/pinnacle_live.json`) 中搜索特定比赛。 #### `node scripts/check_linked_status.js` 检查 `db.json` 中特定记录的链接状态 (用于调试特定比赛未链接的原因)。 #### `node scripts/check_odds.js` 通过交叉比对 Pinnacle 和 Altenar 数据,显示特定比赛的存储赔率。 #### `node scripts/check_mapping.js` 显示 `db.json` 中 `mappedTeams` 字典的条目,以验证保存的别名。 #### `node scripts/generate_full_report.cjs` 生成完整的 CSV (`reporte_completo_partidos.csv`),包含所有 Pinnacle 和 Altenar 的比赛,显示它们是否已链接。可用于审计匹配器的质量。 ``` node scripts/generate_full_report.cjs # 创建:reporte_completo_partidos.csv ``` ### 🧹 投资组合维护脚本 #### `node scripts/reset_database.js` 将 `db.json` 恢复为默认值 (资金 100,历史为空)。 ``` node scripts/reset_database.js ``` #### `node scripts/force_settle_bets.js` 强制清算卡在 `PENDING` 状态的活跃投注。 - 查询 Altenar 的结果 API (`GetEventResults`) 以获取最终比分。 - 对每种类型的 pick (home、away、draw、over、under) 应用赢/输逻辑。 - 当僵尸协议 无法自动清算时很有用。 ``` node scripts/force_settle_bets.js ``` #### `node scripts/purge_invalid_bets.cjs` 从 `db.json` 中手动删除具有无效或损坏事件 ID 的投注。 - 要清除的 ID 列在脚本本身中 (`TARGET_IDS`)。 - 如果发现新的损坏投注,请编辑数组以添加 ID。 ``` node scripts/purge_invalid_bets.cjs ``` #### `node scripts/fix_under_2_bets.cjs` 修复行 为 `under_0` (行 解析错误) 的 Under 投注。从 `market` 字段中提取真实的行 并更正 `pick`。 ``` node scripts/fix_under_2_bets.cjs ``` #### `node scripts/migrate_bankroll.js` 将 `db.json` 中的资金池缩放至新值 (例如从 1,000 到 10,000),对余额和历史记录按比例应用相同的因子。 - 在执行前编辑脚本内的 `newCapital` 值。 ``` node scripts/migrate_bankroll.js ``` ### 🧪 测试和 Mock 脚本 #### `node scripts/mock_pinnacle.js` 生成一个包含虚构数据 (如 Man City vs Liverpool 等测试比赛) 的 `data/pinnacle_live.json` 文件。允许在没有真实 Pinnacle 连接的情况下开发和测试扫描器。 ``` node scripts/mock_pinnacle.js # 在 data/pinnacle_live.json 中创建测试数据 ``` #### `node scripts/tmp-run-booky-confirm.mjs` 直接执行 booky 票据确认,用于热测试。执行前需要在文件中编辑 `ticketId`。 ``` node scripts/tmp-run-booky-confirm.mjs ``` ### 🐞 调试脚本 (开发人员工具) 通用诊断脚本。它们不属于正常的操作流程,但对于调查实时问题很有用: | 脚本 | 何时使用? | |------| | `debug_live.js` | 查看 Altenar 实时数据流的原始结构 (`GetLivenow`) | | `debug_live_event.js` | 检查具有所有详细信息的特定实时事件 | | `debug_live_markets.js` | 查看实时事件中可用的市场 (开放/关闭) | | `debug_live_names.js` | 查看 Altenar 返回的原始球队名称 | | `debug_live_odds.js` | 比较实时事件中 Altenar 与 Pinnacle 的赔率 | | `debug_live_structure_v3.js` | 探索实时端点的完整 JSON 结构 (当前版本) | | `debug_matching.js` | 调试为什么特定的一对球队没有链接 | | `debug_matcher_specific.js` | 使用当前 Pinnacle 缓存 (`data/pinnacle_live.json`) 测试 `findMatch()` | | `debug_full_scan.js` | 以最大日志记录执行完整的机会扫描 | | `debug_monitor_link.js` | 诊断监视器为何不显示 Arcadia 赔率 (计算 `linked` 和 `pinnacleFound`) | | `debug_pinnacle_structure.js` | 查看 Pinnacle Arcadia 响应的原始结构 | | `debug_pinnacle_raw.js` | 查看 Pinnacle 未经转换的原始 HTTP 响应 | | `debug_pinnacle_endpoints.js` | 测试不同的 Pinnacle 端点 (matchups、odds 等) | | `debug_pinnacle_markets.cjs` | 检查 Pinnacle 事件中可用的市场 | | `debug_pinnacle_match_info.cjs` | 查看 Pinnacle 比赛的完整信息 (球队、赔率、状态) | | `debug_altenar_markets.js` | 检查 Altenar 事件的市场 (1X2、Totals、BTTS) | | `debug_totals_structure.js` | 查看 Over/Under 市场结构以验证标准化 | | `debug_scanner_v2.js` | 逐步分析扫描器的输出 (当前版本) | | `audit_date.js` | **投资组合历史审计:** 查询 `GetEventResults`,将真实最终比分与 `db.json` 中记录的进行比较,纠正错误的 WON/LOST 状态并调整余额。接受日期作为参数。 | ``` # Matching 诊断: node scripts/debug_matching.js node scripts/debug_matcher_specific.js # Monitor/Linking 诊断: node scripts/debug_monitor_link.js node scripts/debug_full_scan.js # 投资组合历史审计(修正 score/状态): node scripts/audit_date.js 2026-03-01 ``` ### 📊 快速摘要:每种情况下该执行什么? | 情况 | 命令 | |---|---| | **每日正常启动** | 终端 1:`npm run dev` \| 终端 2:`node services/pinnacleLight.js` \| 终端 3:`cd client && npm run dev` | | **更改 bookie** | `npm run book:acity` 或 `npm run book:dorado` | | **更新 JWT token** | `npm run book:dorado` → `npm run token:booky:wait-close` | | **验证一切正常** | `npm run smoke:booky` | | **在无活动服务器的情况下查看机会** | `node scripts/scan_live.js --dry-run` | | **强制更新 prematch 数据** | `node scripts/ingest-altenar.js` + `node scripts/ingest-pinnacle.js` | | **投注卡在 PENDING** | `node scripts/force_settle_bets.js` | | **匹配器未链接球队** | `node scripts/debug_matching.js` 或 `node scripts/debug_matcher_specific.js` → 在 `dynamicAliases.json` 中添加别名 | | **投注的比分/结果不正确** | `node scripts/audit_date.js YYYY-MM-DD` (更正 `db.json` 中的状态) | | **审计匹配器质量** | `node scripts/generate_full_report.cjs` | | **重置数据库** | `node scripts/reset_database.js` | | **在没有真实 Pinnacle 的情况下进行测试** | `node scripts/mock_pinnacle.js` → `npm run dev` | ## 🚨 故障排除 ### 问题:"Chromium 未关闭" **症状:** Chrome 窗口无限期保持打开。 **原因:** Pinnacle token 未能正确捕获。 **解决方案:** 1. 手动关闭 Chrome 窗口。 2. 删除文件:`rm data/pinnacle_token.json` 3. 重启:`node services/pinnacleLight.js` 4. 当 Chrome 打开时再次登录 Pinnacle。 ### 问题:"前端未出现机会" **症状:** "赛前" 和 "实时" 选项卡为空。 **诊断:** 1. 验证 3 个进程是否都在运行 (终端 1, 2, 3)。 2. 检查终端 1 (服务器) 的日志以查找错误。 3. 直接在浏览器中打开 `http://localhost:3000/api/opportunities/live`。 **解决方案:** - **如果 API 返回 `[]`:** 匹配器未链接事件。使用 "匹配器" 选项卡强制链接。 - **如果出现 500 错误:** 检查 `data/pinnacle_live.json` 是否存在并包含数据。 - **如果 `pinnacle_live.json` 为空:** 终端 2 进程失败。重启。 ### 问题:"间歇性延迟 / 加载时屏幕闪烁" **症状:** 有时加载快,有时全部超时 (资金、机会、kelly card)。 **快速诊断:** ``` npm run health:latency ``` **如果出现间歇性超时:** 1. 激活高负载模式 (`DISABLE_PREMATCH_SCHEDULER=true`,`DISABLE_PINNACLE_INGEST_CRON=true`;如果监视器已打开,可选 `DISABLE_MONITOR_DASHBOARD=true`)。 2. 重启后端。 3. 重复 `npm run health:latency` 并确认 `portfolio/live` 是否稳定。 ### 问题:"数据冻结 (陈旧数据)" **症状:** 监视器显示过时的时间 (例如:Altenar 在第 75 分钟,Pinnacle 在第 70 分钟)。 **原因:** Pinnacle WebSocket 停止接收帧。 **自动解决方案:** 系统检测到这一点并创建 `data/pinnacle_stale.trigger`,触发 socket 的自动重启。 **手动解决方案:** 1. 停止终端 2:`Ctrl+C` 2. 重启:`node services/pinnacleLight.js` ### 问题:"重复投注" **症状:** 同一事件在 "活跃" 中出现两次。 **原因:** 您在服务器运行时在没有 `--dry-run` 标志的情况下执行了 `scan_live.js`。 **预防:** 如果服务器处于活动状态,**务必**使用 `--dry-run`。 **清理:** ``` // Abrir db.json y eliminar manualmente la entrada duplicada en activeBets[] ``` ### 问题:"Booky token 无效或过期" **症状:** 端点 `/api/booky/real/*` **用 ❤️ 为算法交易员构建** ⭐ 如果这个项目对你有帮助,请考虑在 GitHub 上给它点个星
标签:API逆向, GNU通用公共许可证, MITM代理, Node.js, React, Syscalls, WebSocket实时分析, 事件驱动架构, 云资产清单, 体育套利, 套利引擎, 算法交易, 系统行为监控, 网络安全, 自定义脚本, 逆向工程, 量化交易, 隐私保护, 风险控制, 高频交易