本教程将围绕 两个完整可用的脚本 展开:
-
HTTP 脚本:通过REST API 定期查询 BTC 最新成交价,适合入门和低频监控
-
WebSocket 脚本:通过WebSocket 订阅实时行情,构建专业级技术指标预警(金叉 + 放量)
读完本文,你将能够:
-
理解 Infoway HTTP 与 WebSocket 的使用场景差异
-
独立运行并修改这两个脚本
-
知道如何从“拿数据”升级到“做交易信号预警”
一、准备工作
在开始之前,请确保你已经具备以下环境:
-
Python 3.8+
-
已安装依赖库:
pip install requests websocket-client schedule loguru
-
在 Infoway API官网申请并获取 API Key
本文所有示例都以
BTCUSDT为例,你可以很容易替换成其他交易对。
二、HTTP 版行情预警脚本(基础版)
import requests
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import time
# ================= Infoway API =================
API_URL = "https://data.infoway.io/crypto/batch_trade/BTCUSDT"
API_KEY = "yourInfowayApiKey"
# ================= 邮件设置 =================
SMTP_SERVER = "smtp.your-email-provider.com"
SMTP_PORT = 587
EMAIL_ADDRESS = "your_email@example.com"
EMAIL_PASSWORD = "your_password_here"
TO_EMAIL = "recipient@example.com"
# ================= 状态 =================
last_alert_price = None
THRESHOLD = 73000
# ================= 获取最新成交价 =================
def get_btc_price():
headers = {
"User-Agent": "Mozilla/5.0",
"Accept": "application/json",
"apiKey": API_KEY
}
try:
response = requests.get(API_URL, headers=headers, timeout=10)
except Exception as e:
print("请求异常:", e)
return None
if response.status_code != 200:
print("HTTP错误:", response.status_code, response.text)
return None
try:
data = response.json()
except Exception as e:
print("JSON解析失败:", e)
return None
try:
# ✅ 根据你给的返回示例
return float(data["p"])
except (KeyError, ValueError) as e:
print("成交价解析失败:", e, data)
return None
# ================= 发送邮件 =================
def send_email_notification(price):
subject = "比特币价格提醒"
body = f"比特币最新成交价:${price},已超过阈值 {THRESHOLD}"
msg = MIMEMultipart()
msg["From"] = EMAIL_ADDRESS
msg["To"] = TO_EMAIL
msg["Subject"] = subject
msg.attach(MIMEText(body, "plain"))
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls()
server.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
server.sendmail(EMAIL_ADDRESS, TO_EMAIL, msg.as_string())
print("📧 邮件已发送")
except Exception as e:
print("邮件发送失败:", e)
# ================= 主逻辑 =================
def main():
global last_alert_price
price = get_btc_price()
if price is None:
return
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 最新成交价: ${price}")
# 超过阈值且避免重复报警
if price > THRESHOLD and price != last_alert_price:
last_alert_price = price
send_email_notification(price)
if __name__ == "__main__":
main()
2.1 适合什么场景?
HTTP 轮询方式适合:
-
新手快速上手
-
低频价格提醒(例如价格突破某个整数位)
-
不需要毫秒级实时性
它的特点是:简单、稳定、易调试。
2.2 使用的 Infoway 接口
GET https://data.infoway.io/crypto/batch_trade/BTCUSDT
该接口返回的是 最新一笔成交信息,示例:
{
"s": "BTCUSDT",
"t": 1752947397177,
"p": "117783.22",
"v": "0.00048"
}
我们真正关心的字段只有一个:
-
p→ 最新成交价
2.3 HTTP 脚本核心逻辑拆解
第一步:请求最新成交价
price = float(data["p"])
这一步的目标只有一个:拿到当前市场成交价。
第二步:设定预警条件
THRESHOLD = 73000
if price > THRESHOLD:
send_email_notification(price)
这就是一个最简单、也是最常见的行情预警模型:
当价格突破某个关键位置时提醒我
第三步:避免重复报警(非常重要)
last_alert_price
如果不做控制,价格在阈值之上会反复触发报警。
解决思路:
-
只在 第一次突破时 报警
-
或者增加冷却时间(cooldown)
2.4 HTTP 方案的优缺点总结
优点:
-
逻辑简单
-
稳定可靠
-
非常适合新手
缺点:
-
有延迟(取决于轮询间隔)
-
不适合技术指标计算
当你开始关心:
“是不是刚刚金叉了?”
HTTP 就不够用了,这时就该进入 WebSocket 世界。
三、WebSocket 版行情预警脚本(进阶版)
import json
import time
import schedule
import threading
import websocket
from loguru import logger
from collections import deque
class WebsocketExample:
def __init__(self):
self.session = None
self.ws_url = "wss://data.infoway.io/ws?business=crypto&apikey=yourApikey"
self.is_ws_connected = False
# ====== K线缓存 ======
self.closes = deque(maxlen=30) # close价
self.volumes = deque(maxlen=30) # 成交量
self.prev_ma5 = None
self.prev_ma20 = None
# ================= 连接相关 =================
def connect_all(self):
self.connect(self.ws_url)
self.start_reconnection(self.ws_url)
def start_reconnection(self, url):
def check():
if not self.is_connected():
self.connect(url)
schedule.every(10).seconds.do(check)
threading.Thread(target=self._run_schedule, daemon=True).start()
def _run_schedule(self):
while True:
schedule.run_pending()
time.sleep(1)
def is_connected(self):
return self.session and self.is_ws_connected
def connect(self, url):
self.session = websocket.WebSocketApp(
url,
on_open=self.on_open,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close
)
threading.Thread(target=self.session.run_forever, daemon=True).start()
# ================= WebSocket 回调 =================
def on_open(self, ws):
logger.info("WebSocket connected")
self.is_ws_connected = True
# 最新成交
self.send_message({
"code": 10000,
"trace": "trade",
"data": {"codes": "BTCUSDT"}
})
time.sleep(3)
# 盘口
self.send_message({
"code": 10003,
"trace": "depth",
"data": {"codes": "BTCUSDT"}
})
time.sleep(3)
# 1分钟K线
self.send_message({
"code": 10006,
"trace": "kline",
"data": {
"arr": [{"type": 1, "codes": "BTCUSDT"}]
}
})
schedule.every(30).seconds.do(self.ping)
def on_message(self, ws, message):
try:
data = json.loads(message)
except:
return
# ====== 只处理K线数据 ======
if data.get("code") == 10006:
self.handle_kline(data)
def on_close(self, ws, *args):
self.is_ws_connected = False
logger.warning("WebSocket closed")
def on_error(self, ws, error):
self.is_ws_connected = False
logger.error(f"WebSocket error: {error}")
# ================= K线处理 & 预警 =================
def handle_kline(self, msg):
"""
假设 data 中包含:
close: 收盘价
volume: 成交量
"""
k = msg.get("data", {})
close_price = float(k.get("c", 0))
volume = float(k.get("v", 0))
if close_price == 0:
return
self.closes.append(close_price)
self.volumes.append(volume)
if len(self.closes) < 20:
return
ma5 = sum(list(self.closes)[-5:]) / 5
ma20 = sum(list(self.closes)[-20:]) / 20
avg_volume = sum(self.volumes) / len(self.volumes)
# ====== 金叉判断 ======
golden_cross = (
self.prev_ma5 is not None and
self.prev_ma20 is not None and
self.prev_ma5 <= self.prev_ma20 and
ma5 > ma20
)
# ====== 成交量激增 ======
volume_spike = volume > avg_volume * 2
if golden_cross and volume_spike:
self.alert(close_price, volume, ma5, ma20)
self.prev_ma5 = ma5
self.prev_ma20 = ma20
# ================= 预警动作 =================
def alert(self, price, volume, ma5, ma20):
logger.warning(
f"🚨 BTC 金叉 + 放量!\n"
f"价格: {price}\n"
f"MA5: {ma5:.2f}, MA20: {ma20:.2f}\n"
f"成交量: {volume}"
)
# 👉 这里可以接:
# send_email()
# send_telegram()
# send_webhook()
# ================= 工具 =================
def send_message(self, obj):
if self.is_connected():
self.session.send(json.dumps(obj))
def ping(self):
self.send_message({"code": 10010, "trace": "ping"})
# ================= 启动 =================
if __name__ == "__main__":
ws = WebsocketExample()
ws.connect_all()
while True:
schedule.run_pending()
time.sleep(1)
3.1 为什么要用 WebSocket?
WebSocket 是 交易系统的标配:
-
实时推送
-
无需频繁请求
-
可以持续接收 K 线、成交、盘口
一句话总结:
只要你开始做策略,就一定要用 WebSocket。
3.2 本脚本订阅了哪些数据?
在 WebSocket 连接建立后,我们订阅了三类数据:
-
最新成交价(trade)
-
盘口数据(depth)
-
1 分钟 K 线(kline) ← 本文预警逻辑的核心
3.3 金叉预警逻辑详解
什么是金叉?
金叉是最经典的趋势信号之一:
-
短期均线向上突破长期均线
在脚本中我们定义为:
-
MA5(5 根 K 线均价)
-
MA20(20 根 K 线均价)
上一根K线:MA5 <= MA20
当前K线:MA5 > MA20
这样可以有效避免“假突破”。
3.4 为什么还要加「成交量激增」?
没有成交量配合的金叉,可信度非常低。
因此我们增加第二个过滤条件:
当前成交量 > 最近 20 根 K 线平均成交量 × 2
这意味着:
市场不是“慢慢飘过去的”,而是有真实资金推动
3.5 最终触发条件(重点)
金叉成立 AND 成交量激增
只有当 趋势 + 资金 同时出现时,才发送预警。
这已经是一个实战级信号了。
3.6 WebSocket 脚本结构讲解
1️⃣ K 线缓存
self.closes = deque(maxlen=30)
self.volumes = deque(maxlen=30)
用于计算均线和平均成交量。
2️⃣ 均线计算
ma5 = sum(closes[-5:]) / 5
ma20 = sum(closes[-20:]) / 20
3️⃣ 预警触发
if golden_cross and volume_spike:
self.alert(...)
在这里,你可以自由扩展:
-
发邮件
-
发 Telegram
-
调用 Webhook
四、HTTP vs WebSocket:该怎么选?
| 场景 | 推荐方式 |
|---|---|
| 价格突破提醒 | HTTP |
| 技术指标预警 | WebSocket |
| 实时交易策略 | WebSocket |
| 新手入门 | HTTP |
建议路径:
HTTP 入门 → WebSocket 进阶 → 策略组合

被折叠的 条评论
为什么被折叠?



