因为目前已经切换成Rust做交易系统了,并且使用我们的交易系统Http下单比Rust的ureq库快1ms,比Python的request库快3ms,所以分享一些我使用Python做高频策略所遇到的坑。
我们目前技术栈:
为什么做策略要用Python?不纯Rust? 因为很多做策略开发的研究员,学习Rust开发策略,原来Python一周就可以上线的策略,用Rust要至少一个月起步。 而且Python很赚钱的策略,研究员去复现成Rust,结果还不如Python赚钱,因为写法不能完全复制,哈哈哈。
我本身是做黑客和Web全栈+Python爬虫做了好几年后面转量化。 像我这样,技术特别强,策略也特别强,少之又少。 (别问我为什么不继续黑客,我不想出国也不想包吃包住)
一般的研究员,习惯用循环去查询当前最新价格,比如:
ounter(lineounter(lineounter(linewhile 1:price = ....time.sleep(0.001)
这个速度也不错,但是缺陷很明显,天然就比竞争对手慢1ms,并且大量消耗CPU
正确的做法,建立一个websocket订阅最新价格bbo,并且收到行情就执行一次策略:
ounter(lineounter(lineounter(lineounter(linedef trade(price):策略codewebsocket("BTCUSDT", callback=trade)
很多Quant做交易系统和策略开发会习惯启动多线程去做一些事情,但是Python创建多线程所需要的系统耗时平均需要0.1ms!如果波动大,同时创建的多,耗时1ms也会经常出现,所以策略code里面不要用多线程。 测试代码:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineimport threadingimport timedef NowTimeMs():return int(time.time()*1_000_000)def worker(t):print((NowTimeMs() - t) / 1000, 'ms')print('TEST')threads = []for i in range(100):t = threading.Thread(target=worker, args=(NowTimeMs(),))#t.setDaemon(True)t.start()
测试结果:

这个比多线程还糟糕,行情多,在策略里面多次创建create_task任务,直接1秒之后再执行你的操作。。
这个是Python的一个特性,用+号拼接会增加系统延迟,具体原因可以问chatgpt,应该用f"{}",或者format
没想到吧?这个也会增加你的系统耗时,平均一次10us,而且很多哦~ 如果有统计的需求,可以把要打印的内容append到数组里,最后策略运行结束再打印
测试代码:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineimport timedef NowTimeMs():return int(time.time()*1_000_000)for i in range(10):t = NowTimeMs()for i in range(10):print("啦啦啦啦啦啦")print((NowTimeMs() - t) / 1000, 'ms')
测试结果:

看过很多人的策略代码,都用loguru去记录日志,执行大概0.27ms一次吧
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(linefrom loguru import logger# 设置异步日志记录到文件logger.add("multiArbitrage1.log", rotation="10 MB", enqueue=True, backtrace=True, diagnose=True)import timedef NowTimeMs():return int(time.time()*1_000_000)for i in range(10):t = NowTimeMs()for i in range(10):# print("啦啦啦啦啦啦")logger.debug(f'666666666')print((NowTimeMs() - t) / 1000, 'ms')
测试结果:

aiohttp天然就比request库快,所以用aiohttp库会更好,然后有websocket的下单api 都用websocket 当然我们也编写了一个用rust封装的http库,python调用去下单比request快个1-2ms
事件驱动 + 协程 + aiohttp + Websocket下单