├── .gitignore ├── LICENSE ├── README.md ├── README_CN.md ├── assets └── logo.svg ├── contracts ├── FollowTrade.sol ├── MemeInteraction.sol ├── SocialInteraction.sol └── TokenGovernance.sol ├── docs ├── API.md └── DEVELOPER.md ├── package-lock.json ├── package.json ├── program └── src │ ├── follow_trade.rs │ └── lib.rs └── src ├── ai_engine ├── market_data.py ├── meme_generator.py ├── ml_models.py ├── risk_manager.py ├── signal_generator.py ├── trading_engine.py └── voice_generator.py ├── config └── ai_social_config.js ├── contracts └── abi.js ├── index.js └── services ├── follow_trade_service.js ├── real_time_processor.js ├── real_time_service.js ├── social_media_service.js └── trading_service.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | .env 4 | 5 | # Build outputs 6 | dist/ 7 | build/ 8 | 9 | # IDE and editor files 10 | .idea/ 11 | .vscode/ 12 | *.swp 13 | *.swo 14 | 15 | # Logs 16 | logs/ 17 | *.log 18 | npm-debug.log* 19 | 20 | # Testing 21 | coverage/ 22 | 23 | # Python 24 | __pycache__/ 25 | *.py[cod] 26 | *.so 27 | 28 | # Solidity 29 | artifacts/ 30 | cache/ 31 | 32 | # Misc 33 | .DS_Store 34 | Thumbs.db -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 DeepRug 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | DeepRug Logo 3 |

