我们经常会有这样的场景:想在远程(比如聚宽)是发送买入、卖出信号,比如 时间、买入100股,价格、代码、平安银行,然后在redis本地进行接收,解析,打印并且执行任务(比如QMT、miniQMT进行实盘买入下单)
前一个帖子我们已经知道怎么在windows上搭建redis环境,这个教程我们来学习用python进行发送、接收信号。
目录
一、说明
-
sender.py
:远端发送买卖信号(入队) -
worker.py
:本地常驻进程,阻塞式取队列、解析、打印并"执行任务" -
统一消息格式(JSON)
依赖:
pip install redis
二、统一消息格式(JSON)
{
"type": "BUY", // BUY 或 SELL
"symbol": "000001.SZ", // 证券代码
"name": "平安银行", // 可选
"qty": 100, // 数量(股/手)
"price": 12.34, // 价格,允许 0 表示市价或由执行侧自行决定
"client_order_id": "...", // 唯一ID(便于去重/追踪)
"ts": "2025-09-03T17:20:15.123Z" // ISO时间
}
{
"type": "BUY", // BUY 或 SELL
"symbol": "000001.SZ", // 证券代码
"name": "平安银行", // 可选
"qty": 100, // 数量(股/手)
"price": 12.34, // 价格,允许 0 表示市价或由执行侧自行决定
"client_order_id": "...", // 唯一ID(便于去重/追踪)
"ts": "2025-09-03T17:20:15.123Z" // ISO时间
}
三、sender.py(远端发送)
# sender.py
import argparse
import json
import uuid
from datetime import datetime, timezone
import redis
import os
def get_redis():
r = redis.Redis(
host=os.getenv("REDIS_HOST", "127.0.0.1"),
port=int(os.getenv("REDIS_PORT", "6379")),
password=os.getenv("REDIS_PASSWORD", None),
db=int(os.getenv("REDIS_DB", "0")),
decode_responses=True,
socket_timeout=5
)
# 测连通
r.ping()
return r
def build_message(side, symbol, qty, price, name=None):
return {
"type": side.upper(), # BUY / SELL
"symbol": symbol,
"name": name,
"qty": int(qty),
"price": float(price),
"client_order_id": str(uuid.uuid4()),
"ts": datetime.now(timezone.utc).isoformat()
}
def main():
parser = argparse.ArgumentParser(description="Push trade signal to Redis queue")
parser.add_argument("--side", choices=["BUY", "SELL"], required=True, help="BUY or SELL")
parser.add_argument("--symbol", required=True, help="like 000001.SZ")
parser.add_argument("--qty", type=int, required=True, help="quantity")
parser.add_argument("--price", type=float, required=True, help="price (0 for market)")
parser.add_argument("--name", default=None, help="security name, e.g. 平安银行")
parser.add_argument("--queue", default="trade_queue", help="redis list key")
args = parser.parse_args()
r = get_redis()
msg = build_message(args.side, args.symbol, args.qty, args.price, args.name)
r.rpush(args.queue, json.dumps(msg, ensure_ascii=False))
print("Enqueued:", msg)
if __name__ == "__main__":
main()
使用:
在远程电脑上执行,
环境变量
set REDIS_HOST=你的本地公网IP或内网IP
set REDIS_PASSWORD=123456
然后执行发送代码:【注意,可以等先启动了接收程序再启动发送,这样能看到效果】
python sender.py --side BUY --symbol 000001.SZ --qty 100 --price 12.34 --name 平安银行

注意:macos的话用 export来代替set
四、worker.py(本地接收并执行)
# worker.py
import json
import time
import redis
import os
import traceback
QUEUE_KEY = os.getenv("QUEUE_KEY", "trade_queue")
DEAD_KEY = os.getenv("DEAD_KEY", "trade_dead") # 可选死信队列
def get_redis():
r = redis.Redis(
host=os.getenv("REDIS_HOST", "127.0.0.1"),
port=int(os.getenv("REDIS_PORT", "6379")),
password=os.getenv("REDIS_PASSWORD", None),
db=int(os.getenv("REDIS_DB", "0")),
decode_responses=True,
socket_timeout=10
)
r.ping()
return r
def validate(msg: dict):
required = ["type", "symbol", "qty", "price", "client_order_id", "ts"]
for k in required:
if k not in msg:
raise ValueError(f"missing field: {k}")
if msg["type"] not in ("BUY", "SELL"):
raise ValueError("type must be BUY or SELL")
if not isinstance(msg["qty"], int) or msg["qty"] <= 0:
raise ValueError("qty must be positive int")
# 价格可为0(如表示市价或由执行端决定)
float(msg["price"])
def execute_trade(msg: dict):
"""
这里写你的实际执行逻辑(下单、回测接口、模拟撮合、调用券商API等)。
为了演示,先做个"打印执行"的占位。
"""
side = msg["type"]
symbol = msg["symbol"]
name = msg.get("name") or ""
qty = msg["qty"]
price = msg["price"]
cid = msg["client_order_id"]
# ===== 在这替换成你的交易执行 =====
print(f"[EXECUTE] {side} {qty} {symbol} ({name}) @ {price} CID={cid}")
# 例如:broker_api.place_order(side=side, symbol=symbol, qty=qty, price=price, tif="GFD")
# 返回报单号 / 状态,写入日志或回写状态即可。
# =================================
def main():
r = get_redis()
print(f"Worker started. Listening on list: {QUEUE_KEY}")
while True:
try:
# BLPOP: 阻塞等待,timeout=5秒可让我们有机会处理中断/心跳等
item = r.blpop(QUEUE_KEY, timeout=5)
if item is None:
# 队列暂时为空,循环继续
continue
_, payload = item
try:
msg = json.loads(payload)
except Exception:
print("[ERROR] JSON decode failed. Put to dead-letter.")
r.rpush(DEAD_KEY, payload)
continue
try:
validate(msg)
except Exception as e:
print(f"[ERROR] Invalid message: {e}. Put to dead-letter.")
r.rpush(DEAD_KEY, json.dumps({
"error": str(e),
"payload": msg
}, ensure_ascii=False))
continue
# 执行任务
execute_trade(msg)
except KeyboardInterrupt:
print("Worker stopping (Ctrl+C).")
break
except redis.exceptions.ConnectionError as e:
print(f"[WARN] Redis connection issue: {e}. Retry in 3s...")
time.sleep(3)
except Exception:
print("[ERROR] Unexpected error:\n", traceback.format_exc())
# 不中断进程,继续监听
time.sleep(1)
if __name__ == "__main__":
main()
在命令行中:
set REDIS_PASSWORD=123456
然后再执行:
python worker.py
结果如图:

说明已经接收到对应信息!成功!
注意:在此之前,要保证redis是启动状态

五、结语
只需要将 execute_trade() 函数改成真实的QMT下单函数,就能够进行实盘交易了。