From 7eb310b35e954bc097179523771e92c22fbb0d6e Mon Sep 17 00:00:00 2001 From: WrBug Date: Wed, 3 Dec 2025 02:27:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=80=E6=BA=90=E5=87=86=E5=A4=87?= =?UTF-8?q?=E5=92=8C=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 MIT 许可证 - 创建完整的项目 README.md - 前端添加 GitHub 和 Twitter 链接 - 重构表名:copy_trading_accounts -> wallet_accounts - 更新 Account 实体类 - 添加数据库迁移脚本 V3 - 更新初始化脚本和文档 - 优化跟单订单类型:GTC -> FAK - 买入和卖出订单均使用 FAK (Fill-And-Kill) - 允许部分成交,未成交部分立即取消 - 提高跟单响应速度和价格匹配准确性 --- LICENSE | 22 ++ README.md | 231 ++++++++++++++++++ .../com/wrbug/polymarketbot/entity/Account.kt | 4 +- .../service/CopyOrderTrackingService.kt | 8 +- .../db/migration/V1__init_database.sql | 6 +- ...py_trading_accounts_to_wallet_accounts.sql | 36 +++ docs/copy-trading-requirements.md | 6 +- frontend/src/components/Layout.tsx | 59 ++++- 8 files changed, 353 insertions(+), 19 deletions(-) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 backend/src/main/resources/db/migration/V3__rename_copy_trading_accounts_to_wallet_accounts.sql diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..02402b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2024 WrBug + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..c6d0b59 --- /dev/null +++ b/README.md @@ -0,0 +1,231 @@ +# PolyHermes + +[![GitHub](https://img.shields.io/badge/GitHub-WrBug%2FPolyHermes-blue?logo=github)](https://github.com/WrBug/PolyHermes) +[![Twitter](https://img.shields.io/badge/Twitter-@quant__tr-blue?logo=twitter)](https://x.com/quant_tr) + +一个功能强大的 Polymarket 预测市场跟单交易系统,支持自动化跟单、多账户管理、实时订单推送和统计分析。 + +## ✨ 功能特性 + +### 核心功能 +- 🔐 **多账户管理**:支持通过私钥导入多个钱包账户,统一管理 +- 👥 **Leader 管理**:添加和管理被跟单者(Leader),支持分类筛选(sports/crypto) +- 📊 **跟单配置**:灵活的跟单模板配置,支持比例跟单和固定金额跟单 +- 🔄 **自动跟单**:实时监控 Leader 交易,自动复制订单(支持买入和卖出) +- 📈 **订单跟踪**:完整的订单生命周期跟踪,包括买入、卖出和匹配记录 +- 📊 **统计分析**:全局统计、Leader 统计、分类统计,支持时间范围筛选 +- 💼 **仓位管理**:实时查看和管理持仓,支持仓位推送 +- ⚙️ **系统管理**:代理配置、API 健康检查、实时状态监控 + +### 技术特性 +- 🌐 **WebSocket 实时推送**:订单和仓位数据实时推送 +- 🔒 **安全存储**:私钥和 API 凭证加密存储 +- 📱 **响应式设计**:完美支持移动端和桌面端 +- 🚀 **高性能**:异步处理、并发优化 +- 🛡️ **风险控制**:每日亏损限制、订单数限制、价格容忍度等 + +## 🏗️ 技术栈 + +### 后端 +- **框架**: Spring Boot 3.2.0 +- **语言**: Kotlin 1.9.20 +- **数据库**: MySQL 8.2.0 +- **ORM**: Spring Data JPA +- **数据库迁移**: Flyway +- **HTTP 客户端**: Retrofit 2.9.0 + OkHttp 4.12.0 +- **WebSocket**: Spring WebSocket + +### 前端 +- **框架**: React 18 + TypeScript +- **构建工具**: Vite +- **UI 库**: Ant Design 5.12.0 +- **HTTP 客户端**: axios +- **状态管理**: Zustand +- **路由**: React Router 6 +- **以太坊库**: ethers.js 6.9.0 + +## 📦 项目结构 + +``` +polymarket-bot/ +├── backend/ # 后端服务 +│ ├── src/main/kotlin/ # Kotlin 源代码 +│ │ ├── api/ # Polymarket API 接口定义 +│ │ ├── controller/ # REST 控制器 +│ │ ├── service/ # 业务逻辑服务 +│ │ ├── entity/ # 数据库实体 +│ │ ├── repository/ # 数据访问层 +│ │ ├── dto/ # 数据传输对象 +│ │ ├── websocket/ # WebSocket 处理 +│ │ └── util/ # 工具类 +│ └── src/main/resources/ +│ ├── application.properties +│ └── db/migration/ # 数据库迁移脚本 +├── frontend/ # 前端应用 +│ ├── src/ +│ │ ├── components/ # 公共组件 +│ │ ├── pages/ # 页面组件 +│ │ ├── services/ # API 服务 +│ │ ├── types/ # TypeScript 类型 +│ │ └── utils/ # 工具函数 +│ └── package.json +├── docs/ # 文档 +└── README.md +``` + +## 🚀 快速开始 + +### 前置要求 + +- JDK 17+ +- Node.js 18+ +- MySQL 8.0+ +- Gradle 7.5+ + +### 安装步骤 + +1. **克隆仓库** + +```bash +git clone https://github.com/WrBug/PolyHermes.git +cd PolyHermes +``` + +2. **配置数据库** + +创建 MySQL 数据库: + +```sql +CREATE DATABASE polymarket_bot CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +``` + +3. **配置后端** + +编辑 `backend/src/main/resources/application.properties`: + +```properties +# 数据库配置 +spring.datasource.url=jdbc:mysql://localhost:3306/polymarket_bot?useSSL=false&serverTimezone=UTC&characterEncoding=utf8mb4 +spring.datasource.username=${DB_USERNAME:root} +spring.datasource.password=${DB_PASSWORD:your_password} + +# 服务器端口 +server.port=${SERVER_PORT:8000} + +# Polygon RPC(用于查询链上余额) +polygon.rpc.url=${POLYGON_RPC_URL:https://polygon-rpc.com} +``` + +4. **启动后端** + +```bash +cd backend +./gradlew bootRun +``` + +后端服务将在 `http://localhost:8000` 启动。 + +5. **启动前端** + +```bash +cd frontend +npm install +npm run dev +``` + +前端应用将在 `http://localhost:3000` 启动。 + +## 📖 使用指南 + +### 账户管理 + +1. 进入"账户管理"页面 +2. 点击"导入账户" +3. 输入私钥(支持私钥字符串、助记词或 Keystore 文件) +4. 系统自动推导钱包地址并验证 +5. 配置账户名称和是否默认账户 + +### 跟单配置 + +1. 进入"Leader 管理",添加被跟单者(Leader)地址 +2. 进入"跟单模板",创建跟单模板(配置跟单比例、风险控制等) +3. 进入"跟单配置",将账户、模板和 Leader 关联 +4. 启用跟单关系,系统将自动开始跟单 + +### 查看统计 + +- **全局统计**:查看所有跟单关系的汇总统计 +- **Leader 统计**:查看特定 Leader 的统计信息 +- **分类统计**:按分类(sports/crypto)查看统计 +- **跟单关系统计**:查看单个跟单关系的详细统计 + +## 🔧 配置说明 + +### 环境变量 + +| 变量名 | 说明 | 默认值 | +|--------|------|--------| +| `DB_USERNAME` | 数据库用户名 | `root` | +| `DB_PASSWORD` | 数据库密码 | - | +| `SERVER_PORT` | 后端服务端口 | `8000` | +| `POLYGON_RPC_URL` | Polygon RPC 地址 | `https://polygon-rpc.com` | +| `JWT_SECRET` | JWT 密钥 | - | + +### 代理配置 + +系统支持通过 Web UI 配置 HTTP 代理,无需修改环境变量: + +1. 进入"系统管理"页面 +2. 配置代理主机、端口、用户名和密码 +3. 启用代理并测试连接 +4. 配置实时生效,无需重启服务 + +## 📚 API 文档 + +详细的 API 文档请参考: +- [跟单系统需求文档](docs/copy-trading-requirements.md) +- [前端需求文档](docs/copy-trading-frontend-requirements.md) + +## 🤝 贡献 + +欢迎贡献代码!请遵循以下步骤: + +1. Fork 本仓库 +2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) +3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 开启 Pull Request + +## 📝 开发规范 + +- **后端**: 遵循 Kotlin 编码规范,使用 Spring Boot 最佳实践 +- **前端**: 遵循 TypeScript 和 React 最佳实践 +- **提交信息**: 使用清晰的提交信息,遵循 [Conventional Commits](https://www.conventionalcommits.org/) + +详细开发规范请参考: +- [后端开发规范](.cursor/rules/backend.mdc) +- [前端开发规范](.cursor/rules/frontend.mdc) + +## ⚠️ 免责声明 + +本软件仅供学习和研究使用。使用本软件进行交易的风险由用户自行承担。作者不对任何交易损失负责。 + +## 📄 许可证 + +本项目采用 MIT 许可证。详情请参阅 [LICENSE](LICENSE) 文件。 + +## 🔗 相关链接 + +- [GitHub 仓库](https://github.com/WrBug/PolyHermes) +- [Twitter](https://x.com/quant_tr) +- [Polymarket 官网](https://polymarket.com) +- [Polymarket API 文档](https://docs.polymarket.com) + +## 🙏 致谢 + +感谢所有为本项目做出贡献的开发者和用户! + +--- + +**⭐ 如果这个项目对你有帮助,请给个 Star!** + diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/entity/Account.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/entity/Account.kt index 7205d33..003f278 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/entity/Account.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/entity/Account.kt @@ -4,10 +4,10 @@ import jakarta.persistence.* /** * 账户信息实体 - * 用于存储跟单者的账户信息(支持多账户) + * 用于存储钱包账户信息(支持多账户) */ @Entity -@Table(name = "copy_trading_accounts") +@Table(name = "wallet_accounts") data class Account( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/CopyOrderTrackingService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/CopyOrderTrackingService.kt index b632e12..1125624 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/CopyOrderTrackingService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/CopyOrderTrackingService.kt @@ -461,10 +461,12 @@ class CopyOrderTrackingService( } // 8. 构建订单请求 + // 跟单订单使用 FAK (Fill-And-Kill),允许部分成交,未成交部分立即取消 + // 这样可以快速响应 Leader 的交易,避免订单长期挂单导致价格不匹配 val orderRequest = NewOrderRequest( order = signedOrder, owner = account.apiKey!!, - orderType = "GTC", // Good-Til-Cancelled + orderType = "FAK", // Fill-And-Kill deferExec = false ) @@ -584,10 +586,12 @@ class CopyOrderTrackingService( ) // 构建订单请求(每次重试都使用新签名的订单) + // 跟单订单使用 FAK (Fill-And-Kill),允许部分成交,未成交部分立即取消 + // 这样可以快速响应 Leader 的交易,避免订单长期挂单导致价格不匹配 val orderRequest = NewOrderRequest( order = signedOrder, owner = owner, // API Key - orderType = "GTC", // Good-Til-Cancelled + orderType = "FAK", // Fill-And-Kill deferExec = false ) diff --git a/backend/src/main/resources/db/migration/V1__init_database.sql b/backend/src/main/resources/db/migration/V1__init_database.sql index 85328ef..cf830c3 100644 --- a/backend/src/main/resources/db/migration/V1__init_database.sql +++ b/backend/src/main/resources/db/migration/V1__init_database.sql @@ -5,7 +5,7 @@ -- ============================================ -- 1. 创建账户表 -- ============================================ -CREATE TABLE IF NOT EXISTS copy_trading_accounts ( +CREATE TABLE IF NOT EXISTS wallet_accounts ( id BIGINT AUTO_INCREMENT PRIMARY KEY, private_key VARCHAR(500) NOT NULL COMMENT '私钥(加密存储)', wallet_address VARCHAR(42) NOT NULL UNIQUE COMMENT '钱包地址(从私钥推导)', @@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS copy_trading_accounts ( updated_at BIGINT NOT NULL COMMENT '更新时间(毫秒时间戳)', INDEX idx_wallet_address (wallet_address), INDEX idx_is_default (is_default) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='跟单系统账户表'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='钱包账户表'; -- ============================================ -- 2. 创建被跟单者(Leader)表 @@ -77,7 +77,7 @@ CREATE TABLE IF NOT EXISTS copy_trading ( INDEX idx_template_id (template_id), INDEX idx_leader_id (leader_id), INDEX idx_enabled (enabled), - FOREIGN KEY (account_id) REFERENCES copy_trading_accounts(id) ON DELETE CASCADE, + FOREIGN KEY (account_id) REFERENCES wallet_accounts(id) ON DELETE CASCADE, FOREIGN KEY (template_id) REFERENCES copy_trading_templates(id) ON DELETE RESTRICT, FOREIGN KEY (leader_id) REFERENCES copy_trading_leaders(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='跟单关系表(钱包-模板关联)'; diff --git a/backend/src/main/resources/db/migration/V3__rename_copy_trading_accounts_to_wallet_accounts.sql b/backend/src/main/resources/db/migration/V3__rename_copy_trading_accounts_to_wallet_accounts.sql new file mode 100644 index 0000000..6a4a051 --- /dev/null +++ b/backend/src/main/resources/db/migration/V3__rename_copy_trading_accounts_to_wallet_accounts.sql @@ -0,0 +1,36 @@ +-- ============================================ +-- 重命名账户表:copy_trading_accounts -> wallet_accounts +-- ============================================ + +-- 检查表是否存在,如果存在则重命名 +-- 注意:此迁移脚本假设表已经存在(从 V1 迁移创建) + +-- 1. 查找外键约束名称并删除 +SET @fk_name = NULL; +SELECT CONSTRAINT_NAME INTO @fk_name +FROM information_schema.KEY_COLUMN_USAGE +WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'copy_trading' + AND COLUMN_NAME = 'account_id' + AND REFERENCED_TABLE_NAME = 'copy_trading_accounts' +LIMIT 1; + +-- 2. 如果找到外键,删除它 +SET @drop_fk_sql = IF(@fk_name IS NOT NULL, + CONCAT('ALTER TABLE copy_trading DROP FOREIGN KEY `', @fk_name, '`'), + 'SELECT 1'); +PREPARE stmt FROM @drop_fk_sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- 3. 重命名表 +RENAME TABLE copy_trading_accounts TO wallet_accounts; + +-- 4. 重新添加外键约束 +ALTER TABLE copy_trading +ADD CONSTRAINT fk_copy_trading_account_id +FOREIGN KEY (account_id) REFERENCES wallet_accounts(id) ON DELETE CASCADE; + +-- 5. 更新表注释 +ALTER TABLE wallet_accounts COMMENT = '钱包账户表'; + diff --git a/docs/copy-trading-requirements.md b/docs/copy-trading-requirements.md index a4f3d29..33bac51 100644 --- a/docs/copy-trading-requirements.md +++ b/docs/copy-trading-requirements.md @@ -580,7 +580,7 @@ ### 3.1 Account(账户信息) ```kotlin @Entity -@Table(name = "copy_trading_accounts") +@Table(name = "wallet_accounts") data class Account( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -1623,7 +1623,7 @@ const address = account.address; ## 7. 数据库设计 ### 7.1 表结构 -- `copy_trading_accounts`: 账户信息表 +- `wallet_accounts`: 钱包账户表 - `copy_trading_leaders`: 被跟单者表 - `copy_trading_templates`: 跟单模板表 - `copy_trading`: 跟单关系表(钱包-模板关联,多对多) @@ -1632,7 +1632,7 @@ const address = account.address; - `copy_trading_processed_trades`: 已处理交易表(用于去重) ### 7.2 索引设计 -- `copy_trading_accounts.wallet_address`: UNIQUE 索引 +- `wallet_accounts.wallet_address`: UNIQUE 索引 - `copy_trading_leaders.leader_address`: UNIQUE 索引 - `copy_trading_templates.template_name`: UNIQUE 索引 - `copy_trading.account_id + template_id + leader_id`: 联合唯一索引 diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 007fe3b..6270b70 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -13,7 +13,9 @@ import { AppstoreOutlined, TeamOutlined, LogoutOutlined, - SettingOutlined + SettingOutlined, + GithubOutlined, + TwitterOutlined } from '@ant-design/icons' import type { MenuProps } from 'antd' import type { ReactNode } from 'react' @@ -172,12 +174,30 @@ const Layout: React.FC = ({ children }) => {
PolyHermes
-