4 | 5 | # DeepRug (RUG) Project 6 | 7 | [中文文档](README_CN.md) | [License](LICENSE) 8 | 9 | > Let AI tear open the quantitative black box - either get rich or Rug Pull yourself! 10 | 11 | ## 🚀 Project Overview 12 | 13 | DeepRug is a revolutionary AI quantitative trading platform that perfectly combines AI trading strategies with social entertainment. Through 100% on-chain live trading operations, it provides users with a transparent and highly entertaining trading experience. 14 | 15 | ## 🌟 Core Features 16 | 17 | ### 1. Transparent Quantitative Casino 18 | - Real-time ETH/BTC trading based on DeepSeek engine 19 | - Real-time trading signals published on-chain 20 | - Profit/loss live streaming 21 | - User 1-second delay copy trading system 22 | 23 | ### 2. AI Strategy Open Source Challenge 24 | - Weekly release of simplified strategy code 25 | - Community strategy optimization reward mechanism 26 | - Fun code comment culture 27 | 28 | ### 3. AI vs Human Trading Competition 29 | - Monthly "Retail vs AI" competition 30 | - AI real-time commentary system 31 | - Live interactive experience 32 | 33 | ### 4. RUG Token Economics 34 | - Copy trading fee token discount 35 | - Governance voting rights 36 | - Strategy data access rights 37 | - Deflationary burn mechanism (0-50% burn rate) 38 | 39 | ## 🔥 Community Features 40 | - AI Trading Live Stream 41 | - Rug Pull Badge System 42 | - AI Confession Simulator 43 | - Comparative Analysis Weekly Report 44 | 45 | ## 📚 Technical Architecture 46 | 47 | ### Smart Contract System 48 | - FollowTrade Contract: Manages copy trading and profit distribution 49 | - Follow trade management with fee system 50 | - Profit distribution (70% trader / 30% follower) 51 | - Token burn mechanism (0-50% rate) 52 | - Reward withdrawal system 53 | - MemeInteraction Contract: Handles social engagement 54 | - TokenGovernance Contract: Manages platform governance 55 | - SocialInteraction Contract: Manages community features 56 | 57 | ### AI Engine (Python) 58 | - Market data analysis (market_data.py) 59 | - Trading signal generation (signal_generator.py) 60 | - Risk management system (risk_manager.py) 61 | - ML model implementation (ml_models.py) 62 | - Trading execution engine (trading_engine.py) 63 | - Meme and voice content generation 64 | 65 | ### Backend Services (Node.js) 66 | - Real-time data processing service 67 | - WebSocket server (ws://localhost:8081) 68 | - Trading service integration 69 | - Social media integration 70 | - Follow trade service 71 | 72 | ### Frontend Application 73 | - Web Interface (React) 74 | - Real-time Data Visualization 75 | - Social Interaction Features 76 | 77 | ### Blockchain Integration 78 | - On-chain Data Storage 79 | - Smart Contract Interaction 80 | - Token Economic System 81 | 82 | ### Data System 83 | - Market Data Collection 84 | - Trading Signal Analysis 85 | - User Behavior Analysis 86 | 87 | ## 🚀 Development Roadmap 88 | 89 | ### Phase One: Infrastructure (In Progress) 90 | - [ ] Build AI Trading Engine 91 | - [x] Develop Smart Contracts 92 | - [ ] Build Data Processing System 93 | 94 | ### Phase Two: Core Features 95 | - [ ] Implement Live Trading Stream 96 | - [ ] Develop Copy Trading System 97 | - [ ] Deploy Token Contract 98 | 99 | ### Phase Three: Community Features 100 | - [ ] Implement Social Interaction Features 101 | - [ ] Develop NFT Badge System 102 | - [ ] Build Data Analysis Platform 103 | 104 | ## ⚠️ Project Status 105 | 106 | This project is currently under active development. The core smart contracts and basic infrastructure are implemented, but many features are still being developed and refined. We welcome community contributions to help accelerate development. 107 | 108 | ## 📝 Contribution Guidelines 109 | 110 | Welcome to join DeepRug development! Please check our contribution guidelines to learn how to participate in project development. 111 | 112 | ## 📄 License 113 | 114 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # DeepRug (RUG) 项目 2 | 3 | > 让 AI 撕开量化交易的黑盒 - 要么暴富,要么被 Rug Pull! 4 | 5 | ## 🚀 项目概述 6 | 7 | DeepRug 是一个革命性的 AI 量化交易平台,完美地将 AI 交易策略与社交娱乐相结合。通过100%链上实时交易操作,为用户提供透明且高度娱乐性的交易体验。 8 | 9 | ## 🌟 核心功能 10 | 11 | ### 1. 透明量化赌场 12 | - 基于 DeepSeek 引擎的实时 ETH/BTC 交易 13 | - 链上实时发布交易信号 14 | - 实时盈亏直播 15 | - 用户1秒延迟跟单系统 16 | 17 | ### 2. AI 策略开源挑战 18 | - 每周发布简化策略代码 19 | - 社区策略优化奖励机制 20 | - 趣味代码注释文化 21 | 22 | ### 3. AI vs 人类交易大赛 23 | - 每月"散户大战 AI"比赛 24 | - AI 实时解说系统 25 | - 现场互动体验 26 | 27 | ### 4. RUG 代币经济 28 | - 跟单费用代币折扣 29 | - 治理投票权 30 | - 策略数据访问权 31 | - 通缩销毁机制(0-50%销毁率) 32 | 33 | ## 🔥 社区特色 34 | - AI 交易直播 35 | - Rug Pull 徽章系统 36 | - AI 忏悔模拟器 37 | - 每周对比分析报告 38 | 39 | ## 📚 技术架构 40 | 41 | ### 智能合约系统 42 | - 跟单交易合约:管理跟单交易和利润分配 43 | - 跟单管理及费用系统 44 | - 利润分配(交易者70% / 跟单者30%) 45 | - 代币销毁机制(0-50%销毁率) 46 | - 奖励提取系统 47 | - 表情包互动合约:处理社交互动 48 | - 代币治理合约:管理平台治理 49 | - 社交互动合约:管理社区功能 50 | 51 | ### AI 引擎(Python) 52 | - 市场数据分析(market_data.py) 53 | - 交易信号生成(signal_generator.py) 54 | - 风险管理系统(risk_manager.py) 55 | - 机器学习模型实现(ml_models.py) 56 | - 交易执行引擎(trading_engine.py) 57 | - 表情包和语音内容生成 58 | 59 | ### 后端服务(Node.js) 60 | - 实时数据处理服务 61 | - WebSocket 服务器(ws://localhost:8081) 62 | - 交易服务集成 63 | - 社交媒体集成 64 | - 跟单交易服务 65 | 66 | ### 前端应用 67 | - Web 界面(React) 68 | - 实时数据可视化 69 | - 社交互动功能 70 | 71 | ### 区块链集成 72 | - 链上数据存储 73 | - 智能合约交互 74 | - 代币经济系统 75 | 76 | ### 数据系统 77 | - 市场数据采集 78 | - 交易信号分析 79 | - 用户行为分析 80 | 81 | ## 🚀 开发路线图 82 | 83 | ### 第一阶段:基础设施(进行中) 84 | - [ ] 构建 AI 交易引擎 85 | - [x] 开发智能合约 86 | - [ ] 构建数据处理系统 87 | 88 | ### 第二阶段:核心功能 89 | - [ ] 实现实时交易直播 90 | - [ ] 开发跟单系统 91 | - [ ] 部署代币合约 92 | 93 | ### 第三阶段:社区功能 94 | - [ ] 实现社交互动功能 95 | - [ ] 开发 NFT 徽章系统 96 | - [ ] 构建数据分析平台 97 | 98 | ## ⚠️ 项目状态 99 | 100 | 本项目目前正在积极开发中。核心智能合约和基础设施已经实现,但许多功能仍在开发和完善中。我们欢迎社区贡献,帮助加速开发进程。 101 | 102 | ## 📝 贡献指南 103 | 104 | 欢迎加入 DeepRug 开发!请查看我们的贡献指南,了解如何参与项目开发。 105 | 106 | ## 📄 许可证 107 | 108 | 本项目采用 MIT 许可证。详情请参阅 [LICENSE](LICENSE) 文件。 -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 37 | -------------------------------------------------------------------------------- /contracts/FollowTrade.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract FollowTrade { 5 | // State variables 6 | address public owner; 7 | uint256 public followFee; 8 | uint256 public burnRate; 9 | uint256 public totalBurned; 10 | mapping(address => uint256) public balances; 11 | mapping(address => mapping(string => bool)) public activeFollows; 12 | mapping(address => uint256) public traderRewards; 13 | 14 | // Events 15 | event FollowTradeStarted(address follower, string symbol, uint256 fee); 16 | event ProfitDistributed(address trader, address follower, uint256 amount); 17 | event TokensBurned(uint256 amount); 18 | event RewardsWithdrawn(address user, uint256 amount); 19 | 20 | constructor(uint256 _followFee, uint256 _burnRate) { 21 | require(_burnRate <= 50, "Burn rate cannot exceed 50%"); 22 | owner = msg.sender; 23 | followFee = _followFee; 24 | burnRate = _burnRate; 25 | } 26 | 27 | // Modifiers 28 | modifier onlyOwner() { 29 | require(msg.sender == owner, "Only owner can call this function"); 30 | _; 31 | } 32 | 33 | modifier onlyActiveFollower(string memory symbol) { 34 | require(activeFollows[msg.sender][symbol], "Not an active follower"); 35 | _; 36 | } 37 | 38 | // Follow trade function 39 | function startFollow(string memory symbol) external payable { 40 | require(msg.value >= followFee, "Insufficient follow fee"); 41 | require(!activeFollows[msg.sender][symbol], "Already following this symbol"); 42 | 43 | // Calculate burn amount 44 | uint256 burnAmount = (followFee * burnRate) / 100; 45 | uint256 systemAmount = followFee - burnAmount; 46 | 47 | // Update state 48 | activeFollows[msg.sender][symbol] = true; 49 | balances[owner] += systemAmount; 50 | totalBurned += burnAmount; 51 | 52 | // Burn tokens 53 | address deadAddress = address(0); 54 | payable(deadAddress).transfer(burnAmount); 55 | 56 | // Refund excess payment 57 | if (msg.value > followFee) { 58 | payable(msg.sender).transfer(msg.value - followFee); 59 | } 60 | 61 | emit FollowTradeStarted(msg.sender, symbol, followFee); 62 | emit TokensBurned(burnAmount); 63 | } 64 | 65 | // Distribute profits 66 | function distributeProfits(address[] calldata followers, uint256[] calldata amounts) external onlyOwner { 67 | require(followers.length == amounts.length, "Arrays length mismatch"); 68 | 69 | for (uint256 i = 0; i < followers.length; i++) { 70 | address follower = followers[i]; 71 | uint256 amount = amounts[i]; 72 | 73 | require(balances[owner] >= amount, "Insufficient balance"); 74 | 75 | // Calculate profit shares 76 | uint256 traderShare = (amount * 70) / 100; // 70% to trader 77 | uint256 followerShare = amount - traderShare; // 30% to follower 78 | 79 | // Update balances 80 | balances[owner] -= amount; 81 | balances[follower] += followerShare; 82 | traderRewards[msg.sender] += traderShare; 83 | 84 | emit ProfitDistributed(msg.sender, follower, amount); 85 | } 86 | } 87 | 88 | // Withdraw rewards 89 | function withdrawRewards() external { 90 | uint256 amount = traderRewards[msg.sender]; 91 | require(amount > 0, "No rewards to withdraw"); 92 | 93 | traderRewards[msg.sender] = 0; 94 | payable(msg.sender).transfer(amount); 95 | 96 | emit RewardsWithdrawn(msg.sender, amount); 97 | } 98 | 99 | // Withdraw balance 100 | function withdraw() external { 101 | uint256 amount = balances[msg.sender]; 102 | require(amount > 0, "No balance to withdraw"); 103 | 104 | balances[msg.sender] = 0; 105 | payable(msg.sender).transfer(amount); 106 | } 107 | 108 | // Update parameters 109 | function updateFollowFee(uint256 _newFee) external onlyOwner { 110 | followFee = _newFee; 111 | } 112 | 113 | function updateBurnRate(uint256 _newRate) external onlyOwner { 114 | require(_newRate <= 50, "Burn rate cannot exceed 50%"); 115 | burnRate = _newRate; 116 | } 117 | 118 | // View functions 119 | function getFollowerStatus(address follower, string memory symbol) external view returns (bool) { 120 | return activeFollows[follower][symbol]; 121 | } 122 | 123 | function getTraderRewards(address trader) external view returns (uint256) { 124 | return traderRewards[trader]; 125 | } 126 | } -------------------------------------------------------------------------------- /contracts/MemeInteraction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract MemeInteraction { 5 | // State variables 6 | address public owner; 7 | uint256 public memeCount; 8 | uint256 public minimumStakeAmount; 9 | 10 | struct Meme { 11 | address creator; 12 | string content; 13 | string imageHash; 14 | uint256 timestamp; 15 | uint256 likes; 16 | uint256 shares; 17 | mapping(address => bool) hasLiked; 18 | mapping(address => bool) hasShared; 19 | } 20 | 21 | mapping(uint256 => Meme) public memes; 22 | mapping(address => uint256[]) public userMemes; 23 | mapping(address => uint256) public userReputation; 24 | 25 | // Events 26 | event MemeCreated(uint256 indexed memeId, address indexed creator, string content, string imageHash); 27 | event MemeLiked(uint256 indexed memeId, address indexed liker); 28 | event MemeShared(uint256 indexed memeId, address indexed sharer); 29 | event ReputationUpdated(address indexed user, uint256 newReputation); 30 | 31 | constructor(uint256 _minimumStakeAmount) { 32 | owner = msg.sender; 33 | minimumStakeAmount = _minimumStakeAmount; 34 | memeCount = 0; 35 | } 36 | 37 | modifier onlyOwner() { 38 | require(msg.sender == owner, "Only owner can call this function"); 39 | _; 40 | } 41 | 42 | // Meme Creation and Interaction Functions 43 | function createMeme(string memory content, string memory imageHash) external { 44 | memeCount++; 45 | Meme storage meme = memes[memeCount]; 46 | meme.creator = msg.sender; 47 | meme.content = content; 48 | meme.imageHash = imageHash; 49 | meme.timestamp = block.timestamp; 50 | meme.likes = 0; 51 | meme.shares = 0; 52 | 53 | userMemes[msg.sender].push(memeCount); 54 | userReputation[msg.sender] += 1; 55 | 56 | emit MemeCreated(memeCount, msg.sender, content, imageHash); 57 | emit ReputationUpdated(msg.sender, userReputation[msg.sender]); 58 | } 59 | 60 | function likeMeme(uint256 memeId) external { 61 | Meme storage meme = memes[memeId]; 62 | require(!meme.hasLiked[msg.sender], "Already liked this meme"); 63 | 64 | meme.likes++; 65 | meme.hasLiked[msg.sender] = true; 66 | userReputation[meme.creator] += 1; 67 | 68 | emit MemeLiked(memeId, msg.sender); 69 | emit ReputationUpdated(meme.creator, userReputation[meme.creator]); 70 | } 71 | 72 | function shareMeme(uint256 memeId) external { 73 | Meme storage meme = memes[memeId]; 74 | require(!meme.hasShared[msg.sender], "Already shared this meme"); 75 | 76 | meme.shares++; 77 | meme.hasShared[msg.sender] = true; 78 | userReputation[meme.creator] += 2; 79 | userReputation[msg.sender] += 1; 80 | 81 | emit MemeShared(memeId, msg.sender); 82 | emit ReputationUpdated(meme.creator, userReputation[meme.creator]); 83 | emit ReputationUpdated(msg.sender, userReputation[msg.sender]); 84 | } 85 | 86 | // Reputation Management Functions 87 | function getReputation(address user) external view returns (uint256) { 88 | return userReputation[user]; 89 | } 90 | 91 | function getUserMemes(address user) external view returns (uint256[] memory) { 92 | return userMemes[user]; 93 | } 94 | 95 | // Admin Functions 96 | function updateMinimumStakeAmount(uint256 _newAmount) external onlyOwner { 97 | minimumStakeAmount = _newAmount; 98 | } 99 | } -------------------------------------------------------------------------------- /contracts/SocialInteraction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract SocialInteraction { 5 | // State variables 6 | address public owner; 7 | uint256 public tradingCompetitionId; 8 | uint256 public minimumStakeAmount; 9 | 10 | struct TradingCompetition { 11 | uint256 startTime; 12 | uint256 endTime; 13 | uint256 prizePool; 14 | mapping(address => uint256) participantScores; 15 | address[] participants; 16 | bool isActive; 17 | } 18 | 19 | struct CommunityPost { 20 | address author; 21 | string content; 22 | uint256 timestamp; 23 | uint256 likes; 24 | mapping(address => bool) hasLiked; 25 | } 26 | 27 | mapping(uint256 => TradingCompetition) public competitions; 28 | mapping(uint256 => CommunityPost) public posts; 29 | uint256 public postCount; 30 | mapping(address => uint256) public userStakes; 31 | 32 | // Events 33 | event CompetitionStarted(uint256 indexed competitionId, uint256 startTime, uint256 endTime); 34 | event CompetitionEnded(uint256 indexed competitionId, address[] winners); 35 | event PostCreated(uint256 indexed postId, address indexed author, string content); 36 | event PostLiked(uint256 indexed postId, address indexed liker); 37 | event UserStaked(address indexed user, uint256 amount); 38 | 39 | constructor(uint256 _minimumStakeAmount) { 40 | owner = msg.sender; 41 | minimumStakeAmount = _minimumStakeAmount; 42 | tradingCompetitionId = 0; 43 | postCount = 0; 44 | } 45 | 46 | modifier onlyOwner() { 47 | require(msg.sender == owner, "Only owner can call this function"); 48 | _; 49 | } 50 | 51 | modifier hasStaked() { 52 | require(userStakes[msg.sender] >= minimumStakeAmount, "Must stake minimum amount"); 53 | _; 54 | } 55 | 56 | // Trading Competition Functions 57 | function startCompetition(uint256 _duration) external onlyOwner { 58 | tradingCompetitionId++; 59 | uint256 startTime = block.timestamp; 60 | uint256 endTime = startTime + _duration; 61 | 62 | TradingCompetition storage competition = competitions[tradingCompetitionId]; 63 | competition.startTime = startTime; 64 | competition.endTime = endTime; 65 | competition.isActive = true; 66 | 67 | emit CompetitionStarted(tradingCompetitionId, startTime, endTime); 68 | } 69 | 70 | function joinCompetition() external hasStaked { 71 | TradingCompetition storage competition = competitions[tradingCompetitionId]; 72 | require(competition.isActive, "No active competition"); 73 | require(block.timestamp < competition.endTime, "Competition ended"); 74 | 75 | competition.participants.push(msg.sender); 76 | competition.participantScores[msg.sender] = 0; 77 | } 78 | 79 | function updateScore(address participant, uint256 score) external onlyOwner { 80 | TradingCompetition storage competition = competitions[tradingCompetitionId]; 81 | require(competition.isActive, "No active competition"); 82 | competition.participantScores[participant] = score; 83 | } 84 | 85 | function endCompetition() external onlyOwner { 86 | TradingCompetition storage competition = competitions[tradingCompetitionId]; 87 | require(competition.isActive, "No active competition"); 88 | require(block.timestamp >= competition.endTime, "Competition still ongoing"); 89 | 90 | competition.isActive = false; 91 | 92 | // Calculate winners (top 3) 93 | address[] memory winners = new address[](3); 94 | uint256[] memory topScores = new uint256[](3); 95 | 96 | for (uint256 i = 0; i < competition.participants.length; i++) { 97 | address participant = competition.participants[i]; 98 | uint256 score = competition.participantScores[participant]; 99 | 100 | for (uint256 j = 0; j < 3; j++) { 101 | if (score > topScores[j]) { 102 | // Shift lower scores down 103 | for (uint256 k = 2; k > j; k--) { 104 | topScores[k] = topScores[k-1]; 105 | winners[k] = winners[k-1]; 106 | } 107 | topScores[j] = score; 108 | winners[j] = participant; 109 | break; 110 | } 111 | } 112 | } 113 | 114 | emit CompetitionEnded(tradingCompetitionId, winners); 115 | } 116 | 117 | // Community Interaction Functions 118 | function createPost(string memory content) external hasStaked { 119 | postCount++; 120 | CommunityPost storage post = posts[postCount]; 121 | post.author = msg.sender; 122 | post.content = content; 123 | post.timestamp = block.timestamp; 124 | post.likes = 0; 125 | 126 | emit PostCreated(postCount, msg.sender, content); 127 | } 128 | 129 | function likePost(uint256 postId) external hasStaked { 130 | CommunityPost storage post = posts[postId]; 131 | require(!post.hasLiked[msg.sender], "Already liked this post"); 132 | 133 | post.likes++; 134 | post.hasLiked[msg.sender] = true; 135 | 136 | emit PostLiked(postId, msg.sender); 137 | } 138 | 139 | // Staking Functions 140 | function stake() external payable { 141 | require(msg.value > 0, "Must stake some amount"); 142 | userStakes[msg.sender] += msg.value; 143 | emit UserStaked(msg.sender, msg.value); 144 | } 145 | 146 | function withdraw(uint256 amount) external { 147 | require(userStakes[msg.sender] >= amount, "Insufficient stake"); 148 | userStakes[msg.sender] -= amount; 149 | payable(msg.sender).transfer(amount); 150 | } 151 | } -------------------------------------------------------------------------------- /contracts/TokenGovernance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract TokenGovernance { 5 | // State variables 6 | address public owner; 7 | uint256 public proposalCount; 8 | uint256 public minimumStakeForProposal; 9 | uint256 public votingPeriod; 10 | 11 | struct Proposal { 12 | address proposer; 13 | string description; 14 | uint256 startTime; 15 | uint256 endTime; 16 | uint256 forVotes; 17 | uint256 againstVotes; 18 | bool executed; 19 | mapping(address => bool) hasVoted; 20 | mapping(address => uint256) stakedAmount; 21 | } 22 | 23 | mapping(uint256 => Proposal) public proposals; 24 | mapping(address => uint256) public userStakes; 25 | mapping(address => uint256) public votingPower; 26 | 27 | // Events 28 | event ProposalCreated(uint256 indexed proposalId, address indexed proposer, string description); 29 | event VoteCast(uint256 indexed proposalId, address indexed voter, bool support, uint256 weight); 30 | event ProposalExecuted(uint256 indexed proposalId); 31 | event TokensStaked(address indexed user, uint256 amount); 32 | event TokensUnstaked(address indexed user, uint256 amount); 33 | 34 | constructor(uint256 _minimumStakeForProposal, uint256 _votingPeriod) { 35 | owner = msg.sender; 36 | minimumStakeForProposal = _minimumStakeForProposal; 37 | votingPeriod = _votingPeriod; 38 | proposalCount = 0; 39 | } 40 | 41 | modifier onlyOwner() { 42 | require(msg.sender == owner, "Only owner can call this function"); 43 | _; 44 | } 45 | 46 | // Staking Functions 47 | function stake() external payable { 48 | require(msg.value > 0, "Must stake some amount"); 49 | userStakes[msg.sender] += msg.value; 50 | votingPower[msg.sender] = calculateVotingPower(msg.sender); 51 | emit TokensStaked(msg.sender, msg.value); 52 | } 53 | 54 | function unstake(uint256 amount) external { 55 | require(userStakes[msg.sender] >= amount, "Insufficient stake"); 56 | require(canUnstake(msg.sender, amount), "Tokens locked in active proposals"); 57 | 58 | userStakes[msg.sender] -= amount; 59 | votingPower[msg.sender] = calculateVotingPower(msg.sender); 60 | payable(msg.sender).transfer(amount); 61 | 62 | emit TokensUnstaked(msg.sender, amount); 63 | } 64 | 65 | // Governance Functions 66 | function createProposal(string memory description) external { 67 | require(userStakes[msg.sender] >= minimumStakeForProposal, "Insufficient stake to create proposal"); 68 | 69 | proposalCount++; 70 | Proposal storage proposal = proposals[proposalCount]; 71 | proposal.proposer = msg.sender; 72 | proposal.description = description; 73 | proposal.startTime = block.timestamp; 74 | proposal.endTime = block.timestamp + votingPeriod; 75 | 76 | emit ProposalCreated(proposalCount, msg.sender, description); 77 | } 78 | 79 | function castVote(uint256 proposalId, bool support) external { 80 | Proposal storage proposal = proposals[proposalId]; 81 | require(block.timestamp <= proposal.endTime, "Voting period ended"); 82 | require(!proposal.hasVoted[msg.sender], "Already voted"); 83 | require(votingPower[msg.sender] > 0, "No voting power"); 84 | 85 | uint256 weight = votingPower[msg.sender]; 86 | if (support) { 87 | proposal.forVotes += weight; 88 | } else { 89 | proposal.againstVotes += weight; 90 | } 91 | 92 | proposal.hasVoted[msg.sender] = true; 93 | proposal.stakedAmount[msg.sender] = userStakes[msg.sender]; 94 | 95 | emit VoteCast(proposalId, msg.sender, support, weight); 96 | } 97 | 98 | function executeProposal(uint256 proposalId) external { 99 | Proposal storage proposal = proposals[proposalId]; 100 | require(block.timestamp > proposal.endTime, "Voting period not ended"); 101 | require(!proposal.executed, "Proposal already executed"); 102 | 103 | proposal.executed = true; 104 | 105 | emit ProposalExecuted(proposalId); 106 | } 107 | 108 | // Helper Functions 109 | function calculateVotingPower(address user) public view returns (uint256) { 110 | return userStakes[user]; 111 | } 112 | 113 | function canUnstake(address user, uint256 amount) internal view returns (bool) { 114 | uint256 lockedAmount = 0; 115 | for (uint256 i = 1; i <= proposalCount; i++) { 116 | Proposal storage proposal = proposals[i]; 117 | if (!proposal.executed && proposal.hasVoted[user]) { 118 | lockedAmount += proposal.stakedAmount[user]; 119 | } 120 | } 121 | return userStakes[user] - lockedAmount >= amount; 122 | } 123 | 124 | // Admin Functions 125 | function updateMinimumStakeForProposal(uint256 _newAmount) external onlyOwner { 126 | minimumStakeForProposal = _newAmount; 127 | } 128 | 129 | function updateVotingPeriod(uint256 _newPeriod) external onlyOwner { 130 | votingPeriod = _newPeriod; 131 | } 132 | } -------------------------------------------------------------------------------- /docs/API.md: -------------------------------------------------------------------------------- 1 | # DeepRug API Documentation 2 | 3 | ## Smart Contract Interfaces 4 | 5 | ### FollowTrade Contract 6 | 7 | #### State Variables 8 | 9 | - `owner` (address): Contract owner's address 10 | - `followFee` (uint256): Fee required for following trades 11 | - `burnRate` (uint256): Token burn rate (0-50%) 12 | - `totalBurned` (uint256): Total amount of tokens burned 13 | - `balances` (mapping): User balance mapping 14 | - `activeFollows` (mapping): User active follow status 15 | - `traderRewards` (mapping): Trader reward balances 16 | 17 | #### Events 18 | 19 | ```solidity 20 | event FollowTradeStarted(address follower, string symbol, uint256 fee) 21 | event ProfitDistributed(address trader, address follower, uint256 amount) 22 | event TokensBurned(uint256 amount) 23 | event RewardsWithdrawn(address user, uint256 amount) 24 | ``` 25 | 26 | #### Functions 27 | 28 | ##### startFollow 29 | ```solidity 30 | function startFollow(string memory symbol) external payable 31 | ``` 32 | Start following a trade. 33 | - Parameters: 34 | - `symbol`: Trading pair symbol 35 | - Requirements: 36 | - Paid fee must be greater than or equal to followFee 37 | - User cannot follow the same trading pair multiple times 38 | 39 | ##### distributeProfits 40 | ```solidity 41 | function distributeProfits(address[] calldata followers, uint256[] calldata amounts) external onlyOwner 42 | ``` 43 | Distribute profits. 44 | - Parameters: 45 | - `followers`: Array of follower addresses 46 | - `amounts`: Array of corresponding profit amounts 47 | - Distribution rules: 48 | - Trader receives 70% of profits 49 | - Follower receives 30% of profits 50 | 51 | ##### withdrawRewards 52 | ```solidity 53 | function withdrawRewards() external 54 | ``` 55 | Withdraw trading rewards. 56 | 57 | ##### withdraw 58 | ```solidity 59 | function withdraw() external 60 | ``` 61 | Withdraw account balance. 62 | 63 | ##### updateFollowFee 64 | ```solidity 65 | function updateFollowFee(uint256 _newFee) external onlyOwner 66 | ``` 67 | Update follow fee. 68 | 69 | ##### updateBurnRate 70 | ```solidity 71 | function updateBurnRate(uint256 _newRate) external onlyOwner 72 | ``` 73 | Update token burn rate. 74 | 75 | ## Trading Service API 76 | 77 | ### WebSocket Interface 78 | 79 | #### Connection 80 | ```javascript 81 | ws://localhost:8081 82 | ``` 83 | 84 | #### Message Types 85 | 86 | ##### Follow Request 87 | ```javascript 88 | { 89 | "type": "follow_request", 90 | "trader": "", 91 | "symbol": "", 92 | "publicKey": "" 93 | } 94 | ``` 95 | 96 | ##### Unfollow Request 97 | ```javascript 98 | { 99 | "type": "unfollow_request", 100 | "trader": "", 101 | "symbol": "" 102 | } 103 | ``` 104 | 105 | --- 106 | 107 | [点击查看中文文档] 108 | 109 | # DeepRug API 文档 110 | 111 | ## 智能合约接口 112 | 113 | ### 跟随交易合约 114 | 115 | #### 状态变量 116 | 117 | - `owner` (address): 合约所有者地址 118 | - `followFee` (uint256): 跟随交易所需的费用 119 | - `burnRate` (uint256): 代币销毁比率(0-50%) 120 | - `totalBurned` (uint256): 已销毁代币总量 121 | - `balances` (mapping): 用户余额映射 122 | - `activeFollows` (mapping): 用户活跃跟随状态 123 | - `traderRewards` (mapping): 交易者奖励余额 124 | 125 | #### 事件 126 | 127 | ```solidity 128 | event FollowTradeStarted(address follower, string symbol, uint256 fee) 129 | event ProfitDistributed(address trader, address follower, uint256 amount) 130 | event TokensBurned(uint256 amount) 131 | event RewardsWithdrawn(address user, uint256 amount) 132 | ``` 133 | 134 | 事件说明: 135 | - FollowTradeStarted:开始跟随交易时触发 136 | - ProfitDistributed:分配利润时触发 137 | - TokensBurned:代币销毁时触发 138 | - RewardsWithdrawn:提取奖励时触发 139 | 140 | #### 函数 141 | 142 | ##### 开始跟随 143 | ```solidity 144 | function startFollow(string memory symbol) external payable 145 | ``` 146 | 开始跟随一个交易。 147 | - 参数: 148 | - `symbol`: 交易对符号 149 | - 要求: 150 | - 支付的费用必须大于或等于跟随费用 151 | - 用户不能多次跟随同一个交易对 152 | 153 | ##### 分配利润 154 | ```solidity 155 | function distributeProfits(address[] calldata followers, uint256[] calldata amounts) external onlyOwner 156 | ``` 157 | 分配利润。 158 | - 参数: 159 | - `followers`: 跟随者地址数组 160 | - `amounts`: 对应的利润金额数组 161 | - 分配规则: 162 | - 交易者获得70%的利润 163 | - 跟随者获得30%的利润 164 | 165 | ##### 提取奖励 166 | ```solidity 167 | function withdrawRewards() external 168 | ``` 169 | 提取交易奖励。 170 | 171 | ##### 提取余额 172 | ```solidity 173 | function withdraw() external 174 | ``` 175 | 提取账户余额。 176 | 177 | ##### 更新跟随费用 178 | ```solidity 179 | function updateFollowFee(uint256 _newFee) external onlyOwner 180 | ``` 181 | 更新跟随费用。 182 | 183 | ##### 更新销毁比率 184 | ```solidity 185 | function updateBurnRate(uint256 _newRate) external onlyOwner 186 | ``` 187 | 更新代币销毁比率。 188 | 189 | ## 交易服务API 190 | 191 | ### WebSocket接口 192 | 193 | #### 连接 194 | ```javascript 195 | ws://localhost:8081 196 | ``` 197 | 198 | #### 消息类型 199 | 200 | ##### 跟随请求 201 | ```javascript 202 | { 203 | "type": "follow_request", 204 | "trader": "", 205 | "symbol": "", 206 | "publicKey": "" 207 | } 208 | ``` 209 | 210 | ##### 取消跟随请求 211 | ```javascript 212 | { 213 | "type": "unfollow_request", 214 | "trader": "", 215 | "symbol": "" 216 | } 217 | ``` -------------------------------------------------------------------------------- /docs/DEVELOPER.md: -------------------------------------------------------------------------------- 1 | # DeepRug Developer Documentation 2 | 3 | ## Project Architecture 4 | 5 | ### System Components 6 | 7 | 1. Smart Contracts 8 | - FollowTrade.sol: Core contract for follow trading 9 | - Implements user following, profit distribution, token burning functionalities 10 | 11 | 2. Trading Engine 12 | - Located in src/ai_engine directory 13 | - market_data.py: Market data collection and processing 14 | - ml_models.py: Machine learning models 15 | - risk_manager.py: Risk management module 16 | - trading_engine.py: Trading strategy execution 17 | 18 | 3. Service Layer 19 | - follow_trade_service.js: Follow trading service 20 | - trading_service.js: Trade execution service 21 | 22 | ### Tech Stack 23 | 24 | - Smart Contracts: Solidity ^0.8.0 25 | - Backend Services: Node.js 26 | - AI Engine: Python 27 | - WebSocket: Real-time communication 28 | 29 | ## Environment Setup 30 | 31 | ### Prerequisites 32 | 33 | - Node.js >= 14.0.0 34 | - Python >= 3.8 35 | - Solidity ^0.8.0 36 | - Hardhat or Truffle (Smart contract development framework) 37 | 38 | ### Dependencies Installation 39 | 40 | 1. Install Node.js dependencies 41 | ```bash 42 | npm install 43 | ``` 44 | 45 | 2. Install Python dependencies 46 | ```bash 47 | pip install -r requirements.txt 48 | ``` 49 | 50 | ## Local Development 51 | 52 | ### 1. Start Local Blockchain 53 | ```bash 54 | npx hardhat node 55 | ``` 56 | 57 | ### 2. Deploy Smart Contracts 58 | ```bash 59 | npx hardhat run scripts/deploy.js --network localhost 60 | ``` 61 | 62 | ### 3. Start Trading Service 63 | ```bash 64 | node src/index.js 65 | ``` 66 | 67 | ### 4. Start AI Engine 68 | ```bash 69 | python src/ai_engine/trading_engine.py 70 | ``` 71 | 72 | ## Testing 73 | 74 | ### Smart Contract Tests 75 | ```bash 76 | npx hardhat test 77 | ``` 78 | 79 | ### AI Engine Tests 80 | ```bash 81 | python -m pytest tests/ai_engine 82 | ``` 83 | 84 | ## Deployment Process 85 | 86 | ### 1. Prepare Environment Variables 87 | Create .env file: 88 | ``` 89 | PRIVATE_KEY=your_private_key 90 | INFURA_API_KEY=your_infura_key 91 | FOLLOW_FEE=1000000000000000000 92 | BURN_RATE=10 93 | ``` 94 | 95 | ### 2. Compile Contracts 96 | ```bash 97 | npx hardhat compile 98 | ``` 99 | 100 | ### 3. Deploy to Testnet 101 | ```bash 102 | npx hardhat run scripts/deploy.js --network testnet 103 | ``` 104 | 105 | --- 106 | 107 | [点击查看中文文档] 108 | 109 | # DeepRug 开发者文档 110 | 111 | ## 项目架构 112 | 113 | ### 系统组件 114 | 115 | 1. 智能合约 116 | - FollowTrade.sol: 跟随交易的核心合约 117 | - 实现用户跟随、利润分配、代币销毁等功能 118 | 119 | 2. 交易引擎 120 | - 位于src/ai_engine目录 121 | - market_data.py: 市场数据收集和处理 122 | - ml_models.py: 机器学习模型 123 | - risk_manager.py: 风险管理模块 124 | - trading_engine.py: 交易策略执行 125 | 126 | 3. 服务层 127 | - follow_trade_service.js: 跟随交易服务 128 | - trading_service.js: 交易执行服务 129 | 130 | ### 技术栈 131 | 132 | - 智能合约: Solidity ^0.8.0 133 | - 后端服务: Node.js 134 | - AI引擎: Python 135 | - WebSocket: 实时通信 136 | 137 | ## 环境配置 138 | 139 | ### 前置要求 140 | 141 | - Node.js >= 14.0.0 142 | - Python >= 3.8 143 | - Solidity ^0.8.0 144 | - Hardhat 或 Truffle (智能合约开发框架) 145 | 146 | ### 依赖安装 147 | 148 | 1. 安装Node.js依赖 149 | ```bash 150 | npm install 151 | ``` 152 | 153 | 2. 安装Python依赖 154 | ```bash 155 | pip install -r requirements.txt 156 | ``` 157 | 158 | ## 本地开发 159 | 160 | ### 1. 启动本地区块链 161 | ```bash 162 | npx hardhat node 163 | ``` 164 | 165 | ### 2. 部署智能合约 166 | ```bash 167 | npx hardhat run scripts/deploy.js --network localhost 168 | ``` 169 | 170 | ### 3. 启动交易服务 171 | ```bash 172 | node src/index.js 173 | ``` 174 | 175 | ### 4. 启动AI引擎 176 | ```bash 177 | python src/ai_engine/trading_engine.py 178 | ``` 179 | 180 | ## 测试 181 | 182 | ### 智能合约测试 183 | ```bash 184 | npx hardhat test 185 | ``` 186 | 187 | ### AI引擎测试 188 | ```bash 189 | python -m pytest tests/ai_engine 190 | ``` 191 | 192 | ## 部署流程 193 | 194 | ### 1. 准备环境变量 195 | 创建.env文件: 196 | ``` 197 | PRIVATE_KEY=你的私钥 198 | INFURA_API_KEY=你的Infura密钥 199 | FOLLOW_FEE=1000000000000000000 200 | BURN_RATE=10 201 | ``` 202 | 203 | ### 2. 编译合约 204 | ```bash 205 | npx hardhat compile 206 | ``` 207 | 208 | ### 3. 部署到测试网 209 | ```bash 210 | npx hardhat run scripts/deploy.js --network testnet 211 | ``` 212 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deeprug", 3 | "version": "0.1.0", 4 | "description": "A revolutionary AI quantitative trading platform that perfectly combines AI trading strategies with social entertainment", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node src/index.js", 8 | "test": "jest", 9 | "dev": "nodemon src/index.js" 10 | }, 11 | "keywords": [ 12 | "AI", 13 | "trading", 14 | "blockchain", 15 | "DeepSeek", 16 | "cryptocurrency" 17 | ], 18 | "author": "DeepRug Team", 19 | "license": "MIT", 20 | "dependencies": { 21 | "express": "^4.18.2", 22 | "web3": "^4.1.1", 23 | "socket.io": "^4.7.2", 24 | "mongoose": "^7.5.0", 25 | "axios": "^1.5.0", 26 | "dotenv": "^16.3.1" 27 | }, 28 | "devDependencies": { 29 | "jest": "^29.6.4", 30 | "nodemon": "^3.0.1", 31 | "eslint": "^8.48.0" 32 | } 33 | } -------------------------------------------------------------------------------- /program/src/follow_trade.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | use anchor_spl::token::{self, Token, TokenAccount, Transfer}; 3 | 4 | #[program] 5 | pub mod follow_trade { 6 | use super::*; 7 | 8 | pub fn initialize( 9 | ctx: Context, 10 | follow_fee: u64, 11 | burn_rate: u8, 12 | ) -> Result<()> { 13 | let state = &mut ctx.accounts.state; 14 | state.owner = ctx.accounts.owner.key(); 15 | state.follow_fee = follow_fee; 16 | state.burn_rate = burn_rate; 17 | state.total_followers = 0; 18 | Ok(()) 19 | } 20 | 21 | pub fn start_follow( 22 | ctx: Context, 23 | symbol: String, 24 | ) -> Result<()> { 25 | let follow = &mut ctx.accounts.follow; 26 | follow.trader = ctx.accounts.trader.key(); 27 | follow.follower = ctx.accounts.follower.key(); 28 | follow.symbol = symbol; 29 | follow.active = true; 30 | follow.timestamp = Clock::get()?.unix_timestamp; 31 | 32 | let state = &mut ctx.accounts.state; 33 | state.total_followers = state.total_followers.checked_add(1).unwrap(); 34 | 35 | emit!(FollowStarted { 36 | trader: follow.trader, 37 | follower: follow.follower, 38 | symbol: follow.symbol.clone(), 39 | timestamp: follow.timestamp, 40 | }); 41 | 42 | Ok(()) 43 | } 44 | 45 | pub fn distribute_profit( 46 | ctx: Context, 47 | amount: u64, 48 | ) -> Result<()> { 49 | let follow = &ctx.accounts.follow; 50 | require!(follow.active, ErrorCode::FollowNotActive); 51 | 52 | // Calculate profit share 53 | let trader_share = (amount * 70) / 100; // 70% to trader 54 | let follower_share = amount - trader_share; // 30% to follower 55 | 56 | // Transfer profit shares 57 | token::transfer( 58 | CpiContext::new( 59 | ctx.accounts.token_program.to_account_info(), 60 | Transfer { 61 | from: ctx.accounts.profit_pool.to_account_info(), 62 | to: ctx.accounts.trader_token.to_account_info(), 63 | authority: ctx.accounts.state.to_account_info(), 64 | }, 65 | ), 66 | trader_share, 67 | )?; 68 | 69 | token::transfer( 70 | CpiContext::new( 71 | ctx.accounts.token_program.to_account_info(), 72 | Transfer { 73 | from: ctx.accounts.profit_pool.to_account_info(), 74 | to: ctx.accounts.follower_token.to_account_info(), 75 | authority: ctx.accounts.state.to_account_info(), 76 | }, 77 | ), 78 | follower_share, 79 | )?; 80 | 81 | emit!(ProfitDistributed { 82 | trader: follow.trader, 83 | follower: follow.follower, 84 | amount, 85 | trader_share, 86 | follower_share, 87 | }); 88 | 89 | Ok(()) 90 | } 91 | } 92 | 93 | #[derive(Accounts)] 94 | pub struct Initialize<'info> { 95 | #[account(init, payer = owner, space = 8 + State::LEN)] 96 | pub state: Account<'info, State>, 97 | #[account(mut)] 98 | pub owner: Signer<'info>, 99 | pub system_program: Program<'info, System>, 100 | } 101 | 102 | #[derive(Accounts)] 103 | pub struct StartFollow<'info> { 104 | #[account(init, payer = follower, space = 8 + Follow::LEN)] 105 | pub follow: Account<'info, Follow>, 106 | #[account(mut)] 107 | pub state: Account<'info, State>, 108 | pub trader: AccountInfo<'info>, 109 | #[account(mut)] 110 | pub follower: Signer<'info>, 111 | pub system_program: Program<'info, System>, 112 | } 113 | 114 | #[derive(Accounts)] 115 | pub struct DistributeProfit<'info> { 116 | #[account(mut)] 117 | pub follow: Account<'info, Follow>, 118 | #[account(mut)] 119 | pub state: Account<'info, State>, 120 | #[account(mut)] 121 | pub profit_pool: Account<'info, TokenAccount>, 122 | #[account(mut)] 123 | pub trader_token: Account<'info, TokenAccount>, 124 | #[account(mut)] 125 | pub follower_token: Account<'info, TokenAccount>, 126 | pub token_program: Program<'info, Token>, 127 | } 128 | 129 | #[account] 130 | pub struct State { 131 | pub owner: Pubkey, 132 | pub follow_fee: u64, 133 | pub burn_rate: u8, 134 | pub total_followers: u64, 135 | } 136 | 137 | #[account] 138 | pub struct Follow { 139 | pub trader: Pubkey, 140 | pub follower: Pubkey, 141 | pub symbol: String, 142 | pub active: bool, 143 | pub timestamp: i64, 144 | } 145 | 146 | #[event] 147 | pub struct FollowStarted { 148 | pub trader: Pubkey, 149 | pub follower: Pubkey, 150 | pub symbol: String, 151 | pub timestamp: i64, 152 | } 153 | 154 | #[event] 155 | pub struct ProfitDistributed { 156 | pub trader: Pubkey, 157 | pub follower: Pubkey, 158 | pub amount: u64, 159 | pub trader_share: u64, 160 | pub follower_share: u64, 161 | } 162 | 163 | #[error_code] 164 | pub enum ErrorCode { 165 | #[msg("Follow is not active")] 166 | FollowNotActive, 167 | } -------------------------------------------------------------------------------- /program/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | use anchor_spl::token::{self, Burn, Mint, Token, TokenAccount, Transfer}; 3 | 4 | declare_id!("RUGTokenProgramID111111111111111111111111111111"); 5 | 6 | #[program] 7 | pub mod rug_token { 8 | use super::*; 9 | 10 | pub fn initialize( 11 | ctx: Context, 12 | initial_supply: u64, 13 | follow_trade_fee: u64, 14 | burn_rate: u8, 15 | ) -> Result<()> { 16 | let token_program = &ctx.program; 17 | let token_mint = &ctx.accounts.mint; 18 | let owner = &ctx.accounts.owner; 19 | 20 | // Initialize state 21 | let state = &mut ctx.accounts.state; 22 | state.owner = owner.key(); 23 | state.follow_trade_fee = follow_trade_fee; 24 | state.burn_rate = burn_rate; 25 | state.trading_system = Pubkey::default(); 26 | 27 | // Mint initial supply to owner 28 | token::mint_to( 29 | CpiContext::new( 30 | token_program.to_account_info(), 31 | token::MintTo { 32 | mint: token_mint.to_account_info(), 33 | to: owner.to_account_info(), 34 | authority: token_mint.to_account_info(), 35 | }, 36 | ), 37 | initial_supply, 38 | )?; 39 | 40 | Ok(()) 41 | } 42 | 43 | pub fn set_trading_system( 44 | ctx: Context, 45 | trading_system: Pubkey, 46 | ) -> Result<()> { 47 | require!(trading_system != Pubkey::default(), "Invalid address"); 48 | let state = &mut ctx.accounts.state; 49 | state.trading_system = trading_system; 50 | Ok(()) 51 | } 52 | 53 | pub fn pay_follow_trade_fee(ctx: Context) -> Result<()> { 54 | let state = &ctx.accounts.state; 55 | let fee = state.follow_trade_fee; 56 | let burn_amount = (fee * state.burn_rate as u64) / 100; 57 | let system_amount = fee - burn_amount; 58 | 59 | // Burn tokens 60 | token::burn( 61 | CpiContext::new( 62 | ctx.accounts.token_program.to_account_info(), 63 | Burn { 64 | mint: ctx.accounts.mint.to_account_info(), 65 | from: ctx.accounts.user_token_account.to_account_info(), 66 | authority: ctx.accounts.user.to_account_info(), 67 | }, 68 | ), 69 | burn_amount, 70 | )?; 71 | 72 | // Transfer to trading system 73 | token::transfer( 74 | CpiContext::new( 75 | ctx.accounts.token_program.to_account_info(), 76 | Transfer { 77 | from: ctx.accounts.user_token_account.to_account_info(), 78 | to: ctx.accounts.trading_system_token_account.to_account_info(), 79 | authority: ctx.accounts.user.to_account_info(), 80 | }, 81 | ), 82 | system_amount, 83 | )?; 84 | 85 | emit!(FollowTradeFeePaid { 86 | user: ctx.accounts.user.key(), 87 | amount: fee, 88 | }); 89 | 90 | Ok(()) 91 | } 92 | 93 | pub fn update_follow_trade_fee( 94 | ctx: Context, 95 | new_fee: u64, 96 | ) -> Result<()> { 97 | let state = &mut ctx.accounts.state; 98 | state.follow_trade_fee = new_fee; 99 | Ok(()) 100 | } 101 | 102 | pub fn update_burn_rate( 103 | ctx: Context, 104 | new_rate: u8, 105 | ) -> Result<()> { 106 | require!(new_rate <= 100, "Burn rate cannot exceed 100%"); 107 | let state = &mut ctx.accounts.state; 108 | state.burn_rate = new_rate; 109 | Ok(()) 110 | } 111 | } 112 | 113 | #[derive(Accounts)] 114 | pub struct Initialize<'info> { 115 | #[account(init, payer = owner, space = 8 + TokenState::LEN)] 116 | pub state: Account<'info, TokenState>, 117 | #[account(mut)] 118 | pub mint: Account<'info, Mint>, 119 | #[account(mut)] 120 | pub owner: Signer<'info>, 121 | pub system_program: Program<'info, System>, 122 | pub token_program: Program<'info, Token>, 123 | } 124 | 125 | #[derive(Accounts)] 126 | pub struct SetTradingSystem<'info> { 127 | #[account(mut, has_one = owner)] 128 | pub state: Account<'info, TokenState>, 129 | pub owner: Signer<'info>, 130 | } 131 | 132 | #[derive(Accounts)] 133 | pub struct PayFollowTradeFee<'info> { 134 | #[account(mut)] 135 | pub state: Account<'info, TokenState>, 136 | #[account(mut)] 137 | pub mint: Account<'info, Mint>, 138 | #[account(mut)] 139 | pub user_token_account: Account<'info, TokenAccount>, 140 | #[account(mut)] 141 | pub trading_system_token_account: Account<'info, TokenAccount>, 142 | pub user: Signer<'info>, 143 | pub token_program: Program<'info, Token>, 144 | } 145 | 146 | #[derive(Accounts)] 147 | pub struct UpdateFollowTradeFee<'info> { 148 | #[account(mut, has_one = owner)] 149 | pub state: Account<'info, TokenState>, 150 | pub owner: Signer<'info>, 151 | } 152 | 153 | #[derive(Accounts)] 154 | pub struct UpdateBurnRate<'info> { 155 | #[account(mut, has_one = owner)] 156 | pub state: Account<'info, TokenState>, 157 | pub owner: Signer<'info>, 158 | } 159 | 160 | #[account] 161 | pub struct TokenState { 162 | pub owner: Pubkey, 163 | pub follow_trade_fee: u64, 164 | pub burn_rate: u8, 165 | pub trading_system: Pubkey, 166 | } 167 | 168 | impl TokenState { 169 | pub const LEN: usize = 32 + 8 + 1 + 32; 170 | } 171 | 172 | #[event] 173 | pub struct FollowTradeFeePaid { 174 | pub user: Pubkey, 175 | pub amount: u64, 176 | } 177 | 178 | #[event] 179 | pub struct TokensBurned { 180 | pub amount: u64, 181 | } -------------------------------------------------------------------------------- /src/ai_engine/market_data.py: -------------------------------------------------------------------------------- 1 | import ccxt 2 | import numpy as np 3 | import pandas as pd 4 | from datetime import datetime, timedelta 5 | import logging 6 | 7 | class MarketDataCollector: 8 | def __init__(self, exchange_id='binance', api_key=None, api_secret=None): 9 | self.exchange = getattr(ccxt, exchange_id)({ 10 | 'apiKey': api_key, 11 | 'secret': api_secret, 12 | 'enableRateLimit': True, 13 | 'options': {'defaultType': 'future'} 14 | }) 15 | self.logger = logging.getLogger(__name__) 16 | 17 | def fetch_historical_data(self, symbol, timeframe='1h', limit=1000): 18 | """获取历史K线数据""" 19 | try: 20 | ohlcv = self.exchange.fetch_ohlcv(symbol, timeframe, limit=limit) 21 | return self._convert_to_dataframe(ohlcv) 22 | except Exception as e: 23 | self.logger.error(f"Error fetching historical data: {str(e)}") 24 | return None 25 | 26 | def fetch_orderbook(self, symbol, limit=20): 27 | """获取市场深度数据""" 28 | try: 29 | orderbook = self.exchange.fetch_order_book(symbol, limit=limit) 30 | return { 31 | 'bids': np.array(orderbook['bids']), 32 | 'asks': np.array(orderbook['asks']), 33 | 'timestamp': orderbook['timestamp'] 34 | } 35 | except Exception as e: 36 | self.logger.error(f"Error fetching orderbook: {str(e)}") 37 | return None 38 | 39 | def fetch_recent_trades(self, symbol, limit=100): 40 | """获取最近成交数据""" 41 | try: 42 | trades = self.exchange.fetch_trades(symbol, limit=limit) 43 | return pd.DataFrame(trades) 44 | except Exception as e: 45 | self.logger.error(f"Error fetching recent trades: {str(e)}") 46 | return None 47 | 48 | def _convert_to_dataframe(self, ohlcv): 49 | """将OHLCV数据转换为DataFrame格式""" 50 | df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) 51 | df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') 52 | return df 53 | 54 | def calculate_vwap(self, trades_df): 55 | """计算成交量加权平均价格""" 56 | if trades_df is None or trades_df.empty: 57 | return None 58 | 59 | trades_df['vwap'] = (trades_df['price'] * trades_df['amount']).cumsum() / trades_df['amount'].cumsum() 60 | return trades_df['vwap'].iloc[-1] 61 | 62 | def calculate_market_impact(self, orderbook, trade_size): 63 | """计算市场冲击成本""" 64 | if orderbook is None: 65 | return None 66 | 67 | bids, asks = orderbook['bids'], orderbook['asks'] 68 | 69 | def calculate_impact(orders, size, side='buy'): 70 | remaining_size = size 71 | total_cost = 0 72 | for price, volume in orders: 73 | if remaining_size <= 0: 74 | break 75 | executed = min(remaining_size, volume) 76 | total_cost += executed * price 77 | remaining_size -= executed 78 | return total_cost / size if remaining_size <= 0 else None 79 | 80 | buy_impact = calculate_impact(asks, trade_size, 'buy') 81 | sell_impact = calculate_impact(bids, trade_size, 'sell') 82 | 83 | return { 84 | 'buy_impact': buy_impact, 85 | 'sell_impact': sell_impact 86 | } -------------------------------------------------------------------------------- /src/ai_engine/meme_generator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | from PIL import Image, ImageDraw, ImageFont 4 | from transformers import pipeline 5 | 6 | class MemeGenerator: 7 | def __init__(self): 8 | self.sentiment_analyzer = pipeline('sentiment-analysis') 9 | self.text_generator = pipeline('text-generation') 10 | self.templates_dir = os.path.join(os.path.dirname(__file__), 'meme_templates') 11 | self.fonts_dir = os.path.join(os.path.dirname(__file__), 'fonts') 12 | 13 | def analyze_trade_sentiment(self, trade_data): 14 | """分析交易数据情绪""" 15 | trade_text = f"Trade {trade_data['symbol']} at {trade_data['price']} with {trade_data['profit_loss']}" 16 | sentiment = self.sentiment_analyzer(trade_text)[0] 17 | return sentiment['label'], sentiment['score'] 18 | 19 | def generate_meme_text(self, sentiment, trade_data): 20 | """根据交易情绪生成嘲讽文本""" 21 | prompt_templates = { 22 | 'POSITIVE': [ 23 | "When you make {profit} on {symbol} and others are still waiting for dips:", 24 | "Me watching my {symbol} position going to the moon:", 25 | "That moment when your {symbol} trade hits the target:" 26 | ], 27 | 'NEGATIVE': [ 28 | "When you thought {symbol} was going up but it dumps instead:", 29 | "Me watching my {symbol} position getting liquidated:", 30 | "That feeling when you FOMO into {symbol} at the top:" 31 | ] 32 | } 33 | 34 | templates = prompt_templates['POSITIVE'] if sentiment == 'POSITIVE' else prompt_templates['NEGATIVE'] 35 | template = random.choice(templates) 36 | 37 | return template.format( 38 | symbol=trade_data['symbol'], 39 | profit=trade_data.get('profit_loss', '0') 40 | ) 41 | 42 | def create_meme(self, text, template_name='default.jpg', style='classic'): 43 | """创建Meme图片 44 | Args: 45 | text: 要添加的文本 46 | template_name: 模板图片名称 47 | style: 文字样式 ('classic', 'modern', 'minimal', 'bold') 48 | Returns: 49 | 生成的meme图片路径 50 | """ 51 | try: 52 | # 加载模板图片 53 | template_path = os.path.join(self.templates_dir, template_name) 54 | image = Image.open(template_path) 55 | draw = ImageDraw.Draw(image) 56 | 57 | # 样式配置 58 | style_configs = { 59 | 'classic': { 60 | 'font': 'impact.ttf', 61 | 'size_ratio': 0.1, 62 | 'stroke_width': 2, 63 | 'text_color': 'white', 64 | 'stroke_color': 'black' 65 | }, 66 | 'modern': { 67 | 'font': 'helvetica.ttf', 68 | 'size_ratio': 0.08, 69 | 'stroke_width': 0, 70 | 'text_color': 'white', 71 | 'shadow_offset': 3 72 | }, 73 | 'minimal': { 74 | 'font': 'arial.ttf', 75 | 'size_ratio': 0.07, 76 | 'stroke_width': 1, 77 | 'text_color': 'black', 78 | 'background': True 79 | }, 80 | 'bold': { 81 | 'font': 'futura.ttf', 82 | 'size_ratio': 0.12, 83 | 'stroke_width': 3, 84 | 'text_color': 'yellow', 85 | 'stroke_color': 'red' 86 | } 87 | } 88 | 89 | style_config = style_configs.get(style, style_configs['classic']) 90 | 91 | # 设置字体 92 | font_path = os.path.join(self.fonts_dir, style_config['font']) 93 | font_size = int(image.width * style_config['size_ratio']) 94 | font = ImageFont.truetype(font_path, font_size) 95 | 96 | # 创建绘图对象 97 | draw = ImageDraw.Draw(image) 98 | 99 | # 计算文本位置 100 | text_width = draw.textlength(text, font=font) 101 | x = (image.width - text_width) / 2 102 | y = image.height * 0.1 # 文本位置在顶部10%处 103 | 104 | # 绘制文本边框 105 | outline_size = int(font_size * 0.05) 106 | for adj in range(-outline_size, outline_size + 1): 107 | for opp in range(-outline_size, outline_size + 1): 108 | draw.text((x + adj, y + opp), text, font=font, fill='black') 109 | 110 | # 绘制主文本 111 | draw.text((x, y), text, font=font, fill='white') 112 | 113 | return image 114 | 115 | def generate_trade_meme(self, trade_data): 116 | """生成交易相关的Meme""" 117 | # 分析交易情绪 118 | sentiment, _ = self.analyze_trade_sentiment(trade_data) 119 | 120 | # 生成Meme文本 121 | meme_text = self.generate_meme_text(sentiment, trade_data) 122 | 123 | # 选择合适的模板 124 | template_name = 'bullish.jpg' if sentiment == 'POSITIVE' else 'bearish.jpg' 125 | 126 | # 创建Meme 127 | meme = self.create_meme(meme_text, template_name) 128 | 129 | return meme 130 | 131 | def save_meme(self, meme, output_path): 132 | """保存Meme图片""" 133 | meme.save(output_path, quality=95) 134 | return output_path -------------------------------------------------------------------------------- /src/ai_engine/ml_models.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier 3 | from sklearn.preprocessing import StandardScaler 4 | from sklearn.model_selection import cross_val_score, TimeSeriesSplit 5 | from sklearn.metrics import precision_score, recall_score, f1_score 6 | import joblib 7 | import logging 8 | 9 | class MLPredictor: 10 | def __init__(self): 11 | self.models = { 12 | 'rf': RandomForestClassifier(n_estimators=100, max_depth=10, random_state=42), 13 | 'gb': GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, random_state=42) 14 | } 15 | self.scaler = StandardScaler() 16 | self.logger = logging.getLogger(__name__) 17 | self.selected_model = 'rf' 18 | 19 | def prepare_features(self, technical_indicators): 20 | """Prepare features for ML model""" 21 | try: 22 | # Extract basic features 23 | basic_features = [ 24 | technical_indicators['sma_20'], 25 | technical_indicators['sma_50'], 26 | technical_indicators['rsi'], 27 | technical_indicators['volatility'] 28 | ] 29 | 30 | # Calculate advanced features 31 | sma_ratio = technical_indicators['sma_20'] / technical_indicators['sma_50'] if technical_indicators['sma_50'] else 1.0 32 | rsi_momentum = 1 if technical_indicators['rsi'] > 50 else -1 if technical_indicators['rsi'] < 50 else 0 33 | volatility_factor = np.log1p(technical_indicators['volatility']) if technical_indicators['volatility'] else 0 34 | 35 | # Add MACD features 36 | macd_signal = 1 if technical_indicators['macd'] > technical_indicators['macd_signal'] else -1 37 | macd_trend = np.sign(technical_indicators['macd']) 38 | 39 | # Add volume and price features 40 | volume_trend = np.sign(technical_indicators['obv']) 41 | price_momentum = technical_indicators['close'] / technical_indicators['sma_20'] - 1 42 | 43 | # Combine all features 44 | features = basic_features + [ 45 | sma_ratio, 46 | rsi_momentum, 47 | volatility_factor, 48 | macd_signal, 49 | macd_trend, 50 | volume_trend, 51 | price_momentum 52 | ] 53 | features = np.array(features).reshape(1, -1) 54 | 55 | # Handle missing values 56 | features = np.nan_to_num(features, nan=0.0) 57 | 58 | return self.scaler.transform(features) 59 | except Exception as e: 60 | self.logger.error(f"Error preparing features: {str(e)}") 61 | return None 62 | 63 | def predict(self, features): 64 | """Make price movement prediction with confidence score""" 65 | try: 66 | if features is None: 67 | return None, 0.0 68 | 69 | model = self.models[self.selected_model] 70 | prediction = model.predict(features)[0] 71 | confidence = np.max(model.predict_proba(features)[0]) 72 | 73 | return prediction, confidence 74 | except Exception as e: 75 | self.logger.error(f"Error making prediction: {str(e)}") 76 | return None, 0.0 77 | 78 | def evaluate_model(self, X, y): 79 | """Evaluate model performance using time series cross-validation""" 80 | try: 81 | tscv = TimeSeriesSplit(n_splits=5) 82 | scores = cross_val_score(self.models[self.selected_model], X, y, cv=tscv) 83 | 84 | y_pred = self.models[self.selected_model].predict(X) 85 | precision = precision_score(y, y_pred, average='weighted') 86 | recall = recall_score(y, y_pred, average='weighted') 87 | f1 = f1_score(y, y_pred, average='weighted') 88 | 89 | return { 90 | 'cv_scores': scores, 91 | 'cv_mean': scores.mean(), 92 | 'cv_std': scores.std(), 93 | 'precision': precision, 94 | 'recall': recall, 95 | 'f1_score': f1 96 | } 97 | except Exception as e: 98 | self.logger.error(f"Error evaluating model: {str(e)}") 99 | return None 100 | 101 | def train(self, X, y): 102 | """Train the ML model with cross-validation""" 103 | try: 104 | X_scaled = self.scaler.fit_transform(X) 105 | 106 | # Perform cross-validation 107 | cv_scores = cross_val_score(self.model, X_scaled, y, cv=5) 108 | self.logger.info(f"Cross-validation scores: {cv_scores.mean():.3f} (+/- {cv_scores.std() * 2:.3f})") 109 | 110 | # Train final model 111 | self.model.fit(X_scaled, y) 112 | 113 | # Calculate performance metrics 114 | y_pred = self.model.predict(X_scaled) 115 | precision = precision_score(y, y_pred, average='weighted') 116 | recall = recall_score(y, y_pred, average='weighted') 117 | f1 = f1_score(y, y_pred, average='weighted') 118 | 119 | self.logger.info(f"Model performance - Precision: {precision:.3f}, Recall: {recall:.3f}, F1: {f1:.3f}") 120 | 121 | except Exception as e: 122 | self.logger.error(f"Error training model: {str(e)}") 123 | 124 | def save_model(self, path): 125 | """Save model and scaler to file""" 126 | try: 127 | model_path = f"{path}_model.joblib" 128 | scaler_path = f"{path}_scaler.joblib" 129 | 130 | joblib.dump(self.model, model_path) 131 | joblib.dump(self.scaler, scaler_path) 132 | self.logger.info(f"Model saved to {model_path}") 133 | except Exception as e: 134 | self.logger.error(f"Error saving model: {str(e)}") 135 | 136 | def load_model(self, path): 137 | """Load model and scaler from file""" 138 | try: 139 | model_path = f"{path}_model.joblib" 140 | scaler_path = f"{path}_scaler.joblib" 141 | 142 | self.model = joblib.load(model_path) 143 | self.scaler = joblib.load(scaler_path) 144 | self.logger.info(f"Model loaded from {model_path}") 145 | except Exception as e: 146 | self.logger.error(f"Error loading model: {str(e)}") 147 | 148 | def update_features(self, market_data): 149 | """Update model features with new market data""" 150 | try: 151 | if not market_data or 'close' not in market_data: 152 | return False 153 | 154 | # Extract new features 155 | close_prices = market_data['close'] 156 | returns = np.diff(close_prices) / close_prices[:-1] 157 | 158 | # Calculate labels for training 159 | future_returns = np.roll(returns, -1) 160 | labels = (future_returns > 0).astype(int)[:-1] 161 | 162 | # Prepare features 163 | features = self.prepare_features(market_data) 164 | if features is not None and len(labels) > 0: 165 | # Update model with new data 166 | self.model.partial_fit(features, labels) 167 | return True 168 | 169 | return False 170 | except Exception as e: 171 | self.logger.error(f"Error updating features: {str(e)}") 172 | return False -------------------------------------------------------------------------------- /src/ai_engine/risk_manager.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import logging 3 | from datetime import datetime 4 | 5 | class RiskManager: 6 | def __init__(self, max_position_size=0.1, max_drawdown=0.02, stop_loss=0.01): 7 | self.max_position_size = max_position_size 8 | self.max_drawdown = max_drawdown 9 | self.stop_loss = stop_loss 10 | self.logger = logging.getLogger(__name__) 11 | self.position_history = [] 12 | self.drawdown_history = [] 13 | self.last_update = datetime.now() 14 | self.market_state = 'neutral' 15 | 16 | def calculate_position_size(self, portfolio_value, volatility, risk_score): 17 | """Calculate optimal position size based on dynamic risk assessment""" 18 | try: 19 | # Base position size 20 | base_size = portfolio_value * self.max_position_size 21 | 22 | # Dynamic volatility adjustment 23 | vol_factor = 1 / (1 + np.exp(volatility - 0.5)) # Sigmoid function for smooth scaling 24 | 25 | # Risk score adjustment with exponential decay 26 | risk_factor = np.exp(-2 * (1 - risk_score)) 27 | 28 | # Market condition adjustment 29 | market_factor = self._assess_market_conditions() 30 | 31 | # Time decay factor 32 | time_factor = self._calculate_time_decay() 33 | 34 | # Calculate final position size 35 | position_size = base_size * vol_factor * risk_factor * market_factor * time_factor 36 | 37 | # Apply maximum position constraint 38 | max_allowed = portfolio_value * self.max_position_size 39 | position_size = min(position_size, max_allowed) 40 | 41 | self.position_history.append(position_size / portfolio_value) 42 | return position_size 43 | except Exception as e: 44 | self.logger.error(f"Error calculating position size: {str(e)}") 45 | return 0 46 | 47 | def calculate_stop_loss(self, entry_price, position_type='long', volatility=None): 48 | """Calculate dynamic stop loss based on market volatility and trend""" 49 | try: 50 | # Base stop loss percentage 51 | base_stop = self.stop_loss 52 | 53 | # Adjust for volatility if provided 54 | if volatility is not None: 55 | vol_adjustment = np.clip(volatility / 0.02, 0.5, 2.0) 56 | base_stop *= vol_adjustment 57 | 58 | # Calculate stop loss price 59 | if position_type == 'long': 60 | stop_price = entry_price * (1 - base_stop) 61 | else: 62 | stop_price = entry_price * (1 + base_stop) 63 | 64 | return stop_price 65 | except Exception as e: 66 | self.logger.error(f"Error calculating stop loss: {str(e)}") 67 | return None 68 | 69 | def _assess_market_conditions(self): 70 | """Assess current market conditions for risk adjustment""" 71 | try: 72 | # Analyze position history for trend 73 | if len(self.position_history) > 0: 74 | recent_positions = self.position_history[-10:] 75 | trend = np.mean(np.diff(recent_positions)) 76 | 77 | if trend > 0.01: 78 | self.market_state = 'bullish' 79 | return 1.2 80 | elif trend < -0.01: 81 | self.market_state = 'bearish' 82 | return 0.8 83 | 84 | self.market_state = 'neutral' 85 | return 1.0 86 | except Exception as e: 87 | self.logger.error(f"Error assessing market conditions: {str(e)}") 88 | return 1.0 89 | 90 | def _calculate_time_decay(self): 91 | """Calculate time-based decay factor for risk adjustment""" 92 | try: 93 | time_diff = (datetime.now() - self.last_update).total_seconds() / 3600 94 | decay = np.exp(-0.1 * time_diff) 95 | return max(0.5, decay) 96 | except Exception as e: 97 | self.logger.error(f"Error calculating time decay: {str(e)}") 98 | return 1.0 99 | 100 | def update_drawdown(self, current_value, peak_value): 101 | """Update and monitor drawdown levels""" 102 | try: 103 | drawdown = (peak_value - current_value) / peak_value 104 | self.drawdown_history.append(drawdown) 105 | 106 | # Check if max drawdown exceeded 107 | if drawdown > self.max_drawdown: 108 | return False 109 | 110 | return True 111 | except Exception as e: 112 | self.logger.error(f"Error updating drawdown: {str(e)}") 113 | return True 114 | 115 | def get_risk_metrics(self): 116 | """Get current risk metrics summary""" 117 | return { 118 | 'market_state': self.market_state, 119 | 'current_drawdown': self.drawdown_history[-1] if self.drawdown_history else 0, 120 | 'max_historical_drawdown': max(self.drawdown_history) if self.drawdown_history else 0, 121 | 'position_utilization': np.mean(self.position_history[-10:]) if self.position_history else 0 122 | } 123 | 124 | def _calculate_atr(self, period=14): 125 | """Calculate Average True Range for dynamic stop loss""" 126 | try: 127 | if len(self.position_history) < period: 128 | return self.stop_loss 129 | 130 | # Calculate true range 131 | true_ranges = [] 132 | for i in range(1, len(self.position_history)): 133 | true_range = abs(self.position_history[i] - self.position_history[i-1]) 134 | true_ranges.append(true_range) 135 | 136 | return np.mean(true_ranges[-period:]) 137 | except Exception as e: 138 | self.logger.error(f"Error calculating ATR: {str(e)}") 139 | return self.stop_loss 140 | 141 | def _assess_market_conditions(self): 142 | """Assess current market conditions for position sizing""" 143 | try: 144 | if len(self.position_history) < 10: 145 | return 1.0 146 | 147 | recent_positions = self.position_history[-10:] 148 | trend = np.mean(np.diff(recent_positions)) 149 | volatility = np.std(recent_positions) 150 | 151 | # Update market state 152 | if volatility > np.mean(self.position_history) * 1.5: 153 | self.market_state = 'volatile' 154 | elif abs(trend) > np.std(self.position_history) * 2: 155 | self.market_state = 'trending' 156 | else: 157 | self.market_state = 'neutral' 158 | 159 | # Calculate market factor 160 | if self.market_state == 'volatile': 161 | return 0.7 # Reduce position size in volatile markets 162 | elif self.market_state == 'trending': 163 | return 1.2 if trend > 0 else 0.8 164 | return 1.0 165 | except Exception as e: 166 | self.logger.error(f"Error assessing market conditions: {str(e)}") 167 | return 1.0 168 | 169 | def _calculate_time_decay(self): 170 | """Calculate time decay factor for position sizing""" 171 | try: 172 | time_diff = (datetime.now() - self.last_update).total_seconds() / 3600 173 | decay_factor = np.exp(-0.1 * time_diff) # Exponential decay 174 | self.last_update = datetime.now() 175 | return max(0.5, decay_factor) 176 | except Exception as e: 177 | self.logger.error(f"Error calculating time decay: {str(e)}") 178 | return 1.0 179 | 180 | def validate_trade(self, portfolio_value, position_size, stop_loss_price, entry_price): 181 | """Comprehensive trade validation with multiple risk checks""" 182 | try: 183 | # Check position size limits 184 | if position_size > portfolio_value * self.max_position_size: 185 | return False, "Position size exceeds maximum allowed" 186 | 187 | # Calculate potential loss 188 | potential_loss = abs(entry_price - stop_loss_price) * position_size / entry_price 189 | if potential_loss > portfolio_value * self.max_drawdown: 190 | return False, "Potential loss exceeds maximum drawdown" 191 | 192 | # Check market state 193 | if self.market_state == 'volatile': 194 | if position_size > portfolio_value * self.max_position_size * 0.7: 195 | return False, "Position size too large for volatile market" 196 | 197 | # Check recent performance 198 | if len(self.drawdown_history) > 0: 199 | recent_drawdown = np.mean(self.drawdown_history[-5:]) 200 | if recent_drawdown > self.max_drawdown * 0.8: 201 | return False, "Recent drawdown too high" 202 | 203 | return True, "Trade validated" 204 | except Exception as e: 205 | self.logger.error(f"Error validating trade: {str(e)}") 206 | return False, "Validation error" 207 | 208 | def update_market_state(self, market_data): 209 | """Update market state with new data""" 210 | try: 211 | if not market_data or 'close' not in market_data: 212 | return False 213 | 214 | # Calculate returns 215 | close_prices = market_data['close'] 216 | if len(close_prices) < 2: 217 | return False 218 | 219 | returns = np.diff(close_prices) / close_prices[:-1] 220 | 221 | # Update drawdown history 222 | if len(returns) > 0: 223 | drawdown = min(0, returns[-1]) 224 | self.drawdown_history.append(drawdown) 225 | 226 | # Keep history length manageable 227 | if len(self.drawdown_history) > 100: 228 | self.drawdown_history = self.drawdown_history[-100:] 229 | 230 | return True 231 | except Exception as e: 232 | self.logger.error(f"Error updating market state: {str(e)}") 233 | return False 234 | 235 | def _check_cumulative_risk(self, potential_loss, portfolio_value, lookback=5): 236 | """Check if recent cumulative risk is too high""" 237 | try: 238 | if len(self.drawdown_history) < lookback: 239 | return False 240 | 241 | recent_drawdowns = self.drawdown_history[-lookback:] 242 | cumulative_risk = sum(recent_drawdowns) + (potential_loss / portfolio_value) 243 | 244 | return cumulative_risk > self.max_drawdown * 2 245 | except Exception as e: 246 | self.logger.error(f"Error checking cumulative risk: {str(e)}") 247 | return True # Conservative approach: reject trade if error -------------------------------------------------------------------------------- /src/ai_engine/signal_generator.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from typing import Dict, Optional 4 | import talib 5 | import logging 6 | from .ml_models import MLPredictor 7 | 8 | class SignalGenerator: 9 | def __init__(self): 10 | self.ml_predictor = MLPredictor() 11 | self.logger = logging.getLogger(__name__) 12 | 13 | def calculate_technical_indicators(self, ohlcv_data: pd.DataFrame) -> Dict: 14 | """计算技术指标""" 15 | try: 16 | close = ohlcv_data['close'].values 17 | high = ohlcv_data['high'].values 18 | low = ohlcv_data['low'].values 19 | volume = ohlcv_data['volume'].values 20 | 21 | # 计算移动平均 22 | sma_20 = talib.SMA(close, timeperiod=20)[-1] 23 | sma_50 = talib.SMA(close, timeperiod=50)[-1] 24 | ema_12 = talib.EMA(close, timeperiod=12)[-1] 25 | 26 | # 计算动量指标 27 | rsi = talib.RSI(close, timeperiod=14)[-1] 28 | macd, macd_signal, _ = talib.MACD(close) 29 | macd_value = macd[-1] 30 | macd_signal = macd_signal[-1] 31 | 32 | # 计算波动率 33 | atr = talib.ATR(high, low, close, timeperiod=14)[-1] 34 | volatility = talib.STDDEV(close, timeperiod=20)[-1] 35 | 36 | # 计算成交量指标 37 | obv = talib.OBV(close, volume)[-1] 38 | 39 | return { 40 | 'sma_20': sma_20, 41 | 'sma_50': sma_50, 42 | 'ema_12': ema_12, 43 | 'rsi': rsi, 44 | 'macd': macd_value, 45 | 'macd_signal': macd_signal, 46 | 'atr': atr, 47 | 'volatility': volatility, 48 | 'obv': obv 49 | } 50 | except Exception as e: 51 | self.logger.error(f"Error calculating technical indicators: {str(e)}") 52 | return None 53 | 54 | def generate_signal(self, market_data: Dict, portfolio_value: float) -> Optional[Dict]: 55 | """生成交易信号""" 56 | try: 57 | if market_data is None or 'ohlcv' not in market_data: 58 | return None 59 | 60 | # 计算技术指标 61 | indicators = self.calculate_technical_indicators(market_data['ohlcv']) 62 | if not indicators: 63 | return None 64 | 65 | # 准备ML模型特征 66 | features = self.ml_predictor.prepare_features(indicators) 67 | 68 | # 获取ML模型预测 69 | signal, confidence = self.ml_predictor.predict(features) 70 | 71 | # 计算技术分析信号 72 | ta_signal = self._calculate_ta_signal(indicators) 73 | 74 | # 综合信号 75 | final_signal = self._combine_signals(signal, ta_signal, confidence) 76 | 77 | return { 78 | 'signal': final_signal, 79 | 'confidence': confidence, 80 | 'indicators': indicators, 81 | 'ml_signal': signal, 82 | 'ta_signal': ta_signal, 83 | 'timestamp': market_data['timestamp'] 84 | } 85 | except Exception as e: 86 | self.logger.error(f"Error generating signal: {str(e)}") 87 | return None 88 | 89 | def _calculate_ta_signal(self, indicators: Dict) -> int: 90 | """计算技术分析信号""" 91 | signals = [] 92 | 93 | # 移动平均趋势 94 | if indicators['sma_20'] > indicators['sma_50']: 95 | signals.append(1) 96 | elif indicators['sma_20'] < indicators['sma_50']: 97 | signals.append(-1) 98 | else: 99 | signals.append(0) 100 | 101 | # RSI信号 102 | if indicators['rsi'] > 70: 103 | signals.append(-1) # 超买 104 | elif indicators['rsi'] < 30: 105 | signals.append(1) # 超卖 106 | else: 107 | signals.append(0) 108 | 109 | # MACD信号 110 | if indicators['macd'] > indicators['macd_signal']: 111 | signals.append(1) 112 | elif indicators['macd'] < indicators['macd_signal']: 113 | signals.append(-1) 114 | else: 115 | signals.append(0) 116 | 117 | # 返回综合信号 118 | return int(np.sign(sum(signals))) 119 | 120 | def _combine_signals(self, ml_signal: int, ta_signal: int, confidence: float) -> int: 121 | """综合ML和技术分析信号""" 122 | # 如果ML置信度高,赋予更大权重 123 | if confidence > 0.8: 124 | return ml_signal 125 | elif confidence > 0.6: 126 | # ML和技术分析信号一致时保持,不一致时偏向ML信号 127 | return ml_signal if ml_signal == ta_signal else int(np.sign(0.7 * ml_signal + 0.3 * ta_signal)) 128 | else: 129 | # ML置信度低时偏向技术分析信号 130 | return ta_signal -------------------------------------------------------------------------------- /src/ai_engine/trading_engine.py: -------------------------------------------------------------------------------- 1 | import ccxt 2 | import numpy as np 3 | from datetime import datetime 4 | import logging 5 | from .ml_models import MLPredictor 6 | from .risk_manager import RiskManager 7 | from .market_data import MarketDataCollector 8 | 9 | class TradingEngine: 10 | def __init__(self, api_key=None, api_secret=None): 11 | # Initialize market data collector 12 | self.market_data = MarketDataCollector(api_key=api_key, api_secret=api_secret) 13 | 14 | # Initialize ML predictor and risk manager 15 | self.ml_predictor = MLPredictor() 16 | self.risk_manager = RiskManager() 17 | 18 | # Configure logging 19 | logging.basicConfig(level=logging.INFO) 20 | self.logger = logging.getLogger(__name__) 21 | 22 | # Trading state 23 | self.active_positions = {} 24 | self.pending_orders = {} 25 | 26 | def fetch_market_data(self, symbol, timeframe='1m', limit=100): 27 | """Fetch comprehensive market data""" 28 | try: 29 | # Fetch OHLCV data 30 | ohlcv_data = self.market_data.fetch_historical_data(symbol, timeframe, limit) 31 | if ohlcv_data is None: 32 | return None 33 | 34 | # Fetch orderbook 35 | orderbook = self.market_data.fetch_orderbook(symbol) 36 | 37 | # Fetch recent trades 38 | trades = self.market_data.fetch_recent_trades(symbol) 39 | 40 | # Calculate VWAP 41 | vwap = self.market_data.calculate_vwap(trades) 42 | 43 | return { 44 | 'ohlcv': ohlcv_data, 45 | 'orderbook': orderbook, 46 | 'vwap': vwap, 47 | 'timestamp': datetime.now().timestamp() 48 | } 49 | except Exception as e: 50 | self.logger.error(f"Error fetching market data: {str(e)}") 51 | return None 52 | 53 | def generate_trading_signal(self, market_data, portfolio_value): 54 | """Generate comprehensive trading signal""" 55 | try: 56 | if market_data is None: 57 | return None 58 | 59 | # Calculate technical indicators 60 | indicators = self.calculate_technical_indicators(market_data['ohlcv']) 61 | if not indicators: 62 | return None 63 | 64 | # Add market microstructure features 65 | if market_data['orderbook']: 66 | trade_size = portfolio_value * 0.01 # 1% of portfolio for impact calculation 67 | impact = self.market_data.calculate_market_impact(market_data['orderbook'], trade_size) 68 | indicators.update({ 69 | 'buy_impact': impact['buy_impact'] if impact else None, 70 | 'sell_impact': impact['sell_impact'] if impact else None, 71 | 'vwap': market_data['vwap'] 72 | }) 73 | 74 | # Prepare features for ML model 75 | features = self.ml_predictor.prepare_features(indicators) 76 | 77 | # Get prediction and confidence 78 | signal, confidence = self.ml_predictor.predict(features) 79 | 80 | # Calculate position size based on risk management 81 | position_size = self.risk_manager.calculate_position_size( 82 | portfolio_value, 83 | indicators['volatility'], 84 | confidence 85 | ) 86 | 87 | # Calculate stop loss and take profit levels 88 | current_price = market_data['ohlcv']['close'].iloc[-1] 89 | stop_loss = self.risk_manager.calculate_stop_loss( 90 | current_price, 91 | 'long' if signal > 0 else 'short' 92 | ) 93 | 94 | return { 95 | 'signal': signal, # 1 for long, -1 for short, 0 for neutral 96 | 'confidence': confidence, 97 | 'position_size': position_size, 98 | 'stop_loss': stop_loss, 99 | 'indicators': indicators, 100 | 'timestamp': market_data['timestamp'] 101 | } 102 | except Exception as e: 103 | self.logger.error(f"Error generating trading signal: {str(e)}") 104 | return None 105 | 106 | def execute_trade(self, symbol, signal): 107 | """Execute trade based on signal""" 108 | try: 109 | if not signal or signal['signal'] == 0: 110 | return False 111 | 112 | # Validate trade with risk manager 113 | trade_valid, reason = self.risk_manager.validate_trade( 114 | portfolio_value=self.get_portfolio_value(), 115 | position_size=signal['position_size'], 116 | stop_loss_price=signal['stop_loss'], 117 | entry_price=signal['indicators']['close'][-1] 118 | ) 119 | 120 | if not trade_valid: 121 | self.logger.warning(f"Trade validation failed: {reason}") 122 | return False 123 | 124 | # Place order logic here 125 | order_type = 'market' 126 | side = 'buy' if signal['signal'] > 0 else 'sell' 127 | 128 | self.logger.info(f"Executing {side} order for {symbol} with size {signal['position_size']}") 129 | 130 | # Update position tracking 131 | self.active_positions[symbol] = { 132 | 'side': side, 133 | 'size': signal['position_size'], 134 | 'entry_price': signal['indicators']['close'][-1], 135 | 'stop_loss': signal['stop_loss'], 136 | 'timestamp': signal['timestamp'] 137 | } 138 | 139 | return True 140 | except Exception as e: 141 | self.logger.error(f"Error executing trade: {str(e)}") 142 | return False 143 | 144 | def get_portfolio_value(self): 145 | """Get current portfolio value""" 146 | # Implement portfolio value calculation 147 | return 10000 # Placeholder value 148 | 149 | def calculate_technical_indicators(self, market_data): 150 | """Calculate technical indicators for trading decisions""" 151 | if not market_data: 152 | return None 153 | 154 | close_prices = market_data['close'] 155 | high_prices = market_data['high'] 156 | low_prices = market_data['low'] 157 | 158 | # Calculate SMA 159 | sma_20 = np.mean(close_prices[-20:]) if len(close_prices) >= 20 else None 160 | sma_50 = np.mean(close_prices[-50:]) if len(close_prices) >= 50 else None 161 | 162 | # Calculate RSI 163 | delta = np.diff(close_prices) 164 | gain = (delta > 0) * delta 165 | loss = (delta < 0) * -delta 166 | avg_gain = np.mean(gain[-14:]) if len(gain) >= 14 else None 167 | avg_loss = np.mean(loss[-14:]) if len(loss) >= 14 else None 168 | 169 | if avg_gain is not None and avg_loss is not None and avg_loss != 0: 170 | rs = avg_gain / avg_loss 171 | rsi = 100 - (100 / (1 + rs)) 172 | else: 173 | rsi = None 174 | 175 | # Calculate volatility 176 | volatility = np.std(np.diff(np.log(close_prices[-20:]))) if len(close_prices) >= 20 else None 177 | 178 | return { 179 | 'sma_20': sma_20, 180 | 'sma_50': sma_50, 181 | 'rsi': rsi, 182 | 'volatility': volatility 183 | } 184 | 185 | def generate_trading_signal(self, market_data): 186 | """Generate trading signal based on market data and ML predictions""" 187 | try: 188 | # Calculate technical indicators 189 | indicators = self.calculate_technical_indicators(market_data) 190 | if not indicators: 191 | return None 192 | 193 | # Prepare features for ML model 194 | features = self.ml_predictor.prepare_features(indicators) 195 | 196 | # Get prediction and confidence 197 | signal, confidence = self.ml_predictor.predict(features) 198 | 199 | # Calculate position size based on risk management 200 | position_size = self.risk_manager.calculate_position_size( 201 | portfolio_value=100000, # Default portfolio value 202 | volatility=indicators['volatility'], 203 | risk_score=confidence 204 | ) 205 | 206 | # Generate final trading signal 207 | if signal != 0 and position_size > 0: 208 | stop_loss = self.risk_manager.calculate_stop_loss( 209 | entry_price=market_data['close'][-1], 210 | position_type='long' if signal > 0 else 'short' 211 | ) 212 | 213 | return { 214 | 'symbol': market_data.get('symbol'), 215 | 'signal': signal, # 1 for long, -1 for short, 0 for neutral 216 | 'confidence': confidence, 217 | 'position_size': position_size, 218 | 'stop_loss': stop_loss, 219 | 'indicators': indicators, 220 | 'timestamp': datetime.now().timestamp() 221 | } 222 | 223 | return None 224 | except Exception as e: 225 | self.logger.error(f"Error generating trading signal: {str(e)}") 226 | return None 227 | 228 | def validate_signal(self, signal_data): 229 | """Validate trading signal with risk management rules""" 230 | if not signal_data: 231 | return False 232 | 233 | try: 234 | # Validate trade with risk manager 235 | is_valid, reason = self.risk_manager.validate_trade( 236 | portfolio_value=100000, # Default portfolio value 237 | position_size=signal_data['position_size'], 238 | stop_loss_price=signal_data['stop_loss'], 239 | entry_price=signal_data['indicators']['close'][-1] 240 | ) 241 | 242 | if not is_valid: 243 | self.logger.warning(f"Trade validation failed: {reason}") 244 | return False 245 | 246 | return True 247 | except Exception as e: 248 | self.logger.error(f"Error validating signal: {str(e)}") 249 | return False 250 | 251 | def update_market_state(self, market_data): 252 | """Update internal market state with new data""" 253 | try: 254 | # Update risk manager with new market data 255 | self.risk_manager.update_market_state(market_data) 256 | 257 | # Update ML model features 258 | self.ml_predictor.update_features(market_data) 259 | 260 | return True 261 | except Exception as e: 262 | self.logger.error(f"Error updating market state: {str(e)}") 263 | return False 264 | 265 | return { 266 | 'sma_20': sma_20, 267 | 'sma_50': sma_50, 268 | 'rsi': rsi 269 | } 270 | return None 271 | 272 | def generate_trading_signal(self, market_data): 273 | """Generate trading signals based on market data and technical analysis 274 | 275 | Args: 276 | market_data (dict): Processed market data 277 | 278 | Returns: 279 | dict: Trading signal with direction and confidence 280 | """ 281 | if not market_data: 282 | return None 283 | 284 | # Calculate technical indicators 285 | indicators = self.calculate_technical_indicators(market_data) 286 | if not indicators: 287 | return None 288 | 289 | # Get ML prediction 290 | features = self.ml_predictor.prepare_features(indicators) 291 | prediction = self.ml_predictor.predict(features) 292 | 293 | # Calculate volatility 294 | close_prices = market_data['close'] 295 | returns = np.diff(close_prices) / close_prices[:-1] 296 | volatility = np.std(returns) 297 | 298 | # Generate signal 299 | signal = { 300 | 'timestamp': datetime.now().timestamp(), 301 | 'symbol': market_data.get('symbol'), 302 | 'direction': 'buy' if prediction == 1 else 'sell' if prediction == -1 else None, 303 | 'confidence': abs(prediction), 304 | 'volatility': volatility, 305 | 'indicators': indicators 306 | } 307 | 308 | # Validate signal with risk management 309 | if signal['direction']: 310 | portfolio_value = self.get_portfolio_value() 311 | position_size = self.risk_manager.calculate_position_size( 312 | portfolio_value, 313 | volatility, 314 | signal['confidence'] 315 | ) 316 | 317 | current_price = close_prices[-1] 318 | stop_loss = self.risk_manager.calculate_stop_loss( 319 | current_price, 320 | 'long' if signal['direction'] == 'buy' else 'short' 321 | ) 322 | 323 | is_valid, reason = self.risk_manager.validate_trade( 324 | portfolio_value, 325 | position_size, 326 | stop_loss, 327 | current_price 328 | ) 329 | 330 | if not is_valid: 331 | self.logger.warning(f"Trade validation failed: {reason}") 332 | return None 333 | 334 | signal['position_size'] = position_size 335 | signal['stop_loss'] = stop_loss 336 | 337 | return signal if signal['direction'] else None 338 | 339 | def get_portfolio_value(self): 340 | """Get current portfolio value 341 | 342 | Returns: 343 | float: Total portfolio value in USDT 344 | """ 345 | try: 346 | balance = self.exchange.fetch_balance() 347 | return float(balance['total']['USDT']) 348 | except Exception as e: 349 | self.logger.error(f"Error fetching portfolio value: {str(e)}") 350 | return 0.0 351 | # Trading logic based on multiple indicators 352 | close_prices = market_data['close'] 353 | current_price = close_prices[-1] 354 | 355 | # Trend following strategy 356 | trend_signal = 'long' if indicators['sma_20'] > indicators['sma_50'] else 'short' 357 | 358 | # RSI strategy 359 | rsi_signal = None 360 | if indicators['rsi'] is not None: 361 | if indicators['rsi'] < 30: 362 | rsi_signal = 'long' # Oversold 363 | elif indicators['rsi'] > 70: 364 | rsi_signal = 'short' # Overbought 365 | 366 | # Combine signals 367 | final_direction = trend_signal 368 | if rsi_signal and rsi_signal != trend_signal: 369 | # If RSI contradicts trend, reduce confidence 370 | confidence = 0.5 371 | else: 372 | confidence = 0.8 373 | 374 | signal = { 375 | 'timestamp': datetime.now().timestamp(), 376 | 'direction': final_direction, 377 | 'confidence': confidence, 378 | 'price': current_price, 379 | 'indicators': indicators 380 | } 381 | 382 | self.logger.info(f"Generated trading signal: {signal}") 383 | return signal -------------------------------------------------------------------------------- /src/ai_engine/voice_generator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import logging 4 | from transformers import pipeline 5 | from TTS.api import TTS 6 | 7 | class VoiceGenerator: 8 | def __init__(self, config): 9 | self.config = config 10 | self.text_generator = pipeline('text-generation') 11 | self.tts = TTS(config.voice.tts.model, gpu=torch.cuda.is_available()) 12 | self.languages = { 13 | 'en': 'English', 14 | 'zh': 'Chinese', 15 | 'ja': 'Japanese', 16 | 'ko': 'Korean', 17 | 'ru': 'Russian' 18 | } 19 | 20 | # 设置日志记录 21 | logging.basicConfig(level=logging.INFO) 22 | self.logger = logging.getLogger(__name__) 23 | 24 | def generate_confession_text(self, trade_data, language='en'): 25 | """根据交易数据生成认罪文本""" 26 | templates = { 27 | 'en': [ 28 | "I confess that I FOMOed into {symbol} at {price}. I should have done more research. 😔", 29 | "I admit that I leveraged too much on {symbol} and lost {loss}. I was too greedy. 😭", 30 | "I acknowledge my mistake of not setting stop losses on {symbol}. It was pure gambling. 🎰", 31 | "I got rekt on {symbol} because I followed some random influencer. Never again! 🤦", 32 | "My portfolio is down {loss} because I aped into {symbol}. I'm such a degen. 🦍" 33 | ], 34 | 'zh': [ 35 | "我承认我在{price}的价格追高了{symbol}。我应该做更多研究的。😔", 36 | "我承认我在{symbol}上使用了过高的杠杆,亏损了{loss}。我太贪心了。😭", 37 | "我承认我没有在{symbol}上设置止损。这完全是在赌博。🎰", 38 | "我因为跟随某个网红买入{symbol}结果被割了。以后再也不会这样了!🤦", 39 | "我的投资组合因为冲动买入{symbol}已经亏损{loss}了。我就是个韭菜。🦍" 40 | ], 41 | 'ja': [ 42 | "{symbol}を{price}で追いかけ買いしてしまいました。もっと調査すべきでした。😔", 43 | "{symbol}で過度なレバレッジを使い、{loss}を失いました。欲が深すぎました。😭", 44 | "{symbol}でストップロスを設定しませんでした。ただの賭け事でした。🎰", 45 | "インフルエンサーに従って{symbol}を買って失敗しました。もう二度としません!🤦", 46 | "{symbol}に飛び込んで{loss}損失しました。私は本当にバカでした。🦍" 47 | ] 48 | } 49 | 50 | template = torch.randint(0, len(templates[language]), (1,)).item() 51 | text = templates[language][template].format( 52 | symbol=trade_data['symbol'], 53 | price=trade_data.get('price', '0'), 54 | loss=trade_data.get('loss', '0') 55 | ) 56 | return text 57 | 58 | def generate_voice(self, text, language='en', speaker_name="default", output_path=None, emotion="neutral"): 59 | """生成语音文件 60 | Args: 61 | text: 要转换的文本 62 | language: 语言代码 ('en', 'zh', 'ja', 'ko', 'ru') 63 | speaker_name: 说话人名称 64 | output_path: 输出文件路径 65 | emotion: 情感类型 ('neutral', 'sad', 'happy', 'angry', 'excited', 'depressed') 66 | Returns: 67 | 生成的语音文件路径 68 | """ 69 | try: 70 | # 根据情感调整语音参数 71 | emotion_params = { 72 | 'neutral': {'speed': 1.0, 'pitch': 1.0, 'energy': 1.0}, 73 | 'sad': {'speed': 0.8, 'pitch': 0.8, 'energy': 0.7}, 74 | 'happy': {'speed': 1.2, 'pitch': 1.2, 'energy': 1.3}, 75 | 'angry': {'speed': 1.3, 'pitch': 1.4, 'energy': 1.5}, 76 | 'excited': {'speed': 1.4, 'pitch': 1.3, 'energy': 1.6}, 77 | 'depressed': {'speed': 0.7, 'pitch': 0.7, 'energy': 0.5} 78 | } 79 | 80 | params = emotion_params.get(emotion, emotion_params['neutral']) 81 | 82 | # 如果没有指定输出路径,使用临时文件 83 | if not output_path: 84 | output_path = os.path.join( 85 | os.path.dirname(__file__), 86 | 'generated_voices', 87 | f'confession_{language}_{emotion}_{speaker_name}_{hash(text)}.wav' 88 | ) 89 | 90 | os.makedirs(os.path.dirname(output_path), exist_ok=True) 91 | 92 | # 生成语音 93 | self.tts.tts_to_file( 94 | text=text, 95 | file_path=output_path, 96 | speaker_name=speaker_name, 97 | language=self.languages[language], 98 | speed=params['speed'], 99 | pitch=params['pitch'], 100 | energy=params['energy'] 101 | ) 102 | 103 | self.logger.info(f"Successfully generated voice file: {output_path}") 104 | return output_path 105 | 106 | except Exception as e: 107 | self.logger.error(f"Error generating voice: {str(e)}") 108 | raise e 109 | 110 | def generate_trade_confession(self, trade_data, language='en', speaker_name="default", emotion="sad"): 111 | """生成交易认罪语音""" 112 | # 生成认罪文本 113 | confession_text = self.generate_confession_text(trade_data, language) 114 | 115 | # 生成语音文件 116 | voice_path = self.generate_voice( 117 | confession_text, 118 | language, 119 | speaker_name, 120 | emotion=emotion 121 | ) 122 | 123 | return { 124 | 'text': confession_text, 125 | 'voice_path': voice_path, 126 | 'language': language, 127 | 'emotion': emotion 128 | } -------------------------------------------------------------------------------- /src/config/ai_social_config.js: -------------------------------------------------------------------------------- 1 | const aiSocialConfig = { 2 | // 语音生成配置 3 | voice: { 4 | // TTS模型配置 5 | tts: { 6 | model: "tts_models/multilingual/multi-dataset/your_tts", 7 | defaultSpeaker: "default", 8 | outputDir: "generated_voices" 9 | }, 10 | // 语音模板配置 11 | templates: { 12 | confession: { 13 | en: [ 14 | "I confess that I FOMOed into {symbol} at {price}. I should have done more research.", 15 | "I admit that I leveraged too much on {symbol} and lost {loss}. I was too greedy.", 16 | "I acknowledge my mistake of not setting stop losses on {symbol}. It was pure gambling." 17 | ], 18 | zh: [ 19 | "我承认我在{price}的价格追高了{symbol}。我应该做更多研究的。", 20 | "我承认我在{symbol}上使用了过高的杠杆,亏损了{loss}。我太贪心了。", 21 | "我承认我没有在{symbol}上设置止损。这完全是在赌博。" 22 | ], 23 | ja: [ 24 | "{symbol}を{price}で追いかけ買いしてしまいました。もっと調査すべきでした。", 25 | "{symbol}で過度なレバレッジを使い、{loss}を失いました。欲が深すぎました。", 26 | "{symbol}でストップロスを設定しませんでした。ただの賭け事でした。" 27 | ] 28 | } 29 | } 30 | }, 31 | 32 | // 社交媒体配置 33 | social: { 34 | // 发布平台配置 35 | platforms: { 36 | twitter: { 37 | enabled: true, 38 | apiVersion: "2.0", 39 | rateLimit: 300, // 5分钟内的请求限制 40 | mediaSupport: true 41 | }, 42 | telegram: { 43 | enabled: true, 44 | mediaSupport: true, 45 | maxMessageLength: 4096 46 | }, 47 | discord: { 48 | enabled: true, 49 | mediaSupport: true, 50 | maxFileSize: 8388608 // 8MB 51 | } 52 | }, 53 | 54 | // 内容发布策略 55 | postingStrategy: { 56 | retryAttempts: 3, 57 | retryDelay: 1000, // 毫秒 58 | priorityOrder: ["twitter", "telegram", "discord"], 59 | batchSize: 5 // 批量发布数量 60 | }, 61 | 62 | // 内容模板 63 | templates: { 64 | tradeAlert: "🚨 Trade Alert! {symbol}\nPrice: {price}\nPosition: {position}\nLeverage: {leverage}x", 65 | confession: "😅 Trading Confession\n{text}\n#tradingconfession #{symbol}", 66 | meme: "🎭 {symbol} Trading Meme\n{caption}\n#tradingmeme #{symbol}" 67 | } 68 | } 69 | }; 70 | 71 | module.exports = aiSocialConfig; -------------------------------------------------------------------------------- /src/contracts/abi.js: -------------------------------------------------------------------------------- 1 | const FollowTradeABI = [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "_followFee", 7 | "type": "uint256" 8 | }, 9 | { 10 | "internalType": "uint256", 11 | "name": "_burnRate", 12 | "type": "uint256" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "anonymous": false, 20 | "inputs": [ 21 | { 22 | "indexed": false, 23 | "internalType": "address", 24 | "name": "follower", 25 | "type": "address" 26 | }, 27 | { 28 | "indexed": false, 29 | "internalType": "string", 30 | "name": "symbol", 31 | "type": "string" 32 | }, 33 | { 34 | "indexed": false, 35 | "internalType": "uint256", 36 | "name": "fee", 37 | "type": "uint256" 38 | } 39 | ], 40 | "name": "FollowTradeStarted", 41 | "type": "event" 42 | }, 43 | { 44 | "anonymous": false, 45 | "inputs": [ 46 | { 47 | "indexed": false, 48 | "internalType": "address", 49 | "name": "trader", 50 | "type": "address" 51 | }, 52 | { 53 | "indexed": false, 54 | "internalType": "address", 55 | "name": "follower", 56 | "type": "address" 57 | }, 58 | { 59 | "indexed": false, 60 | "internalType": "uint256", 61 | "name": "amount", 62 | "type": "uint256" 63 | } 64 | ], 65 | "name": "ProfitDistributed", 66 | "type": "event" 67 | }, 68 | { 69 | "anonymous": false, 70 | "inputs": [ 71 | { 72 | "indexed": false, 73 | "internalType": "uint256", 74 | "name": "amount", 75 | "type": "uint256" 76 | } 77 | ], 78 | "name": "TokensBurned", 79 | "type": "event" 80 | }, 81 | { 82 | "anonymous": false, 83 | "inputs": [ 84 | { 85 | "indexed": false, 86 | "internalType": "address", 87 | "name": "user", 88 | "type": "address" 89 | }, 90 | { 91 | "indexed": false, 92 | "internalType": "uint256", 93 | "name": "amount", 94 | "type": "uint256" 95 | } 96 | ], 97 | "name": "RewardsWithdrawn", 98 | "type": "event" 99 | }, 100 | { 101 | "inputs": [ 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "string", 109 | "name": "", 110 | "type": "string" 111 | } 112 | ], 113 | "name": "activeFollows", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "view", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [ 126 | { 127 | "internalType": "address[]", 128 | "name": "followers", 129 | "type": "address[]" 130 | }, 131 | { 132 | "internalType": "uint256[]", 133 | "name": "amounts", 134 | "type": "uint256[]" 135 | } 136 | ], 137 | "name": "distributeProfits", 138 | "outputs": [], 139 | "stateMutability": "nonpayable", 140 | "type": "function" 141 | }, 142 | { 143 | "inputs": [ 144 | { 145 | "internalType": "string", 146 | "name": "symbol", 147 | "type": "string" 148 | } 149 | ], 150 | "name": "startFollow", 151 | "outputs": [], 152 | "stateMutability": "payable", 153 | "type": "function" 154 | }, 155 | { 156 | "inputs": [ 157 | { 158 | "internalType": "uint256", 159 | "name": "_newRate", 160 | "type": "uint256" 161 | } 162 | ], 163 | "name": "updateBurnRate", 164 | "outputs": [], 165 | "stateMutability": "nonpayable", 166 | "type": "function" 167 | }, 168 | { 169 | "inputs": [ 170 | { 171 | "internalType": "uint256", 172 | "name": "_newFee", 173 | "type": "uint256" 174 | } 175 | ], 176 | "name": "updateFollowFee", 177 | "outputs": [], 178 | "stateMutability": "nonpayable", 179 | "type": "function" 180 | }, 181 | { 182 | "inputs": [], 183 | "name": "withdraw", 184 | "outputs": [], 185 | "stateMutability": "nonpayable", 186 | "type": "function" 187 | }, 188 | { 189 | "inputs": [], 190 | "name": "withdrawRewards", 191 | "outputs": [], 192 | "stateMutability": "nonpayable", 193 | "type": "function" 194 | } 195 | ]; 196 | 197 | module.exports = { FollowTradeABI }; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const http = require('http').createServer(app); 4 | const io = require('socket.io')(http); 5 | const dotenv = require('dotenv'); 6 | const TradingService = require('./services/trading_service'); 7 | 8 | dotenv.config(); 9 | 10 | // Initialize trading service 11 | const tradingService = new TradingService( 12 | process.env.SOLANA_ENDPOINT || 'https://api.devnet.solana.com', 13 | process.env.PROGRAM_ID 14 | ); 15 | 16 | // Middleware configuration 17 | app.use(express.json()); 18 | 19 | // Start trading stream 20 | tradingService.startTradingStream(); 21 | 22 | // WebSocket connection handling 23 | io.on('connection', (socket) => { 24 | console.log('User connected'); 25 | 26 | socket.on('disconnect', () => { 27 | console.log('User disconnected'); 28 | }); 29 | }); 30 | 31 | // API routes 32 | app.get('/api/health', (req, res) => { 33 | res.json({ status: 'ok' }); 34 | }); 35 | 36 | // Start server 37 | const PORT = process.env.PORT || 3000; 38 | http.listen(PORT, () => { 39 | console.log(`Server running on port ${PORT}`); 40 | }); -------------------------------------------------------------------------------- /src/services/follow_trade_service.js: -------------------------------------------------------------------------------- 1 | const { Connection, PublicKey, Transaction, SystemProgram } = require('@solana/web3.js'); 2 | const BN = require('bn.js'); 3 | const { Program } = require('@project-serum/anchor'); 4 | const WebSocket = require('ws'); 5 | 6 | class FollowTradeService { 7 | constructor(endpoint, programId) { 8 | this.connection = new Connection(endpoint); 9 | this.programId = new PublicKey(programId); 10 | 11 | // Initialize WebSocket server for real-time updates 12 | this.wss = new WebSocket.Server({ port: 8081 }); 13 | this.followers = new Map(); 14 | 15 | this.setupWebSocket(); 16 | } 17 | 18 | setupWebSocket() { 19 | this.wss.on('connection', (ws) => { 20 | ws.on('message', async (message) => { 21 | try { 22 | const data = JSON.parse(message); 23 | 24 | switch (data.type) { 25 | case 'follow_request': 26 | await this.handleFollowRequest(ws, data); 27 | break; 28 | case 'unfollow_request': 29 | await this.handleUnfollowRequest(ws, data); 30 | break; 31 | } 32 | } catch (error) { 33 | console.error('Error processing WebSocket message:', error); 34 | ws.send(JSON.stringify({ 35 | type: 'error', 36 | message: error.message 37 | })); 38 | } 39 | }); 40 | 41 | ws.on('close', () => { 42 | this.removeFollower(ws); 43 | }); 44 | }); 45 | } 46 | 47 | async handleFollowRequest(ws, data) { 48 | const { trader, symbol, publicKey } = data; 49 | 50 | try { 51 | // Create follow instruction 52 | const instruction = await this.program.instruction.startFollow( 53 | symbol, 54 | { 55 | accounts: { 56 | follower: new PublicKey(publicKey), 57 | trader: new PublicKey(trader), 58 | systemProgram: SystemProgram.programId, 59 | }, 60 | } 61 | ); 62 | 63 | // Add to followers list 64 | this.followers.set(ws, { 65 | publicKey, 66 | trader, 67 | symbol 68 | }); 69 | 70 | // Send confirmation 71 | ws.send(JSON.stringify({ 72 | type: 'follow_success', 73 | trader, 74 | symbol 75 | })); 76 | } catch (error) { 77 | ws.send(JSON.stringify({ 78 | type: 'error', 79 | message: 'Failed to start following: ' + error.message 80 | })); 81 | } 82 | } 83 | 84 | async handleUnfollowRequest(ws, data) { 85 | const follower = this.followers.get(ws); 86 | if (!follower) { 87 | return; 88 | } 89 | 90 | try { 91 | // Remove from followers list 92 | this.followers.delete(ws); 93 | 94 | // Send confirmation 95 | ws.send(JSON.stringify({ 96 | type: 'unfollow_success', 97 | trader: follower.trader, 98 | symbol: follower.symbol 99 | })); 100 | } catch (error) { 101 | ws.send(JSON.stringify({ 102 | type: 'error', 103 | message: 'Failed to unfollow: ' + error.message 104 | })); 105 | } 106 | } 107 | 108 | removeFollower(ws) { 109 | this.followers.delete(ws); 110 | } 111 | 112 | broadcastTradeSignal(trader, symbol, signal) { 113 | this.followers.forEach((follower, ws) => { 114 | if (follower.trader === trader && 115 | follower.symbol === symbol && 116 | ws.readyState === WebSocket.OPEN) { 117 | ws.send(JSON.stringify({ 118 | type: 'trade_signal', 119 | trader, 120 | symbol, 121 | signal 122 | })); 123 | } 124 | }); 125 | } 126 | 127 | async distributeProfits(trader, symbol, profits) { 128 | const followers = Array.from(this.followers.values()) 129 | .filter(f => f.trader === trader && f.symbol === symbol); 130 | 131 | if (followers.length === 0) { 132 | return; 133 | } 134 | 135 | try { 136 | // Calculate profit shares 137 | const traderShare = (profits * 70) / 100; // 70% to trader 138 | const followerShare = (profits * 30) / followers.length; // 30% split among followers 139 | 140 | // Create profit distribution instruction 141 | const instruction = await this.program.instruction.distributeProfit( 142 | new BN(profits), 143 | { 144 | accounts: { 145 | trader: new PublicKey(trader), 146 | // Add other required accounts 147 | }, 148 | } 149 | ); 150 | 151 | // Broadcast profit distribution 152 | followers.forEach(({ publicKey }, ws) => { 153 | if (ws.readyState === WebSocket.OPEN) { 154 | ws.send(JSON.stringify({ 155 | type: 'profit_distribution', 156 | trader, 157 | symbol, 158 | amount: followerShare 159 | })); 160 | } 161 | }); 162 | } catch (error) { 163 | console.error('Error distributing profits:', error); 164 | } 165 | } 166 | } 167 | 168 | module.exports = FollowTradeService; -------------------------------------------------------------------------------- /src/services/real_time_processor.js: -------------------------------------------------------------------------------- 1 | const WebSocket = require('ws'); 2 | const { MarketDataCollector } = require('../ai_engine/market_data'); 3 | const { SignalGenerator } = require('../ai_engine/signal_generator'); 4 | const { RiskManager } = require('../ai_engine/risk_manager'); 5 | const { ethers } = require('ethers'); 6 | const followTradeABI = require('../contracts/abi'); 7 | 8 | class RealTimeProcessor { 9 | constructor(config) { 10 | this.marketData = new MarketDataCollector(config.exchange); 11 | this.signalGenerator = new SignalGenerator(); 12 | this.riskManager = new RiskManager(); 13 | this.subscribers = new Map(); 14 | this.activeSymbols = new Set(); 15 | 16 | // Initialize smart contract connection 17 | this.provider = new ethers.providers.JsonRpcProvider(config.rpcUrl); 18 | this.wallet = new ethers.Wallet(config.privateKey, this.provider); 19 | this.followTradeContract = new ethers.Contract( 20 | config.contractAddress, 21 | followTradeABI, 22 | this.wallet 23 | ); 24 | } 25 | 26 | async start() { 27 | this.wss = new WebSocket.Server({ port: 8082 }); 28 | this.setupWebSocket(); 29 | this.startDataProcessing(); 30 | this.setupContractListeners(); 31 | } 32 | 33 | setupWebSocket() { 34 | this.wss.on('connection', (ws) => { 35 | ws.on('message', async (message) => { 36 | try { 37 | const data = JSON.parse(message); 38 | await this.handleMessage(ws, data); 39 | } catch (error) { 40 | console.error('Error processing message:', error); 41 | ws.send(JSON.stringify({ type: 'error', message: error.message })); 42 | } 43 | }); 44 | 45 | ws.on('close', () => { 46 | this.removeSubscriber(ws); 47 | }); 48 | }); 49 | } 50 | 51 | setupContractListeners() { 52 | // Listen for follow trade events 53 | this.followTradeContract.on('FollowTradeStarted', async (follower, symbol, fee) => { 54 | console.log(`New follow trade: ${follower} following ${symbol}`); 55 | await this.handleNewFollower(follower, symbol); 56 | }); 57 | 58 | // Listen for profit distribution events 59 | this.followTradeContract.on('ProfitDistributed', (trader, follower, amount) => { 60 | console.log(`Profit distributed: ${amount} to ${follower} from ${trader}`); 61 | }); 62 | } 63 | 64 | async handleNewFollower(follower, symbol) { 65 | try { 66 | // Add to active symbols if not already tracking 67 | if (!this.activeSymbols.has(symbol)) { 68 | this.activeSymbols.add(symbol); 69 | await this.startSymbolProcessing(symbol); 70 | } 71 | 72 | // Initialize risk parameters for the follower 73 | const riskMetrics = this.riskManager.get_risk_metrics(); 74 | const initialRiskScore = 0.5; // Default risk score 75 | 76 | // Store follower information 77 | if (!this.subscribers.has(symbol)) { 78 | this.subscribers.set(symbol, new Map()); 79 | } 80 | this.subscribers.get(symbol).set(follower, { 81 | riskScore: initialRiskScore, 82 | metrics: riskMetrics 83 | }); 84 | } catch (error) { 85 | console.error(`Error handling new follower: ${error.message}`); 86 | } 87 | } 88 | 89 | async startSymbolProcessing(symbol) { 90 | try { 91 | while (this.activeSymbols.has(symbol)) { 92 | const marketData = await this.marketData.fetch_historical_data(symbol, '1m', 100); 93 | if (!marketData) continue; 94 | 95 | const technicalIndicators = this.signalGenerator.calculate_technical_indicators(marketData); 96 | const prediction = await this.signalGenerator.generate_signal(technicalIndicators); 97 | 98 | if (prediction) { 99 | await this.processTradeSignal(symbol, prediction, technicalIndicators); 100 | } 101 | 102 | await new Promise(resolve => setTimeout(resolve, 60000)); // 1-minute interval 103 | } 104 | } catch (error) { 105 | console.error(`Error processing symbol ${symbol}: ${error.message}`); 106 | } 107 | } 108 | 109 | async processTradeSignal(symbol, prediction, indicators) { 110 | const subscribers = this.subscribers.get(symbol); 111 | if (!subscribers) return; 112 | 113 | for (const [follower, data] of subscribers) { 114 | try { 115 | // Calculate position size based on risk profile 116 | const positionSize = this.riskManager.calculate_position_size( 117 | 1000, // Default portfolio value, should be fetched from contract 118 | indicators.volatility, 119 | data.riskScore 120 | ); 121 | 122 | // Generate trade parameters 123 | const tradeParams = { 124 | symbol, 125 | direction: prediction.signal > 0 ? 'long' : 'short', 126 | size: positionSize, 127 | stopLoss: this.riskManager.calculate_stop_loss( 128 | indicators.close, 129 | prediction.signal > 0 ? 'long' : 'short', 130 | indicators.volatility 131 | ) 132 | }; 133 | 134 | // Broadcast trade signal to follower 135 | this.broadcastTradeSignal(follower, tradeParams); 136 | } catch (error) { 137 | console.error(`Error processing trade signal for ${follower}: ${error.message}`); 138 | } 139 | } 140 | } 141 | 142 | broadcastTradeSignal(follower, tradeParams) { 143 | const message = { 144 | type: 'trade_signal', 145 | data: tradeParams, 146 | timestamp: Date.now() 147 | }; 148 | 149 | // Send signal to specific follower's WebSocket connection 150 | const ws = Array.from(this.wss.clients).find(client => 151 | client.follower === follower && client.readyState === WebSocket.OPEN 152 | ); 153 | 154 | if (ws) { 155 | ws.send(JSON.stringify(message)); 156 | } 157 | } 158 | } 159 | 160 | module.exports = RealTimeProcessor; -------------------------------------------------------------------------------- /src/services/real_time_service.js: -------------------------------------------------------------------------------- 1 | const { WebSocketServer } = require('ws'); 2 | const { TradingEngine } = require('../ai_engine/trading_engine'); 3 | const { ethers } = require('ethers'); 4 | const followTradeABI = require('../contracts/FollowTrade.json'); 5 | 6 | class RealTimeService { 7 | constructor(config) { 8 | this.tradingEngine = new TradingEngine(config.apiKey, config.apiSecret); 9 | this.provider = new ethers.providers.JsonRpcProvider(config.rpcUrl); 10 | this.wallet = new ethers.Wallet(config.privateKey, this.provider); 11 | this.followTradeContract = new ethers.Contract( 12 | config.contractAddress, 13 | followTradeABI, 14 | this.wallet 15 | ); 16 | 17 | this.wss = new WebSocketServer({ port: config.wsPort }); 18 | this.activeSymbols = new Set(); 19 | this.subscribers = new Map(); 20 | this.initialize(); 21 | } 22 | 23 | initialize() { 24 | // 设置WebSocket连接处理 25 | this.wss.on('connection', (ws) => { 26 | ws.on('message', async (message) => { 27 | try { 28 | const data = JSON.parse(message); 29 | switch(data.type) { 30 | case 'subscribe': 31 | await this.handleSubscribe(ws, data); 32 | break; 33 | case 'unsubscribe': 34 | await this.handleUnsubscribe(ws, data); 35 | break; 36 | } 37 | } catch (error) { 38 | console.error('Error processing message:', error); 39 | ws.send(JSON.stringify({ type: 'error', message: error.message })); 40 | } 41 | }); 42 | }); 43 | 44 | // 启动信号生成循环 45 | this.startSignalGeneration(); 46 | } 47 | 48 | async handleSubscribe(ws, data) { 49 | const { symbol, address } = data; 50 | 51 | // 验证用户是否有效跟随者 52 | const isActiveFollower = await this.followTradeContract.getFollowerStatus(address, symbol); 53 | if (!isActiveFollower) { 54 | ws.send(JSON.stringify({ 55 | type: 'error', 56 | message: 'Not an active follower for this symbol' 57 | })); 58 | return; 59 | } 60 | 61 | // 添加到订阅列表 62 | if (!this.subscribers.has(symbol)) { 63 | this.subscribers.set(symbol, new Set()); 64 | } 65 | this.subscribers.get(symbol).add(ws); 66 | this.activeSymbols.add(symbol); 67 | 68 | ws.send(JSON.stringify({ 69 | type: 'subscribed', 70 | symbol: symbol 71 | })); 72 | } 73 | 74 | async handleUnsubscribe(ws, data) { 75 | const { symbol } = data; 76 | if (this.subscribers.has(symbol)) { 77 | this.subscribers.get(symbol).delete(ws); 78 | if (this.subscribers.get(symbol).size === 0) { 79 | this.subscribers.delete(symbol); 80 | this.activeSymbols.delete(symbol); 81 | } 82 | } 83 | } 84 | 85 | async startSignalGeneration() { 86 | const INTERVAL = 1000; // 1秒更新间隔 87 | const MAX_RETRIES = 3; 88 | let performanceMetrics = new Map(); 89 | 90 | setInterval(async () => { 91 | for (const symbol of this.activeSymbols) { 92 | try { 93 | const startTime = Date.now(); 94 | let retries = 0; 95 | let marketData; 96 | 97 | // 带重试的市场数据获取 98 | while (retries < MAX_RETRIES && !marketData) { 99 | marketData = await this.tradingEngine.fetch_market_data(symbol); 100 | if (!marketData) { 101 | retries++; 102 | await new Promise(resolve => setTimeout(resolve, 1000 * retries)); 103 | } 104 | } 105 | 106 | if (!marketData) { 107 | throw new Error(`Failed to fetch market data for ${symbol} after ${MAX_RETRIES} retries`); 108 | } 109 | 110 | // 获取投资组合价值 111 | const portfolioValue = await this.getPortfolioValue(symbol); 112 | 113 | // 生成交易信号 114 | const signal = await this.tradingEngine.generate_trading_signal( 115 | marketData, 116 | portfolioValue 117 | ); 118 | 119 | // 评估交易风险 120 | const riskAssessment = await this.assessTradeRisk(signal, marketData); 121 | 122 | // 记录性能指标 123 | const processingTime = Date.now() - startTime; 124 | this.updatePerformanceMetrics(symbol, processingTime); 125 | 126 | // 广播信号 127 | if (signal && signal.signal !== 0 && signal.confidence > 0.7 && riskAssessment.riskScore < 0.8) { 128 | signal.position_size = riskAssessment.recommendedSize; 129 | await this.broadcastSignal(symbol, signal); 130 | } 131 | 132 | } catch (error) { 133 | console.error(`Error processing ${symbol}:`, error); 134 | this.notifyError(symbol, error); 135 | } 136 | } 137 | }, INTERVAL); 138 | } 139 | 140 | async getPortfolioValue(symbol) { 141 | try { 142 | // 从智能合约获取跟随者的投资组合价值 143 | const followers = await this.followTradeContract.getFollowers(symbol); 144 | let totalValue = 0; 145 | 146 | for (const follower of followers) { 147 | const balance = await this.followTradeContract.balances(follower); 148 | totalValue += balance.toNumber(); 149 | } 150 | 151 | return totalValue; 152 | } catch (error) { 153 | console.error('Error getting portfolio value:', error); 154 | return 1000000; // 默认值 155 | } 156 | } 157 | 158 | async assessTradeRisk(signal, marketData) { 159 | try { 160 | const volatility = marketData.indicators.volatility; 161 | const volume = marketData.ohlcv.volume.mean(); 162 | const price = marketData.ohlcv.close.last(); 163 | 164 | // 计算风险分数 165 | let riskScore = 0.5; // 基础风险分数 166 | 167 | // 波动率调整 168 | if (volatility > 0.02) riskScore += 0.2; 169 | if (volatility > 0.05) riskScore += 0.3; 170 | 171 | // 成交量调整 172 | const avgVolume = volume * price; 173 | if (avgVolume < 1000000) riskScore += 0.2; // 流动性风险 174 | 175 | // 市场冲击成本 176 | const impact = marketData.orderbook ? 177 | this.tradingEngine.market_data.calculate_market_impact(marketData.orderbook, signal.position_size) : 178 | { buy_impact: 0, sell_impact: 0 }; 179 | 180 | if (impact.buy_impact > 0.01 || impact.sell_impact > 0.01) { 181 | riskScore += 0.1; 182 | } 183 | 184 | return { 185 | riskScore: Math.min(riskScore, 1), 186 | factors: { 187 | volatility, 188 | volume: avgVolume, 189 | impact 190 | }, 191 | recommendedSize: signal.position_size * (1 - riskScore) 192 | }; 193 | } catch (error) { 194 | console.error('Error assessing trade risk:', error); 195 | return { 196 | riskScore: 1, 197 | factors: {}, 198 | recommendedSize: 0 199 | }; 200 | } 201 | } 202 | 203 | updatePerformanceMetrics(symbol, latency) { 204 | if (!this.performanceMetrics) { 205 | this.performanceMetrics = new Map(); 206 | } 207 | 208 | const metrics = this.performanceMetrics.get(symbol) || { 209 | latencies: [], 210 | errors: 0, 211 | signalCount: 0 212 | }; 213 | 214 | metrics.latencies.push(latency); 215 | metrics.signalCount++; 216 | 217 | if (metrics.latencies.length > 100) { 218 | metrics.latencies.shift(); 219 | } 220 | 221 | this.performanceMetrics.set(symbol, metrics); 222 | } 223 | 224 | notifyError(symbol, error) { 225 | const subscribers = this.subscribers.get(symbol); 226 | if (!subscribers) return; 227 | 228 | const errorMessage = JSON.stringify({ 229 | type: 'error', 230 | symbol, 231 | message: error.message, 232 | timestamp: Date.now() 233 | }); 234 | 235 | subscribers.forEach(ws => { 236 | if (ws.readyState === ws.OPEN) { 237 | ws.send(errorMessage); 238 | } 239 | }); 240 | 241 | this.updateErrorMetrics(symbol, error); 242 | } 243 | 244 | updateErrorMetrics(symbol, error) { 245 | if (!this.errorMetrics) { 246 | this.errorMetrics = new Map(); 247 | } 248 | 249 | const metrics = this.errorMetrics.get(symbol) || { 250 | count: 0, 251 | lastError: null, 252 | timestamp: null 253 | }; 254 | 255 | metrics.count++; 256 | metrics.lastError = error.message; 257 | metrics.timestamp = Date.now(); 258 | 259 | this.errorMetrics.set(symbol, metrics); 260 | } 261 | 262 | async getPortfolioValue(symbol) { 263 | try { 264 | // 从智能合约获取跟随者的投资组合价值 265 | const followers = await this.followTradeContract.getFollowers(symbol); 266 | let totalValue = 0; 267 | 268 | for (const follower of followers) { 269 | const balance = await this.followTradeContract.balances(follower); 270 | totalValue += balance.toNumber(); 271 | } 272 | 273 | return totalValue; 274 | } catch (error) { 275 | console.error('Error getting portfolio value:', error); 276 | return 1000000; // 默认值 277 | } 278 | } 279 | 280 | async assessTradeRisk(signal, marketData) { 281 | try { 282 | const volatility = marketData.indicators.volatility; 283 | const volume = marketData.ohlcv.volume.mean(); 284 | const price = marketData.ohlcv.close.last(); 285 | 286 | // 计算风险分数 287 | let riskScore = 0.5; // 基础风险分数 288 | 289 | // 波动率调整 290 | if (volatility > 0.02) riskScore += 0.2; 291 | if (volatility > 0.05) riskScore += 0.3; 292 | 293 | // 成交量调整 294 | const avgVolume = volume * price; 295 | if (avgVolume < 1000000) riskScore += 0.2; // 流动性风险 296 | 297 | // 市场冲击成本 298 | const impact = marketData.orderbook ? 299 | this.tradingEngine.market_data.calculate_market_impact(marketData.orderbook, signal.position_size) : 300 | { buy_impact: 0, sell_impact: 0 }; 301 | 302 | if (impact.buy_impact > 0.01 || impact.sell_impact > 0.01) { 303 | riskScore += 0.1; 304 | } 305 | 306 | return { 307 | riskScore: Math.min(riskScore, 1), 308 | factors: { 309 | volatility, 310 | volume: avgVolume, 311 | impact 312 | }, 313 | recommendedSize: signal.position_size * (1 - riskScore) 314 | }; 315 | } catch (error) { 316 | console.error('Error assessing trade risk:', error); 317 | return { 318 | riskScore: 1, 319 | factors: {}, 320 | recommendedSize: 0 321 | }; 322 | } 323 | } 324 | 325 | updatePerformanceMetrics(symbol, latency) { 326 | if (!this.performanceMetrics) { 327 | this.performanceMetrics = new Map(); 328 | } 329 | 330 | const metrics = this.performanceMetrics.get(symbol) || { 331 | latencies: [], 332 | errors: 0, 333 | signalCount: 0 334 | }; 335 | 336 | metrics.latencies.push(latency); 337 | metrics.signalCount++; 338 | 339 | if (metrics.latencies.length > 100) { 340 | metrics.latencies.shift(); 341 | } 342 | 343 | this.performanceMetrics.set(symbol, metrics); 344 | } 345 | 346 | updateErrorMetrics(symbol, error) { 347 | if (!this.errorMetrics) { 348 | this.errorMetrics = new Map(); 349 | } 350 | 351 | const metrics = this.errorMetrics.get(symbol) || { 352 | count: 0, 353 | lastError: null, 354 | timestamp: null 355 | }; 356 | 357 | metrics.count++; 358 | metrics.lastError = error.message; 359 | metrics.timestamp = Date.now(); 360 | 361 | this.errorMetrics.set(symbol, metrics); 362 | } 363 | } 364 | 365 | module.exports = { RealTimeService }; -------------------------------------------------------------------------------- /src/services/social_media_service.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const FormData = require('form-data'); 3 | const fs = require('fs'); 4 | 5 | class SocialMediaService { 6 | constructor(config) { 7 | this.config = config; 8 | this.platforms = { 9 | twitter: this.postToTwitter.bind(this), 10 | telegram: this.postToTelegram.bind(this), 11 | discord: this.postToDiscord.bind(this), 12 | reddit: this.postToReddit.bind(this), 13 | weibo: this.postToWeibo.bind(this) 14 | }; 15 | } 16 | 17 | async postContent(content, platforms = ['twitter', 'telegram', 'discord', 'reddit', 'weibo']) { 18 | const results = []; 19 | for (const platform of platforms) { 20 | if (this.platforms[platform]) { 21 | try { 22 | const result = await this.platforms[platform](content); 23 | results.push({ platform, success: true, result }); 24 | } catch (error) { 25 | console.error(`Error posting to ${platform}:`, error); 26 | results.push({ platform, success: false, error: error.message }); 27 | } 28 | } 29 | } 30 | return results; 31 | } 32 | 33 | async postToTwitter(content) { 34 | const { text, mediaPath, replyToId } = content; 35 | const data = new FormData(); 36 | data.append('text', text); 37 | 38 | if (mediaPath && fs.existsSync(mediaPath)) { 39 | data.append('media', fs.createReadStream(mediaPath)); 40 | } 41 | 42 | if (replyToId) { 43 | data.append('reply', { in_reply_to_tweet_id: replyToId }); 44 | } 45 | 46 | const response = await axios.post( 47 | 'https://api.twitter.com/2/tweets', 48 | data, 49 | { 50 | headers: { 51 | ...data.getHeaders(), 52 | 'Authorization': `Bearer ${this.config.twitter.accessToken}` 53 | } 54 | } 55 | ); 56 | 57 | return response.data; 58 | } 59 | 60 | async postToTelegram(content) { 61 | const { text, mediaPath, replyToMessageId } = content; 62 | const method = mediaPath ? 'sendPhoto' : 'sendMessage'; 63 | const data = mediaPath ? 64 | { photo: fs.createReadStream(mediaPath), caption: text } : 65 | { text }; 66 | 67 | if (replyToMessageId) { 68 | data.reply_to_message_id = replyToMessageId; 69 | } 70 | 71 | const response = await axios.post( 72 | `https://api.telegram.org/bot${this.config.telegram.botToken}/${method}`, 73 | { 74 | chat_id: this.config.telegram.channelId, 75 | ...data 76 | }, 77 | { 78 | headers: { 'Content-Type': 'application/json' } 79 | } 80 | ); 81 | 82 | return response.data; 83 | } 84 | 85 | async postToDiscord(content) { 86 | const { text, mediaPath, threadId } = content; 87 | const data = { content: text }; 88 | 89 | if (threadId) { 90 | data.thread_id = threadId; 91 | } 92 | 93 | if (mediaPath) { 94 | const form = new FormData(); 95 | form.append('file', fs.createReadStream(mediaPath)); 96 | form.append('payload_json', JSON.stringify(data)); 97 | 98 | return await axios.post( 99 | this.config.discord.webhookUrl, 100 | form, 101 | { headers: form.getHeaders() } 102 | ); 103 | } 104 | 105 | return await axios.post( 106 | this.config.discord.webhookUrl, 107 | data, 108 | { headers: { 'Content-Type': 'application/json' } } 109 | ); 110 | } 111 | 112 | async postToReddit(content) { 113 | const { text, mediaPath, subreddit } = content; 114 | const data = { 115 | title: text.split('\n')[0], 116 | text: text, 117 | sr: subreddit || this.config.reddit.defaultSubreddit 118 | }; 119 | 120 | if (mediaPath) { 121 | data.image = fs.createReadStream(mediaPath); 122 | } 123 | 124 | const response = await axios.post( 125 | 'https://oauth.reddit.com/api/submit', 126 | data, 127 | { 128 | headers: { 129 | 'Authorization': `Bearer ${this.config.reddit.accessToken}`, 130 | 'Content-Type': 'application/json' 131 | } 132 | } 133 | ); 134 | 135 | return response.data; 136 | } 137 | 138 | async postToWeibo(content) { 139 | const { text, mediaPath } = content; 140 | const data = new FormData(); 141 | data.append('status', text); 142 | 143 | if (mediaPath && fs.existsSync(mediaPath)) { 144 | data.append('pic', fs.createReadStream(mediaPath)); 145 | } 146 | 147 | const response = await axios.post( 148 | 'https://api.weibo.com/2/statuses/share.json', 149 | data, 150 | { 151 | headers: { 152 | ...data.getHeaders(), 153 | 'Authorization': `OAuth2 ${this.config.weibo.accessToken}` 154 | } 155 | } 156 | ); 157 | 158 | return response.data; 159 | } 160 | 161 | async distributeTradeContent(tradeData, memeImage, confessionVoice) { 162 | const content = { 163 | text: `🚨 Trade Alert! ${tradeData.symbol}\n` + 164 | `💰 Price: ${tradeData.price}\n` + 165 | `📊 P/L: ${tradeData.profit_loss}\n` + 166 | `${tradeData.description || ''}\n\n` + 167 | `#DeepRug #Trading #Crypto ${tradeData.tags || ''}`, 168 | mediaPath: memeImage 169 | }; 170 | 171 | // 首先发布Meme图片 172 | const memeResults = await this.postContent(content); 173 | 174 | // 如果有认罪语音,作为单独的内容发布 175 | if (confessionVoice) { 176 | const voiceContent = { 177 | text: `🎤 Trader's Confession 😅\n` + 178 | `Listen to what happened with ${tradeData.symbol} 🔊\n` + 179 | `#TraderConfession #CryptoLife`, 180 | mediaPath: confessionVoice 181 | }; 182 | const voiceResults = await this.postContent(voiceContent); 183 | return [...memeResults, ...voiceResults]; 184 | } 185 | 186 | return memeResults; 187 | } 188 | 189 | async createThread(content, platforms = ['discord']) { 190 | const results = []; 191 | for (const platform of platforms) { 192 | if (platform === 'discord' && this.platforms[platform]) { 193 | try { 194 | const result = await this.platforms[platform]({ 195 | ...content, 196 | createThread: true 197 | }); 198 | results.push({ platform, success: true, result }); 199 | } catch (error) { 200 | console.error(`Error creating thread on ${platform}:`, error); 201 | results.push({ platform, success: false, error: error.message }); 202 | } 203 | } 204 | } 205 | return results; 206 | } 207 | } 208 | 209 | module.exports = SocialMediaService; -------------------------------------------------------------------------------- /src/services/trading_service.js: -------------------------------------------------------------------------------- 1 | const { Connection, PublicKey, Transaction, SystemProgram } = require('@solana/web3.js'); 2 | const { Program } = require('@project-serum/anchor'); 3 | const { TradingEngine } = require('../ai_engine/trading_engine'); 4 | const WebSocket = require('ws'); 5 | 6 | class TradingService { 7 | constructor(endpoint, programId) { 8 | // Initialize Solana connection 9 | this.connection = new Connection(endpoint); 10 | this.programId = new PublicKey(programId); 11 | 12 | // Initialize trading engine 13 | this.tradingEngine = new TradingEngine(); 14 | 15 | // Active trading signals 16 | this.activeSignals = new Map(); 17 | 18 | // Initialize WebSocket server 19 | this.wss = new WebSocket.Server({ port: 8080 }); 20 | this.clients = new Map(); 21 | 22 | this.setupWebSocket(); 23 | } 24 | 25 | setupWebSocket() { 26 | this.wss.on('connection', (ws) => { 27 | ws.on('message', async (message) => { 28 | try { 29 | const data = JSON.parse(message); 30 | 31 | if (data.type === 'subscribe') { 32 | this.clients.set(ws, { 33 | publicKey: data.publicKey, 34 | symbols: new Set(data.symbols) 35 | }); 36 | } 37 | } catch (error) { 38 | console.error('Error processing WebSocket message:', error); 39 | } 40 | }); 41 | 42 | ws.on('close', () => { 43 | this.clients.delete(ws); 44 | }); 45 | }); 46 | } 47 | 48 | broadcastSignal(symbol, signal) { 49 | this.clients.forEach((client, ws) => { 50 | if (client.symbols.has(symbol) && ws.readyState === WebSocket.OPEN) { 51 | ws.send(JSON.stringify({ 52 | type: 'signal', 53 | symbol, 54 | signal 55 | })); 56 | } 57 | }); 58 | } 59 | 60 | notifyFollowSuccess(userPublicKey, symbol, signal) { 61 | this.clients.forEach((client, ws) => { 62 | if (client.publicKey === userPublicKey && ws.readyState === WebSocket.OPEN) { 63 | ws.send(JSON.stringify({ 64 | type: 'follow_success', 65 | symbol, 66 | signal 67 | })); 68 | } 69 | }); 70 | } 71 | 72 | async generateAndBroadcastSignal(symbol) { 73 | try { 74 | // Fetch market data and generate signal 75 | const marketData = await this.tradingEngine.fetch_market_data(symbol); 76 | const signal = await this.tradingEngine.generate_trading_signal(marketData); 77 | 78 | if (signal) { 79 | // Store active signal 80 | this.activeSignals.set(symbol, { 81 | ...signal, 82 | followers: new Set() 83 | }); 84 | 85 | // Broadcast signal to connected clients 86 | this.broadcastSignal(symbol, signal); 87 | } 88 | 89 | return signal; 90 | } catch (error) { 91 | console.error('Error generating trading signal:', error); 92 | return null; 93 | } 94 | } 95 | 96 | async followTrade(userPublicKey, symbol) { 97 | try { 98 | // Check if signal exists 99 | const signal = this.activeSignals.get(symbol); 100 | if (!signal) { 101 | throw new Error('No active signal for this symbol'); 102 | } 103 | 104 | // Check if user is already following 105 | if (signal.followers.has(userPublicKey)) { 106 | throw new Error('Already following this signal'); 107 | } 108 | 109 | // Create follow trade instruction 110 | const instruction = await this.program.instruction.followTrade({ 111 | accounts: { 112 | user: userPublicKey, 113 | systemProgram: SystemProgram.programId, 114 | }, 115 | signers: [userPublicKey] 116 | }); 117 | 118 | // Add user to followers 119 | signal.followers.add(userPublicKey); 120 | 121 | // Notify user of successful follow 122 | this.notifyFollowSuccess(userPublicKey, symbol, signal); 123 | 124 | return true; 125 | } catch (error) { 126 | console.error('Error following trade:', error); 127 | return false; 128 | } 129 | } 130 | 131 | async startTradingStream(symbols = ['BTC/USDT', 'ETH/USDT']) { 132 | // Start periodic signal generation 133 | setInterval(async () => { 134 | for (const symbol of symbols) { 135 | await this.generateAndBroadcastSignal(symbol); 136 | } 137 | }, 60000); // Generate signals every minute 138 | } 139 | throw new Error('No active signal for this symbol'); 140 | } 141 | 142 | // Create transaction for follow trade fee 143 | const transaction = new Transaction(); 144 | const instruction = await this.program.methods 145 | .payFollowTradeFee() 146 | .accounts({ 147 | user: userPublicKey, 148 | // Add other required accounts based on your program structure 149 | }) 150 | .instruction(); 151 | 152 | transaction.add(instruction); 153 | 154 | // Send and confirm transaction 155 | const signature = await this.connection.sendTransaction(transaction, []); 156 | const confirmation = await this.connection.confirmTransaction(signature); 157 | 158 | if (confirmation.value.err === null) { 159 | // Add user to signal followers 160 | signal.followers.add(userPublicKey.toString()); 161 | 162 | // Notify user of successful follow 163 | this.notifyFollowSuccess(userPublicKey.toString(), symbol, signal); 164 | return true; 165 | } 166 | 167 | return false; 168 | } catch (error) { 169 | console.error('Error following trade:', error); 170 | return false; 171 | } 172 | } 173 | 174 | broadcastSignal(symbol, signal) { 175 | // This method should be implemented to work with your WebSocket system 176 | // to broadcast signals to connected clients 177 | console.log(`Broadcasting signal for ${symbol}:`, signal); 178 | } 179 | 180 | notifyFollowSuccess(userPublicKey, symbol, signal) { 181 | // This method should be implemented to notify users of successful follows 182 | console.log(`User ${userPublicKey} successfully followed ${symbol} signal`); 183 | } 184 | } 185 | 186 | module.exports = TradingService; --------------------------------------------------------------------------------