redis - 远程发送买卖信号、本地接收信号处理

我们经常会有这样的场景:想在远程(比如聚宽)是发送买入、卖出信号,比如 时间、买入100股,价格、代码、平安银行,然后在redis本地进行接收,解析,打印并且执行任务(比如QMT、miniQMT进行实盘买入下单)

前一个帖子我们已经知道怎么在windows上搭建redis环境,这个教程我们来学习用python进行发送、接收信号。

目录

一、说明

二、统一消息格式(JSON)

三、sender.py(远端发送)

四、worker.py(本地接收并执行)

五、结语


一、说明

  • 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下单函数,就能够进行实盘交易了。

相关推荐
思辨共悟3 小时前
(Python)数据分析:概念和流程
python·数据分析
叫我阿柒啊3 小时前
从全栈开发到云原生:一位Java工程师的实战经验分享
java·spring boot·redis·云原生·kafka·vue·全栈开发
数据科学作家3 小时前
0基础怎么学习数据分析、统计分析、机器学习?数学不好、一看编程就头疼,能行吗?
python·数据分析·统计分析·stata·spss·统计学·计量经济学
在钱塘江3 小时前
LangGraph从新手到老师傅 - 11 - 自定义序列化处理复杂数据
人工智能·python
THMAIL3 小时前
机器学习从入门到精通 - 卷积神经网络(CNN)实战:图像识别模型搭建指南
linux·人工智能·python·算法·机器学习·cnn·逻辑回归
没有bug.的程序员3 小时前
Redis 数据结构全面解析:从底层编码到实战应用
java·数据结构·redis·wpf
LQ深蹲不写BUG4 小时前
Redis的五种常用数据类型。
数据库·redis·缓存
夏暮客4 小时前
day2today3夏暮客的Python之路
笔记·python·学习
小妖同学学AI4 小时前
cursor+python轻松实现电脑监控
开发语言·python