如何构建 AI 交易机器人:完整开发者指南(2026)
作者:Usman Asim

在过去几年中,我们见证了 AI 交易工具的大量涌现。
约有 58% 的散户投资者现在使用某种形式的 AI 来协助构建投资组合,风险投资已向 Web3 AI 交易技术注入了 2.13 亿美元,一些自主 AI agent 在短短一个月内的交易量已超过 4 亿美元,其市场分析、执行速度以及与其他 agent 的协作能力也在不断提升。
但在热潮之下是更为复杂的现实:成功不仅取决于精巧的算法,还取决于可靠的基础设施、稳健的风险管理,以及对 AI 能力边界的现实预期。
本指南将带你了解构建自己的 AI 交易机器人所需的一切知识。我们将探讨当前 AI 交易的格局,包括新兴的自主 agent 经济体,梳理可用的工具和平台,分析不同的机器人策略,并提供一份教程,帮助你使用 Alchemy 的区块链基础设施开始构建自己的交易机器人。
什么是 AI 交易机器人?
AI 交易机器人是一种使用机器学习算法分析市场数据、识别交易机会并自动执行买卖订单的软件。与遵循静态“如果-那么”逻辑的传统规则型机器人不同,AI 驱动的机器人能够适应不断变化的市场条件,从历史模式中学习,并基于海量数据做出概率性决策。它们全天候运行,消除了交易决策中的情绪偏差,反应速度也快于任何人类。
2025 年的 AI 交易机器人格局呈现出明显反差。AI 辅助交易工具的采用率大幅增长,参与自动化交易的散户投资者数量创历史新高。然而,实际成功率却揭示了一个更为严峻的现实:只有 10%-30% 的机器人用户实现了持续盈利。
采用率与成功率之间的这一差距并不令人意外,因为加密市场以波动剧烈著称,预测模型需要不断调整,而许多新手低估了风险管理的重要性。真正成功的机器人并不一定拥有最精巧的 AI,而是建立在扎实基础之上:可靠的数据、清晰的策略和严格的执行纪律。
由此可见:AI 交易机器人是强大的工具,但并非魔法。成功与否取决于既理解其能力,也理解其局限。
区块链基础设施的作用
AI 交易机器人是强大的工具,但成功与否取决于既理解其能力,也理解其局限。然而,一个常被忽视的问题是:模型的精巧程度只是方程式的一部分。大多数机器人失败并非因为 AI 做出了错误预测,而是因为底层基础设施跟不上——数据过时、API 在市场剧烈波动时宕机、速度更快的竞争对手抢先完成了交易。这些都不是特例,而是算法交易中的日常现实。
有三项关键的基础设施要求,决定了机器人是持续盈利还是最终崩溃:
- 数据准确性:AI 模型的表现取决于其训练和反应所依赖的数据质量。过时的代币价格、滞后的流动性池状态,或遗漏的巨鲸动向,都会直接转化为糟糕的交易决策。当机器人依据错误数据行动时,就会亏钱——再精巧的算法逻辑也无法弥补根本上有缺陷的输入。
- 延迟:在算法交易中,速度决定谁能获利。当你的机器人发现一个套利机会时,很可能有数十个其他机器人也看到了同样的信号。拥有最快数据管道的机器人会率先执行并获取价差,其他人则只能接受更差的成交价,甚至完全错失交易。低延迟基础设施是竞争的必要条件,而不是性能优化的锦上添花。
- 可靠性:在市场剧烈波动期间的基础设施宕机可能是灾难性的。哪怕只是短短几分钟的离线,也可能意味着在暴跌中错过止损、仓位被强制平仓而无法防御,或者在机器人重新连接之前机会已经消失。对于管理真实资金的交易系统而言,正常运行时间不是一项服务级别指标,而是生存的必要条件。
这正是 Alchemy 这类数据服务商变得至关重要的地方。Alchemy 提供了 AI 交易机器人有效运行所需的可靠、实时的数据访问——包括跨多条链的代币价格、交易量、巨鲸动向、流动性池状态等。Alchemy 的增强型 API 和基础设施能够大规模满足这些需求,支持超过 100 条区块链,并具备竞争性交易所要求的低延迟性能。
构建安全、可观测的交易机器人
即使拥有扎实的基础设施,AI 交易机器人仍可能表现出不可预测的行为。市场会以模型未曾预见的方式波动,边缘情况会触发意外行为,而复合性错误可能将小失误演变为灾难性损失。在机器人架构中构建安全机制并非可选项,而是决定你能否存活足够长的时间以持续迭代和改进的关键。
- 构建可观测的系统:每笔交易都应可追溯。哪些数据支撑了这一决策?机器人为何选择了这一特定动作?当出现问题时(问题必然会出现),你需要判断究竟是数据有误、逻辑有缺陷,还是模型未曾预见的边缘情况。
- 添加熔断机制:设置自动暂停交易的最大亏损阈值,实施速率限制器以防止失控执行,并在重大亏损后设置冷却期。这些机制可以防止运行异常的机器人在你察觉问题之前耗尽账户资金。
- 保持人工介入:完全自主听起来令人印象深刻,但最具韧性的系统会在高风险决策中保留人工参与。可以考虑要求对超过特定阈值的交易进行人工审批,或构建警报系统,在机器人行为偏离预期模式时通知你。
从长期来看,能够成功的机器人不仅仅是拥有最佳模型的那些,而是那些具备足够的可观测性和安全防护措施、能够及早发现问题并妥善恢复的机器人。
工具与技术:你的 AI 交易机器人技术栈
在了解了 AI 交易机器人的基础设施层面——数据准确性、延迟和可靠性之后,下一步是组建实际的工具集。以下是构建生产级 AI 交易机器人技术栈所需的内容:
核心编程技术栈
得益于其丰富的机器学习生态系统和简洁性,Python 仍然是 AI 交易机器人的主流语言。你的核心 Python 库应包括:
- Pandas:用于数据处理和时间序列分析
- NumPy:用于价格和成交量数据的数值计算
- scikit-learn:用于传统机器学习模型(回归、分类、聚类)
- PyTorch 或 TensorFlow:用于 LSTM 等深度学习模型,或用于序列预测的 transformer
这些库共同为你提供了完整的能力谱系:从一个下午就能搭建完成的简单移动平均线交叉机器人,到融合技术分析、情绪评分和链上指标的复杂多模型机器人。这正是 Python 生态系统的魅力所在:你可以从简单开始,按需逐步增加复杂度,如果线性回归就能完成任务,第一天就没必要为深度学习搭建架构。
提示:如果你要构建对微秒级延迟敏感的高频交易机器人,C++ 提供了原始的执行速度和底层控制能力。Rust 因其性能和内存安全性,也在加密领域获得了广泛采用,尤其适用于构建链上组件或需要高度安全性的自定义 DEX 集成。Go 则是需要同时监控多个市场的并发系统的另一个可靠选择。
话虽如此,对于大多数加密交易策略而言,即便是相对复杂的策略,Python 的性能也已经绰绰有余,其带来的开发速度优势远超大多数散户交易者所能获得的边际速度提升。可以先从 Python 开始,等到性能分析结果表明确有必要时,再将关键组件迁移到速度更快的语言。
区块链基础设施:Alchemy 层
这正是 Alchemy 变得不可或缺的地方。Alchemy 提供了支撑可靠 AI 交易机器人大规模运行的基础设施层。关键工具包括:
- 实时区块链数据:在 50 条以上的链上查询代币价格、余额、交易历史和 NFT 元数据。可以在我们的沙盒环境中亲自体验。
- WebSocket 连接:订阅待处理交易、新区块或智能合约状态变化等实时事件。
- 增强型 API:获取 gas 价格预测、带元数据的代币余额,以及历史交易数据。
对于加密交易机器人,你还需要:
- Web3.py:与 Ethereum 交互的接口,用于发送交易、调用智能合约、编码数据。如果你直接在 DEX 上交易或与 DeFi 协议交互,这是必不可少的工具。
- CCXT:一个统一的 API 封装库,让你能够使用一致的语法在 100 多个中心化交易所(Binance、Coinbase、Kraken 等)上进行交易。CCXT 将各交易所之间的 API 差异统一起来,无需逐一学习各自的接口特性。
- Alchemy 的 MCP(Model Context Protocol)服务器:这是区块链与 AI 的交汇点:我们的 MCP 服务器使 AI agent 能够使用自然语言查询链上数据。你的 AI 无需编写复杂查询,只需问“ETH 目前的价格是多少?”即可获得结构化数据。
安装 Alchemy Skills,连接 MCP 服务器,并使用 CLI:
npx skills add alchemyplatform/skills --yes
# Claude Code
claude mcp add alchemy --transport http https://mcp.alchemy.com/mcp
# Codex
codex mcp add alchemy --url https://mcp.alchemy.com/mcp
npm i -g @alchemy/cli@latest
alchemy auth
alchemy --json --no-interactive prices symbol ETH,BTC
alchemy --json --no-interactive balance vitalik.eth -n eth-mainnet关于自主交易执行,参见 CLI 中的 agent 钱包。
AI 增强工具
我们已经看到交易机器人的下一阶段演进:不再只是分析数据,而是使用 AI 来做出越来越精细的决策。过去一年出现了两大主要方法,不同的开发者一直在使用它们来完善自己的流程:
大语言模型 API(Claude、GPT-4 等)解锁了超越传统机器学习的能力:
- 情绪分析:处理成千上万条推文、Reddit 帖子或新闻文章,以判断市场情绪
- 策略生成:用简单的英文描述一个交易想法,让 AI 帮助将其形式化为代码
- 异常检测:使用大语言模型发现市场数据中可能预示机会的异常模式
2025 年,我们看到了更进一步的新 Agent 框架,它们通过构建自主系统将这一能力推向新高度:
- ElizaOS(来自 ai16z):支撑去中心化 AI 基金的框架,让你能够构建不仅提出交易建议、还能实际执行交易的 agent。它们可以管理投资组合,甚至与其他 agent 协作。
- Virtuals GAME SDK:创建能够参与更大 agent 经济体的 agent——赚取费用、为其他 agent 提供服务,或协作完成复杂策略。可以将其理解为构建一个能与其他 agent“良好协作”的机器人。
- LangChain:用于编排复杂 AI 工作流的瑞士军刀,让你能够整合多次 AI 调用、组合来自不同来源的数据,并构建原本需要繁琐硬编码才能实现的决策树。当你的策略需要多步推理时尤其有用。
这些工具将你的机器人从“遵循规则的机器人”转变为“能够适应和学习的 agent”。开发的学习曲线更陡峭,但潜在回报也显著更高。
必备的支持工具
- 市场数据 API:CoinGecko、CoinMarketCap 或交易所专属 API(Binance、Coinbase、Kraken)等服务提供定价数据、交易量、市值排名以及历史 OHLCV(开盘价、最高价、最低价、收盘价、成交量)数据。Alchemy 负责处理链上数据,而这些 API 则填补了中心化交易所价格及更广泛市场背景方面的空白,而这些正是你的模型做出明智决策所需要的。
- 回测框架:在动用真实资金之前,你需要针对历史数据验证自己的策略。Backtrader 和 Zipline 等框架可以让你模拟机器人在过去市场条件下(牛市、崩盘和横盘震荡期间)的表现。良好的回测基础设施能帮助你发现策略弱点、优化参数,并在上线前建立信心。
- 版本控制:对于正式的交易系统而言,Git 不是可选项。随着你的策略不断演进——调整参数、添加新信号、修复错误——你需要追踪每一次变更、回滚失败的实验,并清楚记录特定交易执行时运行的是哪个版本的代码。这对于长期调试和审计机器人行为至关重要。
AI 交易机器人的类型
AI 交易机器人涵盖了从简单自动化到实验性多 agent 系统的广泛策略和复杂程度。以下是你会遇到的最常见类别:
- 技术分析与情绪分析机器人:技术型机器人分析价格图表、移动平均线和各类指标以识别交易机会——AI 增强功能使它们能够动态调整信号权重,并识别静态规则会遗漏的复杂模式。情绪型机器人解析 Twitter/X 帖子、Reddit 讨论、新闻文章以及链上信号(巨鲸动向、交易所流入量、gas 激增),基于市场情绪预测短期价格走势。这类机器人在炒作周期驱动波动的山寨币和 meme 代币中尤其流行。
- 套利与做市机器人:套利机器人利用不同交易所或流动性池之间的价格差异——在某个平台以 2,000 美元买入 ETH,在另一个平台以 2,010 美元卖出。AI 通过在差价出现之前进行预测,并优化跨 DEX 的多跳路由来提供帮助。做市机器人通过同时提供买卖报价来提供流动性,从价差中获利。在 DeFi 中,这意味着将资金存入 Uniswap 或 Curve 流动性池,并使用 AI 管理无常损失,根据波动性调整价差。
- 趋势跟踪与投资组合管理机器人:动量机器人识别正在积累力量的资产,并在信号反转之前持续跟随趋势,LSTM(长短期记忆网络)等模型有助于预测趋势将延续还是崩溃。投资组合机器人根据 AI 预测自动再平衡持仓,将配置向预期回报更强的资产倾斜,同时管理整体风险敞口。
- 自主 AI Agent 基金:在实验前沿,ElizaOS 等项目管理由 DAO 治理的基金,其中 AI agent 协调交易策略、共享信号并优化整体表现,类似 aixbt。这些多 agent 系统模糊了交易机器人与自主金融实体之间的界限——虽然仍处于早期阶段,但已经能窥见 AI 驱动金融的发展方向。
构建你的第一个 AI 交易机器人:分步教程
在这一部分,我们将尝试为 Ethereum 创建一个自己的情绪增强型趋势预测机器人,将链上数据与机器学习结合起来做出交易决策。
我们将构建:
- 一个通过 Alchemy 获取实时 ETH 价格和区块链数据的机器人
- 结合价格指标与链上情绪信号的特征工程
- 一个预测短期价格走势的机器学习模型
- 带有置信度阈值和风险管理的交易逻辑
- 在上线前验证策略的回测能力
这是一个较为初级的示例:可以把它看作是你可以在其上继续构建的基础,而非一套可直接投产的系统。目标是理解核心概念和工作流程,然后根据你自己的具体策略进行扩展。
前置条件
在开始编写代码之前,请确保你已具备:
- 机器上已安装 Python 3.8 或更高版本
- 一个带有 API key 的 Alchemy 账户(在此免费注册)
- 基本的 Python 知识:应熟悉函数、循环和数据结构
- 基本的机器学习理解:熟悉训练/测试集划分和模型评估等概念
首先,我们需要安装所需的软件包:
pip install pandas numpy scikit-learn requests web3 python-dotenv这些软件包各自的作用:
pandas:处理数据操作和时间序列numpy:支持数值计算scikit-learn:提供机器学习算法requests:向 API 发起 HTTP 请求web3:连接 Alchemy 的 Ethereum 端点并与区块链交互python-dotenv:安全地管理环境变量
步骤 1:设置 Alchemy 并获取历史区块链数据
首先,让我们建立与区块链的连接,并收集用于训练模型的历史数据。
在你的项目目录中创建一个 .env 文件,用于安全地存储你的 API key:
ALCHEMY_API_KEY=your_api_key_here现在,让我们创建一个名为 blockchain\_data\_fetcher.py 的文件,编写用于获取区块链数据的代码:
import os
from dotenv import load_dotenv
from web3 import Web3
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import time
# Load environment variables from .env file
load_dotenv()
# Connect to Alchemy's Ethereum mainnet endpoint
w3 = Web3(Web3.HTTPProvider(
f"https://eth-mainnet.g.alchemy.com/v2/{os.getenv('ALCHEMY_API_KEY')}"
))
def fetch_historical_data(hours=168): # Default: last week (168 hours)
"""
Fetch historical blockchain data that we'll use as features.
We're collecting:
- Block numbers and timestamps (for temporal ordering)
- Gas used per block (proxy for network activity)
- Transaction counts (proxy for market interest)
These on-chain metrics can signal market conditions before they
appear in price data.
"""
current_block = w3.eth.block_number
# Ethereum produces ~1 block every 12 seconds# So roughly 300 blocks per hour
blocks_per_hour = 300
blocks_to_fetch = hours * blocks_per_hour
# We'll sample every N blocks to avoid excessive API calls# Sampling hourly (every 300 blocks) gives us manageable data
data = []
for i in range(current_block - blocks_to_fetch, current_block, blocks_per_hour):
try:
block = w3.eth.get_block(i)
data.append({
'block_number': i,
'timestamp': block['timestamp'],
'gas_used': block['gasUsed'],
'transaction_count': len(block['transactions'])
})
except Exception as e:
print(f"Error fetching block {i}: {e}")
continue
return pd.DataFrame(data)
# Fetch a week of data
print("Fetching historical blockchain data...")
df = fetch_historical_data(hours=168)
print(f"Retrieved {len(df)} data points")
print(df.head())该脚本使用 web3.py 配合你的 Alchemy API key 连接到 Ethereum 主网。随后根据你所需的时间范围计算需要获取多少个区块——Ethereum 大约 12 秒一个区块,意味着每小时大约产生 300 个区块。为了让数据集保持可管理的规模并避免过多的 API 调用,我们每小时采样一个区块,而不是获取每一个区块。对于每个采样的区块,我们提取 gas 使用量和交易数量作为网络活动的代理指标,然后将所有数据存储到一个 pandas DataFrame 中,方便后续步骤的处理。
这些链上指标通常能在价格数据显现之前,提前提供市场活动的信号。当 gas 使用量激增时,通常意味着交易活动增加、DeFi 交互增多,或发生了重大链上事件——所有这些都可能先于价格波动出现。类似地,交易数量的上升可能预示着人们对 ETH 兴趣的增长,或 DeFi 活动的升温。通过将这些区块链原生信号与传统价格数据一并纳入模型,我们为机器人提供了纯粹基于价格的策略所无法捕捉到的信息。
步骤 2:使用 Alchemy 获取 ETH 价格数据
仅凭区块链数据是不够的:我们还需要实际的价格信息来训练模型。让我们创建一个名为 fetch\_eth\_price.py 的文件,并集成 Alchemy 的 Prices API,该 API 以低延迟提供跨多条链的实时价格。
为什么选择 Alchemy 的 Prices API?
- 统一的提供商:使用相同的 API key、相同的速率限制、统一的计费方式
- 交易所聚合:价格反映了多个交易所的实际市场情况
- 低延迟:针对交易应用进行了优化(典型响应时间低于 100 毫秒)
- 支持多链:同样的 API 结构适用于任何受支持链上的任意代币
import requests
from datetime import datetime, timedelta
def fetch_eth_prices_alchemy(hours=168):
"""
Fetch historical ETH prices using Alchemy's Token Prices API.
This gives us reliable, exchange-aggregated pricing that reflects
actual market conditions across major venues.
"""
# Alchemy's prices endpoint
url = f"https://eth-mainnet.g.alchemy.com/prices/v1/{os.getenv('ALCHEMY_API_KEY')}/tokens/by-symbol"
# Calculate our time window
end_time = datetime.now()
start_time = end_time - timedelta(hours=hours)
params = {
'symbols': 'ETH',
'startTime': int(start_time.timestamp()),
'endTime': int(end_time.timestamp()),
'interval': '1h' # Hourly price points
}
headers = {
'Accept': 'application/json'
}
response = requests.get(url, params=params, headers=headers)
if response.status_code == 200:
data = response.json()
prices = data['data'][0]['prices']
# Convert to DataFrame format
price_data = []
for price_point in prices:
price_data.append({
'timestamp': datetime.fromtimestamp(price_point['timestamp']),
'price': price_point['value']
})
return pd.DataFrame(price_data)
else:
raise Exception(f"Failed to fetch prices: {response.status_code} - {response.text}")
# Fetch prices
print("Fetching ETH price data from Alchemy...")
price_df = fetch_eth_prices_alchemy(hours=168)
# Ensure timestamps are datetime objects for merging
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s')
# Merge blockchain data with price data# merge_asof handles slight timestamp mismatches by finding nearest match
df = pd.merge_asof(
df.sort_values('timestamp'),
price_df.sort_values('timestamp'),
on='timestamp',
direction='nearest'
)
print(f"Merged data shape: {df.shape}")
print(df.head())该脚本在与我们的区块链数据相同的时间窗口内(默认 168 小时),从 Alchemy 的 Token Prices API 获取历史 ETH 价格。我们定义起止时间,请求每小时一个的价格点,并将响应解析为包含时间戳和价格值的 pandas DataFrame。
最后一步的关键在于将这份价格数据与步骤 1 中的区块链数据进行合并。我们使用 merge\_asof 而不是标准的合并方式,因为区块数据和价格数据的时间戳不会完全对齐——merge\_asof 会为每一行找到最接近的匹配时间戳,确保不会因为微小的时间差异而丢失数据。完成这一步后,我们就得到了一个统一的 DataFrame,同时包含链上指标(gas 使用量、交易数量)和价格数据,可以用于下一步的特征工程。
步骤 3:为机器学习设计特征
现在我们已经获得了原始数据,需要将其转化为能够捕捉模型可学习模式的特征。这正是领域知识与数据科学相结合的地方。
def engineer_features(df):
"""
Transform raw data into predictive features.
We're creating two types of features:
1. Price-based technical indicators (moving averages, volatility)
2. On-chain sentiment proxies (gas and transaction trends)
The goal is to give the model multiple perspectives on market conditions.
"""
# ============================================# PRICE-BASED FEATURES# ============================================
# Percentage change from previous hour# Captures momentum - is price accelerating up or down?
df['price_change'] = df['price'].pct_change()
# Moving averages - smooth out noise, identify trends
df['price_ma_12'] = df['price'].rolling(window=12).mean() # 12-hour
df['price_ma_24'] = df['price'].rolling(window=24).mean() # 24-hour
# When short-term MA crosses above long-term MA = bullish signal# When it crosses below = bearish signal
# Volatility - standard deviation of recent price changes# High volatility = risky/unstable market
df['volatility'] = df['price_change'].rolling(window=12).std()
# ============================================# ON-CHAIN SENTIMENT FEATURES# ============================================
# Gas usage trend - are people paying more to transact?# Spikes often precede price movements
df['gas_trend'] = df['gas_used'].pct_change()
# Transaction count trend - is activity increasing?# More transactions = more interest = potential price catalyst
df['tx_trend'] = df['transaction_count'].pct_change()
# ============================================# MOMENTUM INDICATORS# ============================================
# Price change over last 6 hours# Positive momentum = upward trajectory
df['momentum'] = df['price'] - df['price'].shift(6)
# ============================================# TARGET VARIABLE# ============================================
# What we're trying to predict: will price go up in the next hour?# 1 = yes (buy signal), 0 = no (sell/hold signal)
df['target'] = (df['price'].shift(-1) > df['price']).astype(int)
# Drop rows with NaN values (from rolling windows and shifts)
df = df.dropna()
return df
df = engineer_features(df)
print(f"\nEngineered features: {df.columns.tolist()}")
print(f"Data shape: {df.shape}")
print(f"\nSample of engineered data:")
print(df[['price', 'price_change', 'volatility', 'momentum', 'target']].head())这个函数将我们的原始区块链和价格数据转换为机器学习模型可用于做出预测的特征。每个特征都捕捉了关于市场状况的不同信号,有些源自价格波动,有些源自链上活动。以下是每个特征所代表的含义,以及它们为何对预测价格方向很重要:
- 价格变化(
pct\_change):将绝对价格变动转换为百分比。从 2,000 美元涨到 2,020 美元是 1% 的涨幅——这比简单地说“上涨 20 美元”更有意义,也更便于在不同价格水平之间比较。百分比对不同价格水平上的变化进行了归一化处理。 - 移动平均线(12 小时和 24 小时):这些指标能够平滑短期价格噪音,揭示潜在趋势。当短期均线上穿长期均线时,传统上被解读为看涨信号;下穿则暗示看跌动能。模型可以学习这些交叉模式。
- 波动率:以近期价格变化的标准差来衡量。高波动率表明市场不稳定,价格波动幅度更大——风险更高,但潜在回报也可能更高。有些策略会回避波动剧烈的时期,而另一些则专门针对这些时期。
- Gas 和交易趋势:可能领先于价格变动的链上指标。如果 gas 使用量突然激增,可能意味着正在发生一些重大事件(大型 NFT 发售、DeFi 漏洞利用、巨鲸活动),这些事件可能在体现于交易数据之前就已影响 ETH 价格。
- 动量:一个简单但有效的指标,用于判断过去 6 小时内价格是否呈上升趋势。正动量表明可能会继续上涨;负动量表明可能会下跌。动量交易者利用这些信号来顺势而为。
- 目标变量:这是我们训练模型要预测的内容:下一小时的价格是否会高于当前价格?值为 1 表示会(潜在买入信号),0 表示不会(潜在卖出或持有信号)。这种二元分类方法简化了预测问题。
步骤 4:训练机器学习模型
现在我们训练一个模型,从我们设计的特征中学习模式。我们使用 Random Forest:一种对噪声数据具有较强鲁棒性、且不需要大量超参数调优的集成方法。
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score, classification_report
# Select the features we engineered
feature_columns = [
'price_change', 'price_ma_12', 'price_ma_24', 'volatility',
'gas_trend', 'tx_trend', 'momentum'
]
X = df[feature_columns]
y = df['target']
# Split data: 80% for training, 20% for testing# CRITICAL: shuffle=false to avoid look-ahead bias# in time series, future data can't inform past predictions
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, shuffle=False
)
print(f"Training samples: {len(X_train)}")
print(f"Testing samples: {len(X_test)}")
# Initialize random forest classifier
model = RandomForestClassifier(
n_estimators=100, # 100 decision trees in the forest
max_depth=10, # Prevent trees from growing too deep (overfitting)
random_state=42, # For reproducibility
class_weight='balanced' # Handle imbalanced classes (more ups than downs or vice versa)
)
print("\nTraining model...")
model.fit(X_train, y_train)
print("✓ Model trained")
# ============================================# EVALUATE ON TEST set# ============================================
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"\n{'='*50}")
print(f"TEST SET PERFORMANCE")
print(f"{'='*50}")
print(f"Accuracy: {accuracy:.2%}")
print(f"\nDetailed Classification Report:")
print(classification_report(y_test, y_pred, target_names=['Down', 'Up']))
# ============================================# CROSS-validation# ============================================# cross-validation gives us more robust performance estimates# by training/testing on multiple data splits
cv_scores = cross_val_score(model, X_train, y_train, cv=5)
print(f"\nCross-validation scores: {cv_scores}")
print(f"Average CV score: {cv_scores.mean():.2%} (+/- {cv_scores.std():.2%})")
# ============================================# FEATURE importance# ============================================# random forests tell us which features mattered most
feature_importance = pd.DataFrame({
'feature': feature_columns,
'importance': model.feature_importances_
}).sort_values('importance', ascending=False)
print(f"\n{'='*50}")
print("FEATURE IMPORTANCE")
print(f"{'='*50}")
print(feature_importance)该脚本在我们上一步设计的特征上训练一个 Random Forest 分类器。我们将数据划分为训练集(80%)和测试集(20%),并使用 shuffle=False 以保留时间顺序。这对时间序列数据至关重要,因为我们不能让未来的信息泄露到过去的预测中。模型从训练数据中学习模式,然后对它之前未见过的测试集进行预测。我们还进行了交叉验证,即在多个不同的数据划分上进行训练和测试,以检验我们的结果是稳定的还是纯属巧合。
解读结果
机器学习模型会输出大量指标,正确解读这些指标对于判断你的机器人是否具备可行的策略至关重要。以下是每个输出的含义以及需要关注的重点:
- 准确率:正确预测所占的百分比。在交易中,55%-60% 的准确率实际上已经相当不错——市场本质上就是嘈杂且难以预测的。不要期待 90% 以上的准确率。如果你看到如此高的数字,你的模型很可能存在过拟合,或者存在数据泄露问题。
- 分类报告:该报告分别展示了两个预测类别(上涨和下跌)的表现。精确率(Precision)告诉你当模型预测“上涨”时的正确概率——这一点很重要,因为误报意味着糟糕的交易。召回率(Recall)告诉你模型捕捉到了实际“上涨”走势中的百分之多少——这一点很重要,因为它关系到是否会错失机会。F1 分数是两者的调和平均值,能给你一个平衡的表现视图。
- 交叉验证分数:在数据的不同子集上进行训练,可以揭示你的模型表现是否稳定,还是会因所用的具体数据点不同而出现剧烈波动。各折之间分数一致,说明策略较为稳健;方差较大,则说明模型可能学到的是噪声,而非真实的模式。
- 特征重要性:Random Forest 会告诉你哪些特征对预测的贡献最大。如果
momentum的重要性最高,说明你的策略主要由动量驱动。如果volatility占主导,说明你的交易主要基于市场的不稳定性。这一洞察有助于你理解模型实际在做什么,以及它是否与你的交易理论相符。
什么样的结果算“好”?
对于一个交易模型,你需要关注的是:准确率高于 55%(优于随机猜测的 50%)、训练集和测试集的表现相近(说明模型没有过拟合),以及交叉验证分数保持一致(说明该策略在不同市场条件下具有稳健性)。如果你的测试准确率明显低于训练准确率,说明模型记住了训练数据,而没有学到可泛化的模式。
步骤 5:实现实时交易逻辑
现在让我们构建机器人的主循环:获取当前数据、做出预测并执行交易的逻辑。
def fetch_current_data():
"""
Fetch the most recent data point for making a prediction.
In production, this runs every N minutes to stay current.
"""
# Get latest block from blockchain
current_block = w3.eth.block_number
block = w3.eth.get_block(current_block)
# Get current ETH price (using Alchemy Prices API)
price_url = f"https://eth-mainnet.g.alchemy.com/prices/v1/{os.getenv('ALCHEMY_API_KEY')}/tokens/by-symbol"
price_response = requests.get(
price_url,
params={'symbols': 'ETH'},
headers={'Accept': 'application/json'}
)
current_price = price_response.json()['data'][0]['prices'][0]['value']
return {
'block_number': current_block,
'timestamp': datetime.now(),
'gas_used': block.gas_used,
'transaction_count': len(block.transactions),
'price': current_price
}
def prepare_features_for_prediction(current_data, historical_df):
"""
Engineer features from current data point using historical context.
Why we need historical context: Features like moving averages and
momentum require previous data points to calculate.
"""
# Append current data to our historical DataFrame
temp_df = pd.concat([
historical_df,
pd.DataFrame([current_data])
], ignore_index=True)
# Re-run feature engineering to get current features
temp_df = engineer_features(temp_df)
# Return only the latest row (current features)
return temp_df[feature_columns].iloc[-1:].values
def execute_trade(action, amount, current_price):
"""
Execute a trade. Currently simulated—prints trade details.
In production, replace with:
- Exchange API calls (via CCXT)
- Signed onchain transactions sent through Alchemy's Node API
- Order execution with slippage controls
"""
print(f"\n{'='*50}")
print(f"TRADE SIGNAL: {action.upper()}")
print(f"Amount: {amount} ETH")
print(f"Price: ${current_price:,.2f}")
print(f"Est. Value: ${amount * current_price:,.2f}")
print(f"Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'='*50}\n")
# TODO: In production, add real execution:# if action == 'BUY':# exchange.create_market_buy_order('ETH/USD', amount)# elif action == 'SELL':# exchange.create_market_sell_order('ETH/USD', amount)
def run_trading_bot(model, historical_df, interval_seconds=300):
"""
Main bot loop: fetch data, predict, execute trades.
This runs continuously, checking market conditions every N seconds.
"""
print("="*60)
print("AI TRADING BOT STARTED")
print("="*60)
print(f"Checking market every {interval_seconds} seconds")
print(f"Model accuracy: {accuracy:.2%}")
print(f"Press Ctrl+C to stop\n")
# Track bot state
position = None # Current position: 'long', 'short', or None
entry_price = 0
trades_executed = 0
while True:
try:
# ============================================# 1. FETCH CURRENT MARKET DATA# ============================================
current_data = fetch_current_data()
current_price = current_data['price']
# ============================================# 2. PREPARE FEATURES & MAKE PREDICTION# ============================================
features = prepare_features_for_prediction(current_data, historical_df)
prediction = model.predict(features)[0]
prediction_proba = model.predict_proba(features)[0]
# Display current state
print(f"[{datetime.now().strftime('%H:%M:%S')}] Price: ${current_price:,.2f} | "
f"Prediction: {'UP' if prediction == 1 else 'DOWN'} "
f"(Confidence: {prediction_proba[prediction]:.1%}) | "
f"Position: {position or 'None'}")
# ============================================# 3. TRADING LOGIC WITH CONFIDENCE THRESHOLD# ============================================
# Only trade when model is confident (>60%)
confidence_threshold = 0.6
# BUY SIGNAL: Predict UP with high confidence, no position
if prediction == 1 and prediction_proba[1] > confidence_threshold:
if position != 'long':
execute_trade('BUY', 0.1, current_price)
position = 'long'
entry_price = current_price
trades_executed += 1
# SELL SIGNAL: Predict DOWN with high confidence, have long position
elif prediction == 0 and prediction_proba[0] > confidence_threshold:
if position == 'long':
profit_pct = ((current_price - entry_price) / entry_price) * 100
print(f"Closing long position. Profit: {profit_pct:+.2f}%")
execute_trade('SELL', 0.1, current_price)
position = None
trades_executed += 1
# ============================================# 4. UPDATE HISTORICAL DATA (ROLLING WINDOW)# ============================================
historical_df = pd.concat([
historical_df,
pd.DataFrame([current_data])
], ignore_index=True).tail(168) # Keep last week
# ============================================# 5. WAIT BEFORE NEXT CHECK# ============================================
time.sleep(interval_seconds)
except KeyboardInterrupt:
print(f"\n{'='*60}")
print("BOT STOPPED BY USER")
print(f"Total trades executed: {trades_executed}")
print(f"{'='*60}")
break
except Exception as e:
print(f"ERROR: {e}")
print("Retrying in 60 seconds...")
time.sleep(60)
# Run the bot (check every 5 minutes)
run_trading_bot(model, df, interval_seconds=300)这一步将所有内容整合成一个功能完整的交易机器人。代码定义了四个按顺序运作的主要函数:fetch_current_data 从 Alchemy 拉取最新的区块链指标和 ETH 价格,prepare_features_for_prediction 将原始数据转换为与模型训练时相同的特征,execute_trade 负责实际的买卖执行(此处为模拟,但已为生产环境集成做好准备),run_trading_bot 则在一个持续运行的循环中协调所有环节,每 5 分钟检查一次市场状况。
主交易循环遵循一个直接明了的周期:获取当前数据、生成特征、做出预测、根据置信度阈值决定是否交易、更新历史数据,然后等待后再重复。以下是内置在该循环中的几项关键设计决策:
- 置信度阈值:只有当模型对预测的置信度超过 60% 时,机器人才会执行交易。这可以过滤掉更可能是噪声而非真实机会的弱信号。你可以根据自己的风险承受能力调整这一阈值——阈值越高,交易次数越少,但筛选也更严格。
- 仓位跟踪:机器人会持续掌握自身当前的状态(多头、空头或空仓)。这可以防止诸如在已持有 ETH 时反复买入,或在没有任何持仓时进行卖出这类不合逻辑的行为。
- 滚动窗口:历史数据被限制在最近 168 小时(一周)以内。这可以防止长时间运行过程中出现内存问题,并确保机器人的特征计算始终与当前市场状况保持相关,而不会因为陈旧数据而产生偏差。
- 错误处理:try/except 代码块确保临时性故障(API 超时、网络问题、速率限制)不会导致整个机器人崩溃。相反,错误会被记录下来,机器人会在短暂暂停后重试。
- 优雅关闭:按下 Ctrl+C 可以干净地停止机器人,并打印汇总统计信息,让你无需丢失状态信息即可查看表现。
为什么选择 5 分钟的间隔?这一默认值在响应速度、API 速率限制和计算开销之间取得了平衡。你可以根据自己的策略进行调整:高频策略可能需要每隔几秒钟检查一次,而波段交易策略可能只需要每小时更新一次。间隔越短,能捕捉到的机会越多,但也会消耗更多的 API 调用次数,并要求更快的执行基础设施。
步骤 6:使用 Alchemy 添加链上情绪分析
价格和技术指标只能说明部分情况。在加密领域,链上活动——尤其是“巨鲸”的大额转账——往往能在价格数据显现之前,预示即将到来的价格波动。巨鲸将 ETH 转入交易所通常意味着存在抛售压力,而将 ETH 转出交易所则暗示正在积累。通过实时监控这些转账,你的机器人可以在价格反映相关活动之前,获得几秒钟或几分钟的提前预警。
这一步将巨鲸监控作为交易机器人的额外输入层加入进来。
在接下来的两段代码块中,我们首先会在每个区块上轮询 Alchemy,获取新的 WETH 转账,筛选出超过设定阈值(100 ETH)的转账,并根据资金是流入还是流出已知交易所地址对其进行分类。普通的 ETH 转账不会触发事件,因此 WETH Transfer 事件是追踪大额 ETH 转移的一种实用替代方案。
在第二段代码块中,我们将展示如何将巨鲸活动数据输入到你现有的交易逻辑中,根据巨鲸看起来是在买入还是卖出来调整置信度阈值。
设置巨鲸转账监控:
def monitor_whale_activity():
"""
Monitor large WETH transfers as sentiment signals using Alchemy's Node API.
Why this matters:
- Whales moving ETH to exchanges often signals selling pressure
- Whales moving ETH off exchanges signals accumulation (bullish)
- Large transfers between wallets can indicate OTC deals or fund movements
This real-time data can give you seconds or minutes of advance warning
before price reflects the activity.
"""
# Define what constitutes a "whale" transaction
WHALE_THRESHOLD = 100 # 100 ETH (~$200K-400K depending on price)
# Known exchange addresses (for context)
EXCHANGE_ADDRESSES = {
'0x3f5ce5fbfe3e9af3971dd833d26ba9b5c936f0be': 'Binance',
'0x28c6c06298d514db089934071355e5743bf21d60': 'Binance 2',
'0x21a31ee1afc51d94c2efccaa2092ad1028285549': 'Binance 3',
'0xdfd5293d8e347dfe59e90efd55b2956a1343963d': 'Binance 4',
'0x56eddb7aa87536c09ccc2793473599fd21a8b17f': 'Binance 5',
'0x9696f59e4d72e237be84ffd425dcad154bf96976': 'Binance 6',
'0x4e9ce36e442e55ecd9025b9a6e0d88485d628a67': 'Binance 7',
'0xbe0eb53f46cd790cd13851d5eff43d12404d33e8': 'Binance 8',
'0xf977814e90da44bfa03b6295a0616a897441acec': 'Binance 9',
'0x001866ae5b3de6caa5a51543fd9fb64f524f5478': 'Coinbase 1',
'0x71660c4005ba85c37ccec55d0c4493e66fe775d3': 'Coinbase 2',
'0x503828976d22510aad0201ac7ec88293211d23da': 'Coinbase 3',
'0xddfabcdc4d8ffc6d5beaf154f18b778f892a0740': 'Coinbase 4',
'0x3cd751e6b0078be393132286c442345e5dc49699': 'Coinbase 5',
'0xb5d85cbf7cb3ee0d56b3bb207d5fc4b82f43f511': 'Coinbase 6',
'0xeb2629a2734e272bcc07bda959863f316f4bd4cf': 'Coinbase 7',
}
def handle_transfer(event):
"""
Process each transfer event as it happens.
"""
try:
# Extract transfer details
value_wei = int.from_bytes(event['data'], 'big')
value_eth = value_wei / 1e18
from_addr = '0x' + event['topics'][1].hex()[-40:]
to_addr = '0x' + event['topics'][2].hex()[-40:]
tx_hash = event['transactionHash'].to_0x_hex()
# Only process whale-sized transfers
if value_eth >= WHALE_THRESHOLD:
# Determine transfer context
from_exchange = EXCHANGE_ADDRESSES.get(from_addr, None)
to_exchange = EXCHANGE_ADDRESSES.get(to_addr, None)
# Build alert message
alert = f"\n🐋 WHALE ALERT: {value_eth:.2f} ETH"
if from_exchange and not to_exchange:
# Moving OFF exchange = potential buying/holding
alert += f"\n📤 From {from_exchange} to private wallet"
alert += "\n💡 Signal: BULLISH (accumulation)"
elif not from_exchange and to_exchange:
# Moving TO exchange = potential selling
alert += f"\n📥 From private wallet to {to_exchange}"
alert += "\n💡 Signal: BEARISH (potential sell pressure)"
elif from_exchange and to_exchange:
# Exchange to exchange = arbitrage or OTC
alert += f"\n🔄 From {from_exchange} to {to_exchange}"
alert += "\n💡 Signal: NEUTRAL (arbitrage or OTC)"
else:
# Wallet to wallet = unknown intent
alert += f"\n↔️ Between private wallets"
alert += "\n💡 Signal: UNCLEAR (monitor for pattern)"
alert += f"\nTx: https://etherscan.io/tx/{tx_hash}"
print(alert)
# TODO: In production, you might:# - Adjust trading thresholds based on whale activity# - Increase position size if whales are accumulating# - Exit positions early if whales are dumping# - Log whale activity for later analysis
except Exception as e:
print(f"Error processing whale transfer: {e}")
# WETH contract and the Transfer(address,address,uint256) event signature
WETH_ADDRESS = Web3.to_checksum_address('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2')
TRANSFER_TOPIC = Web3.keccak(text="Transfer(address,address,uint256)").to_0x_hex()
print("\n" + "="*60)
print("WHALE ACTIVITY MONITOR STARTED")
print("="*60)
print(f"Tracking transfers ≥ {WHALE_THRESHOLD} ETH")
print("Press Ctrl+C to stop\n")
last_block = w3.eth.block_number
while True:
try:
latest_block = w3.eth.block_number
if latest_block > last_block:
logs = w3.eth.get_logs({
'address': WETH_ADDRESS,
'topics': [TRANSFER_TOPIC],
'fromBlock': last_block + 1,
'toBlock': latest_block,
})
for log in logs:
handle_transfer(log)
last_block = latest_block
except Exception as e:
print(f"Whale monitor error: {e}")
time.sleep(12) # Ethereum produces a block roughly every 12 seconds
# Run whale monitor in a separate thread so it doesn't block the main bot
import threading
whale_thread = threading.Thread(target=monitor_whale_activity, daemon=True)
whale_thread.start()
# Now your main trading bot can run alongside the whale monitor# the whale alerts will print in real-time while your bot trades上面的巨鲸监控器负责收集数据,但这些数据需要输入到你的交易机器人中,才能真正影响决策。以下代码展示了如何将巨鲸情绪作为一个持续更新的分数进行跟踪,并据此调整你的置信度阈值——当巨鲸在积累时降低买入门槛,当他们似乎在卖出时提高门槛。
# Add this to your trading bot
whale_sentiment = 0 # Global variable tracking recent whale activity
def update_whale_sentiment(signal_type):
"""
Update sentiment based on whale activity.
+1 for bullish moves, -1 for bearish, 0 for neutral.
"""
global whale_sentiment
if signal_type == 'BULLISH':
whale_sentiment += 1
elif signal_type == 'BEARISH':
whale_sentiment -= 1
# Decay over time so old signals matter less
whale_sentiment *= 0.9
# Modify your trading logic to incorporate whale sentiment
def should_trade(prediction, confidence, whale_sentiment):
"""
Enhanced trading logic that considers both ML prediction and whale activity.
"""
base_threshold = 0.6
# If whales are bullish and model predicts up, lower threshold
if prediction == 1 and whale_sentiment > 2:
threshold = base_threshold - 0.1 # More aggressive buying# If whales are bearish, raise threshold (be more cautious)
elif prediction == 1 and whale_sentiment < -2:
threshold = base_threshold + 0.1 # Less aggressive buying
else:
threshold = base_threshold
return confidence > threshold这两段代码块共同为你的交易机器人增加了一个额外的信号层。第一段代码在后台线程中运行,通过 WebSocket 持续监听大额 ETH 转账,并将每一笔转账分类为看涨(转出交易所)、看跌(转入交易所)或中性。第二段代码根据这些巨鲸活动维护一个持续更新的情绪分数,并据此调整你的交易阈值。
当你的机器学习模型的预测与巨鲸行为一致时——例如,预测价格上涨的同时巨鲸也在积累——组合信号会更强,机器人也会更积极地交易。当信号出现冲突时,机器人则会变得更加谨慎。
这一点之所以重要,是因为机构投资者和大户往往拥有比散户交易者更好的信息或更长的时间视野。大额资金流入或流出交易所会影响可用供应量,可能领先于价格走势数分钟到数小时。通过将链上活动与机器学习模型的预测结合起来,你为机器人提供了比单纯价格数据更为完整的市场图景。
步骤 7:实施风险管理
这可以说是整个教程中最重要的一步。即使是最好的预测模型,如果没有恰当的风险管理,也会亏钱。一个 60% 时间都判断正确的机器人,如果那 40% 的亏损交易得不到控制,仍然可能破产——一笔糟糕的仓位就可能抹去数十笔盈利交易的成果。风险管理承担着几项关键功能:限制单笔交易的最大亏损(止损)、在市场反转前锁定收益(止盈)、防止投资组合灾难性下跌(回撤限制),以及遏制情绪化的过度交易(每日交易次数限制)。下面的代码将所有这些功能实现为一个可复用的 RiskManager 类,可与你的交易机器人集成。
构建 RiskManager 类
以下这个类将所有风险管理逻辑集中在一处。它跟踪你的投资组合价值,监控危险状况,根据置信度计算合适的仓位大小,并记录每一笔交易以供后续分析。
class RiskManager:
"""
Comprehensive risk management for trading bots.
Risk management is what separates profitable bots from bankrupt ones.
Key principles:
1. Never risk more than you can afford to lose
2. Cut losses quickly, let winners run
3. Position size matters more than win rate
4. Track everything for post-mortem analysis
"""
def __init__(self,
initial_capital=10000,
max_position_size=1.0,
max_drawdown=0.15,
stop_loss=0.05,
take_profit=0.10,
max_daily_trades=20):
"""
Initialize risk parameters.
Args:
initial_capital: Starting portfolio value in USD
max_position_size: Maximum ETH per trade
max_drawdown: Max portfolio decline before pausing (15% = 0.15)
stop_loss: Per-trade loss limit (5% = 0.05)
take_profit: Per-trade profit target (10% = 0.10)
max_daily_trades: Prevent overtrading
"""
self.initial_capital = initial_capital
self.portfolio_value = initial_capital
self.peak_value = initial_capital
self.max_position_size = max_position_size
self.max_drawdown = max_drawdown
self.stop_loss = stop_loss
self.take_profit = take_profit
self.max_daily_trades = max_daily_trades
self.trades = []
self.daily_trades = 0
self.last_trade_date = datetime.now().date()
self.trading_paused = False
def check_drawdown(self):
"""
Pause trading if drawdown exceeds threshold.
Drawdown is measured from peak portfolio value.
This prevents catastrophic losses during bad market conditions.
"""
current_drawdown = (self.peak_value - self.portfolio_value) / self.peak_value
if current_drawdown >= self.max_drawdown:
self.trading_paused = True
print(f"\n{'='*60}")
print(f"⚠️ MAX DRAWDOWN REACHED: {current_drawdown:.2%}")
print(f"Portfolio: ${self.portfolio_value:,.2f} (down from ${self.peak_value:,.2f})")
print(f"Trading PAUSED. Manual review required.")
print(f"{'='*60}\n")
return False
return True
def calculate_position_size(self, confidence, current_price):
"""
Adjust position size based on prediction confidence and portfolio size.
This implements a simplified Kelly Criterion approach:
- Higher confidence = larger position
- Never exceed max position size
- Scale down if portfolio has shrunk
Args:
confidence: Model's prediction probability (0-1)
current_price: Current ETH price for value calculation
Returns:
Position size in ETH
"""
# Base size scaled by confidence# At 60% confidence: 0.6 * max_size# At 90% confidence: 0.9 * max_size
base_size = self.max_position_size * confidence
# Scale down if portfolio has lost value
portfolio_scale = self.portfolio_value / self.initial_capital
adjusted_size = base_size * portfolio_scale
# Never exceed max position size
final_size = min(adjusted_size, self.max_position_size)
# Verify we can afford this trade
trade_value = final_size * current_price
if trade_value > self.portfolio_value * 0.95: # Never use >95% of portfolio
final_size = (self.portfolio_value * 0.95) / current_price
return round(final_size, 4) # Round to 4 decimals
def check_stop_loss(self, entry_price, current_price, position_type):
"""
Check if stop loss is triggered for current position.
Stop losses protect against large individual trade losses.
Even if your model is right 60% of the time, the 40% losers
can wipe you out without stops.
"""
if position_type == 'long':
loss = (entry_price - current_price) / entry_price
if loss >= self.stop_loss:
print(f"\n🛑 STOP LOSS TRIGGERED")
print(f"Entry: ${entry_price:,.2f} → Current: ${current_price:,.2f}")
print(f"Loss: {loss:.2%}")
return True
return False
def check_take_profit(self, entry_price, current_price, position_type):
"""
Check if take profit target is reached.
Taking profits locks in gains and prevents giving back winnings
if the market reverses.
"""
if position_type == 'long':
profit = (current_price - entry_price) / entry_price
if profit >= self.take_profit:
print(f"\n🎯 TAKE PROFIT TARGET REACHED")
print(f"Entry: ${entry_price:,.2f} → Current: ${current_price:,.2f}")
print(f"Profit: {profit:.2%}")
return True
return False
def check_daily_limit(self):
"""
Prevent overtrading by limiting daily trades.
Overtrading leads to:
- Death by a thousand fees
- Emotional decision-making
- Curve-fitting to noise rather than signal
"""
today = datetime.now().date()
# Reset counter at start of new day
if today != self.last_trade_date:
self.daily_trades = 0
self.last_trade_date = today
if self.daily_trades >= self.max_daily_trades:
print(f"⚠️ Daily trade limit reached ({self.max_daily_trades})")
return False
return True
def can_trade(self):
"""
Master check: Can we trade right now?
"""
if self.trading_paused:
return False
if not self.check_drawdown():
return False
if not self.check_daily_limit():
return False
return True
def record_trade(self, trade_type, price, amount, profit_loss=0):
"""
Track all trades for analysis and performance monitoring.
This data is gold for:
- Understanding what's working/not working
- Tax reporting
- Strategy refinement
- Performance attribution
"""
self.trades.append({
'timestamp': datetime.now(),
'type': trade_type,
'price': price,
'amount': amount,
'value': price * amount,
'profit_loss': profit_loss,
'portfolio_value': self.portfolio_value
})
# Update portfolio value
self.portfolio_value += profit_loss
self.peak_value = max(self.peak_value, self.portfolio_value)
# Increment daily trade counter
self.daily_trades += 1
def get_performance_stats(self):
"""
Calculate comprehensive performance metrics.
"""
if not self.trades:
return "No trades executed yet"
df = pd.DataFrame(self.trades)
# Separate buys and sells
buys = df[df['type'] == 'BUY']
sells = df[df['type'] == 'SELL']
# Calculate returns
total_return = ((self.portfolio_value - self.initial_capital) / self.initial_capital) * 100
# Win rate (profitable trades / total trades)
profitable_trades = len(sells[sells['profit_loss'] > 0])
total_closed_trades = len(sells)
win_rate = (profitable_trades / total_closed_trades * 100) if total_closed_trades > 0 else 0
# Average profit per winning trade
avg_win = sells[sells['profit_loss'] > 0]['profit_loss'].mean() if profitable_trades > 0 else 0
# Average loss per losing trade
losing_trades = sells[sells['profit_loss'] < 0]
avg_loss = losing_trades['profit_loss'].mean() if len(losing_trades) > 0 else 0
# Profit factor (total wins / total losses)
total_wins = sells[sells['profit_loss'] > 0]['profit_loss'].sum()
total_losses = abs(sells[sells['profit_loss'] < 0]['profit_loss'].sum())
profit_factor = total_wins / total_losses if total_losses > 0 else float('inf')
# Current drawdown
current_drawdown = ((self.peak_value - self.portfolio_value) / self.peak_value) * 100
stats = f"""
{'='*60}
PERFORMANCE STATISTICS
{'='*60}
Portfolio Value: ${self.portfolio_value:,.2f}
Initial Capital: ${self.initial_capital:,.2f}
Total Return: {total_return:+.2f}%
Peak Value: ${self.peak_value:,.2f}
Current Drawdown: {current_drawdown:.2f}%
Trading Activity:
- Total Trades: {len(self.trades)}
- Closed Trades: {total_closed_trades}
- Win Rate: {win_rate:.1f}%
- Profitable Trades: {profitable_trades}
- Losing Trades: {len(losing_trades)}
Trade Quality:
- Average Win: ${avg_win:,.2f}
- Average Loss: ${avg_loss:,.2f}
- Profit Factor: {profit_factor:.2f}x
- Total Wins: ${total_wins:,.2f}
- Total Losses: ${total_losses:,.2f}
Risk Status:
- Trading Paused: {self.trading_paused}
- Daily Trades: {self.daily_trades}/{self.max_daily_trades}
{'='*60}
"""
return stats
# Initialize risk manager
risk_manager = RiskManager(
initial_capital=10000,
max_position_size=0.5, # 0.5 ETH max per trade
max_drawdown=0.15, # Stop at 15% portfolio loss
stop_loss=0.03, # 3% stop loss per trade
take_profit=0.06, # 6% take profit target
max_daily_trades=15 # Max 15 trades per day
)RiskManager 类将所有风险控制集中到一个单一的、可复用的组件中。初始化时,你需要定义各项风险参数:初始资金、每笔交易的最大仓位规模、触发交易暂停的投资组合回撤百分比、单笔交易的止损和止盈阈值,以及防止过度交易的每日交易次数限制。
该类提供了几个关键方法。check\_drawdown 监控你的投资组合是否较其峰值下跌过多,并在触及阈值时自动暂停交易——这可以防止连续亏损耗尽你的全部账户资金。calculate\_position\_size 实现了一种简化版的凯利公式方法,根据模型置信度确定仓位大小(置信度越高,仓位越大),同时在投资组合已经出现亏损时按比例缩减。
check\_stop\_loss 和 check\_take\_profit 监控未平仓仓位,并在价格超出你设定的阈值时触发平仓。record\_trade 记录每一笔交易以供后续分析,get\_performance\_stats 则计算胜率、盈利因子和当前回撤等综合指标。
将风险管理集成到你的机器人中
在定义好 RiskManager 类之后,下一步是将其接入你的主交易循环。以下代码修改了步骤 5 中的机器人,使其在每次交易前检查风险限制,基于置信度使用动态仓位大小,并在触及止损或止盈水平时自动退出仓位。
# Modified trading loop with risk management
def run_trading_bot_with_risk_management(model, historical_df, risk_manager, interval_seconds=300):
"""
Enhanced trading bot with comprehensive risk management.
"""
print("="*60)
print("AI TRADING BOT WITH RISK MANAGEMENT")
print("="*60)
print(f"Initial Capital: ${risk_manager.initial_capital:,.2f}")
print(f"Max Position: {risk_manager.max_position_size} ETH")
print(f"Stop Loss: {risk_manager.stop_loss:.1%}")
print(f"Max Drawdown: {risk_manager.max_drawdown:.1%}")
print("="*60 + "\n")
position = None
entry_price = 0
position_size = 0
while True:
try:
# Check if we can trade
if not risk_manager.can_trade():
print("Trading paused due to risk limits")
time.sleep(interval_seconds)
continue
# Fetch data and predict
current_data = fetch_current_data()
current_price = current_data['price']
features = prepare_features_for_prediction(current_data, historical_df)
prediction = model.predict(features)[0]
prediction_proba = model.predict_proba(features)[0]
confidence = prediction_proba[prediction]
# Display status
print(f"[{datetime.now().strftime('%H:%M:%S')}] "
f"Price: ${current_price:,.2f} | "
f"Prediction: {'UP' if prediction == 1 else 'DOWN'} ({confidence:.1%}) | "
f"Portfolio: ${risk_manager.portfolio_value:,.2f} | "
f"Position: {position or 'None'}")
# Check stop loss and take profit for open positions
if position == 'long':
if risk_manager.check_stop_loss(entry_price, current_price, 'long'):
# STOP LOSS HIT
loss = (entry_price - current_price) * position_size
execute_trade('SELL (Stop Loss)', position_size, current_price)
risk_manager.record_trade('SELL', current_price, position_size, loss)
position = None
continue
elif risk_manager.check_take_profit(entry_price, current_price, 'long'):
# TAKE PROFIT HIT
profit = (current_price - entry_price) * position_size
execute_trade('SELL (Take Profit)', position_size, current_price)
risk_manager.record_trade('SELL', current_price, position_size, profit)
position = None
continue
# Regular trading logic
if prediction == 1 and confidence > 0.6:
if position != 'long':
# Calculate position size based on confidence
position_size = risk_manager.calculate_position_size(confidence, current_price)
execute_trade('BUY', position_size, current_price)
risk_manager.record_trade('BUY', current_price, position_size)
position = 'long'
entry_price = current_price
elif prediction == 0 and confidence > 0.6:
if position == 'long':
# Close position
profit = (current_price - entry_price) * position_size
execute_trade('SELL', position_size, current_price)
risk_manager.record_trade('SELL', current_price, position_size, profit)
position = None
# Update historical data
historical_df = pd.concat([
historical_df,
pd.DataFrame([current_data])
], ignore_index=True).tail(168)
time.sleep(interval_seconds)
except KeyboardInterrupt:
print("\n" + risk_manager.get_performance_stats())
break
except Exception as e:
print(f"ERROR: {e}")
time.sleep(60)
# Run bot with risk management
run_trading_bot_with_risk_management(model, df, risk_manager, interval_seconds=300)与步骤 5 中的基础版本相比,这个增强版交易循环增加了几层防护。在每次迭代之前,机器人都会检查 risk_manager.can_trade\(\),以确认没有触发任何风险限制——如果投资组合已达到最大回撤,或每日交易次数限额已用尽,交易会自动暂停。
对于未平仓仓位,机器人会持续监控是否触及止损或止盈阈值,一旦触发就会立即平仓,无需等待模型生成新的信号。仓位大小现在是动态的,由风险管理器根据模型置信度和当前投资组合价值计算得出,而不是使用固定金额。
最终得到的机器人能够在连续亏损期间保护资金,自动锁定利润,并根据自身表现动态调整风险敞口。当你停止机器人时,它会打印出全面的绩效统计信息,包括总回报率、胜率、平均盈亏幅度和盈利因子——为你评估和完善策略提供所需的数据。
步骤 8:回测你的策略
在动用真实资金之前,先在历史数据上回测你的策略。这将揭示你的机器人在不同市场条件下会有怎样的表现。
以下函数会针对历史数据模拟你整个交易策略的运行,包括真实的手续费和滑点估算、止损止盈的执行,以及详细的绩效跟踪。它会输出关键指标,并生成一张权益曲线图,展示你的投资组合价值随时间演变的情况。
def backtest_strategy(model, df, risk_manager, initial_capital=10000):
"""
Comprehensive backtest with risk management.
Backtesting answers critical questions:
- Would this strategy have been profitable?
- What's the maximum drawdown I need to stomach?
- How many trades does it generate?
- Does it work in different market conditions?
CRITICAL: Backtests are optimistic. Real trading includes:
- Slippage (getting worse prices than expected)
- Fees (exchange commissions, gas costs)
- Execution delays (orders take time to fill)
- Market impact (your trades affect prices)
Assume real performance will be 20-30% worse than backtest.
"""
print("\n" + "="*60)
print("BACKTESTING STRATEGY")
print("="*60)
print(f"Data points: {len(df)}")
print(f"Time period: {df['timestamp'].min()} to {df['timestamp'].max()}")
print(f"Initial capital: ${initial_capital:,.2f}\n")
# Reset risk manager for clean backtest
capital = initial_capital
position = None
entry_price = 0
position_size = 0
trades = []
portfolio_values = []
# Track statistics
wins = 0
losses = 0
total_fees = 0
max_drawdown = 0
peak_value = initial_capital
# Simulation parameters
FEE_RATE = 0.001 # 0.1% per trade (typical exchange fee)
SLIPPAGE = 0.0005 # 0.05% slippage (market orders get worse prices)
for i in range(len(df)):
if i < 24: # Need history for features
continue
current_price = df['price'].iloc[i]
timestamp = df['timestamp'].iloc[i]
# Get features and prediction
features = df[feature_columns].iloc[i:i+1].values
prediction = model.predict(features)[0]
prediction_proba = model.predict_proba(features)[0]
confidence = prediction_proba[prediction]
# Check stop loss and take profit for open positions
if position == 'long':
current_pnl_pct = (current_price - entry_price) / entry_price
# Stop loss hit
if current_pnl_pct <= -risk_manager.stop_loss:
sell_price = current_price * (1 - SLIPPAGE) # Slippage on market sell
pnl = (sell_price - entry_price) * position_size
fees = sell_price * position_size * FEE_RATE
net_pnl = pnl - fees
capital += (position_size * sell_price) - fees
total_fees += fees
losses += 1
trades.append({
'timestamp': timestamp,
'type': 'SELL (Stop)',
'price': sell_price,
'amount': position_size,
'pnl': net_pnl,
'capital': capital
})
position = None
continue
# Take profit hit
elif current_pnl_pct >= risk_manager.take_profit:
sell_price = current_price * (1 - SLIPPAGE)
pnl = (sell_price - entry_price) * position_size
fees = sell_price * position_size * FEE_RATE
net_pnl = pnl - fees
capital += (position_size * sell_price) - fees
total_fees += fees
wins += 1
trades.append({
'timestamp': timestamp,
'type': 'SELL (Profit)',
'price': sell_price,
'amount': position_size,
'pnl': net_pnl,
'capital': capital
})
position = None
continue
# Regular trading logic
if prediction == 1 and confidence > 0.6:
if position != 'long' and capital > 0:
# BUY
buy_price = current_price * (1 + SLIPPAGE) # Slippage on market buy
position_size = min(
risk_manager.max_position_size,
(capital * 0.95) / buy_price # Use max 95% of capital
)
cost = position_size * buy_price
fees = cost * FEE_RATE
capital -= (cost + fees)
total_fees += fees
entry_price = buy_price
position = 'long'
trades.append({
'timestamp': timestamp,
'type': 'BUY',
'price': buy_price,
'amount': position_size,
'pnl': -fees, # Fees are a loss
'capital': capital
})
elif prediction == 0 and confidence > 0.6:
if position == 'long':
# SELL
sell_price = current_price * (1 - SLIPPAGE)
pnl = (sell_price - entry_price) * position_size
fees = sell_price * position_size * FEE_RATE
net_pnl = pnl - fees
capital += (position_size * sell_price) - fees
total_fees += fees
if net_pnl > 0:
wins += 1
else:
losses += 1
trades.append({
'timestamp': timestamp,
'type': 'SELL',
'price': sell_price,
'amount': position_size,
'pnl': net_pnl,
'capital': capital
})
position = None
# Track portfolio value (including open position)
if position == 'long':
current_value = capital + (position_size * current_price)
else:
current_value = capital
portfolio_values.append({
'timestamp': timestamp,
'value': current_value
})
# Track drawdown
peak_value = max(peak_value, current_value)
current_drawdown = (peak_value - current_value) / peak_value
max_drawdown = max(max_drawdown, current_drawdown)
# Close any open position at end
if position == 'long':
final_price = df['price'].iloc[-1] * (1 - SLIPPAGE)
pnl = (final_price - entry_price) * position_size
fees = final_price * position_size * FEE_RATE
capital += (position_size * final_price) - fees
total_fees += fees
# Calculate final statistics
total_return = ((capital - initial_capital) / initial_capital) * 100
total_trades = len([t for t in trades if t['type'] == 'BUY'])
win_rate = (wins / (wins + losses) * 100) if (wins + losses) > 0 else 0
# Print results
print("\n" + "="*60)
print("BACKTEST RESULTS")
print("="*60)
print(f"\nCapital:")
print(f" Initial: ${initial_capital:,.2f}")
print(f" Final: ${capital:,.2f}")
print(f" Total Return: {total_return:+.2f}%")
print(f" Max Drawdown: {max_drawdown:.2%}")
print(f"\nTrading Activity:")
print(f" Total Trades: {total_trades}")
print(f" Winning Trades: {wins}")
print(f" Losing Trades: {losses}")
print(f" Win Rate: {win_rate:.1f}%")
print(f" Total Fees Paid: ${total_fees:,.2f}")
if wins > 0 and losses > 0:
avg_win = sum(t['pnl'] for t in trades if t['pnl'] > 0) / wins
avg_loss = sum(t['pnl'] for t in trades if t['pnl'] < 0) / losses
profit_factor = abs(sum(t['pnl'] for t in trades if t['pnl'] > 0) /
sum(t['pnl'] for t in trades if t['pnl'] < 0))
print(f"\nTrade Quality:")
print(f" Avg Win: ${avg_win:,.2f}")
print(f" Avg Loss: ${avg_loss:,.2f}")
print(f" Profit Factor: {profit_factor:.2f}x")
print("="*60 + "\n")
# Plot equity curve
import matplotlib.pyplot as plt
pv_df = pd.DataFrame(portfolio_values)
plt.figure(figsize=(12, 6))
plt.plot(pv_df['timestamp'], pv_df['value'])
plt.axhline(y=initial_capital, color='r', linestyle='--', label='Initial Capital')
plt.title('Portfolio Value Over Time (Backtest)')
plt.xlabel('Date')
plt.ylabel('Portfolio Value ($)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('backtest_equity_curve.png')
print("📊 Equity curve saved to 'backtest_equity_curve.png'\n")
return trades, capital
# Run comprehensive backtest
trades, final_capital = backtest_strategy(model, df, risk_manager, initial_capital=10000)这个函数会针对你收集的历史数据,重放你整个交易策略,模拟机器人本会做出的每一笔买卖决策。它遍历数据集中的每一个时间段,使用你训练好的模型生成预测,检查未平仓仓位是否触及止损或止盈阈值,在置信度超过阈值时执行交易,并全程跟踪投资组合价值。
该模拟包含了真实的摩擦成本:每笔交易 0.1% 的手续费(主流交易所的典型水平),以及 0.05% 的滑点(使用市价单时预期成交价与实际成交价之间的差异)。这些看似很小的百分比在大量交易中会迅速累积,这也是该函数要跟踪总手续费支出的原因——手续费往往是原本可盈利策略的隐形杀手。
最后,该函数会输出全面的统计数据,并保存一张权益曲线图,展示你的投资组合价值在整个测试周期内的演变情况。
解读回测结果
回测会输出多项指标,帮助你评估策略是否具备可行性。以下是每项指标的含义以及需要关注的重点:
- 总回报率:你策略的盈利能力。任何高于 0% 的结果都算是盈利,但你应该将这些结果与买入并持有 ETH 的表现进行比较。
- 最大回撤:从峰值到谷底的最严重跌幅。如果你无法承受 15% 的亏损,就不应该运行这一策略。
- 胜率:盈利交易所占的百分比。如果你的盈利幅度大于亏损幅度,即使胜率低于 50%,你仍然可以实现盈利。
- 盈利因子:总盈利 / 总亏损。高于 1.5 倍通常算不错,低于 1.0 倍则意味着你在亏钱。
- 总手续费:往往是隐形杀手。高频策略在扣除手续费之前可能是盈利的,但扣除后却可能变成亏损。
现实检验:如果你的回测显示 100% 以上的回报率,你很可能存在某种 bug(前瞻性偏差、过拟合等)。由于滑点、手续费、执行延迟以及不可预见的事件,真实交易的表现会比回测更差。
恭喜——如果你运行了这套代码,就应该能看到自己已经构建出了一个功能完整的 AI 交易机器人!
你已经构建了什么
现在你拥有了一个可以运行的交易机器人,它能够:
- 使用 Alchemy 的基础设施获取实时区块链数据
- 整合多种数据来源:价格、链上指标、巨鲸活动
- 使用机器学习预测短期价格走势
- 通过止损、仓位规模控制和回撤限制来管理风险
- 可以在上线前通过回测来验证策略
这是一个初级但完整的系统。它展示了任何 AI 交易机器人从数据收集到执行的核心工作流程。
重要提示与警告
在启动你的 AI 交易机器人之前,请留意以下事项,以保护你的资金:
- 从模拟交易开始:先用模拟订单运行你的机器人至少一个月。跟踪假设情境下的表现,以便在不冒真实资金风险的情况下发现 bug 并完善策略。
- 使用小仓位:真正上线时,先投入你预定资金规模的 10%-20%。即使经过充分测试的机器人,在生产环境中也可能出现意外行为。
- 持续监控:尤其是在最初几周,密切关注你的机器人。为异常行为(交易次数过多、大额亏损、错误)设置警报。
- 设置自动化熔断开关:内置机制,在触及关键阈值(每日最大亏损、异常波动激增或系统错误)时自动停止交易。市场可能比你手动干预的速度更快地转向不利方向,因此仅依赖手动关停是不够的。即使你在睡觉或不在电脑前,机器人也应该能够自我保护。
- 注意手续费:在 DEX 上交易需要支付 gas 费用;CEX 则收取交易手续费。高频策略在扣除手续费之前可能盈利,扣除后却可能变成亏损。务必始终纳入真实的手续费估算。
- 合规监管:了解你所在司法管辖区的相关法律。某些地区要求对算法交易进行许可。如果是为他人管理资金,很可能适用证券监管法规。
- 税务影响:在许多司法管辖区,每一笔交易都是应税事件。请保持详尽的记录。你的机器人每天 100 笔交易,可能会带来一场税务申报的噩梦。
- 安全至上:
- 切勿在代码中硬编码 API key
- 使用环境变量
- 在所有账户上启用双因素认证(2FA)
- 考虑使用带有支出限额的智能合约钱包
- 尽可能将私钥保存在离线环境中
- 定期审查你的代码,排查安全漏洞
结语
本指南所介绍的工具和技术——获取实时区块链数据、设计预测特征、训练机器学习模型、实施风险管理以及回测策略——为构建 AI 交易系统提供了基础。但这只是一个起点,而非最终成品。真实世界的交易需要持续迭代:随着市场状况变化不断完善模型,针对边缘情况进行压力测试,并构建能够 7×24 小时可靠运行的强健基础设施。
准备好开始构建了吗?注册 Alchemy 以获取你的 API key,开始试验上述代码示例。如需系统性学习区块链开发,欢迎访问 Alchemy University。
常见问题
我可以自己构建 AI 交易机器人吗?
可以,你可以使用 Python、scikit-learn 或 PyTorch 等机器学习库,以及用于实时数据访问的区块链基础设施,来构建自己的 AI 交易机器人。本指南提供了一份完整的入门教程。
构建 AI 交易机器人最适合使用哪种编程语言?
Python 是最推荐使用的语言,因为它拥有丰富的机器学习和数据分析库,包括 Pandas、NumPy、scikit-learn,以及 PyTorch 或 TensorFlow。
AI 交易机器人的基本组成部分有哪些?
一个完整的 AI 交易机器人需要可靠的区块链数据基础设施、用于预测的机器学习模型、结合价格与链上指标的特征工程、包含止损和仓位规模控制的风险管理,以及在上线前用于验证策略的回测能力。
区块链基础设施对 AI 交易机器人有多重要?
基础设施至关重要——大多数机器人失败并非因为预测不佳,而是因为数据过时、API 宕机或延迟过高。你需要实时、低延迟的数据访问,以及跨多条区块链进行竞争性交易所要求的可靠性。
AI 交易机器人的现实成功率是多少?
只有 10%-30% 的机器人用户能够实现持续盈利。成功与否取决于可靠的基础设施、稳健的风险管理和现实的预期,而不仅仅是精巧的算法。在波动剧烈的加密市场中,55%-60% 的预测准确率已经相当不错。
如何用 AI 交易机器人管理风险?
实施止损和止盈水平,根据置信度确定仓位大小(通常每笔交易最多占投资组合的 2%),设置能够暂停交易的最大回撤阈值,限制每日交易次数以防止过度交易,并针对意外损失设置熔断机制。
我的 AI 交易机器人应该使用哪些数据源?
结合实时价格数据、gas 使用量和交易数量等链上指标、移动平均线和波动率等技术指标,以及来自巨鲸钱包动向的情绪信号,以获得最全面的市场视图。
在使用真实资金之前,我应该回测我的交易机器人吗?
是的,务必先在历史数据上进行回测,然后用模拟订单进行至少一个月的模拟交易。开始实盘交易时,只投入你预定资金规模的 10%-20%,因为由于手续费、滑点和执行延迟,实际表现会比回测差 20%-30%。
AI 交易机器人的主要类型有哪些?
常见类型包括:使用价格模式和指标的技术分析机器人、解析社交媒体和链上信号的情绪分析机器人、利用交易所间价差的套利机器人,以及协调多种策略的自主 AI agent 基金。
我应该在交易机器人中内置哪些安全机制?
构建能够追溯每一个决策的可观测系统,添加带有最大亏损阈值和冷却期的熔断机制,实施速率限制器以防止失控执行,并对超过特定阈值的高风险决策保留人工介入。
Alchemy 新闻通讯
第一时间获取发布信息
订阅我们的新闻通讯
获取 Alchemy 的最新产品更新和资源
填写您的电子邮箱地址即表示您同意接收我们的营销通讯和产品更新。您确认 Alchemy 按照我们的隐私声明处理我们收到的信息。您可以随时取消订阅。


