
文件单到底是什么东西
很多散户听到量化交易就觉得必须会写Python、必须租服务器、必须对接券商API。其实有一种最土但最管用的方式,叫文件单。说白了,就是你往一个固定文件夹里扔一个文本文件,里面写清楚要买什么、买多少、什么价格,交易程序自动读取这个文件然后去下单。反过来,成交回报也写回另一个文件里。整个过程就像给交易软件留纸条,它看到纸条就干活。
这种方式在期货市场特别常见。早年间程序化交易接口没放开,很多个人交易者就是用文件单绕过限制。现在股票市场虽然有了官方量化接口,但文件单依然有生命力,尤其是对编程不熟、又不想把账户密码交给第三方平台的人。
文件单的底层逻辑比你想象的简单
文件单的核心就三件事:文件夹、文件格式、监控程序。你在一台电脑上建两个文件夹,一个叫发单目录,一个叫回报目录。监控程序每隔几百毫秒扫一眼发单目录,发现新文件就解析内容、调用交易接口下单,然后把结果写到回报目录。整个过程不需要网络通讯协议,不需要数据库,甚至不需要多线程。
这种方式的优势在于解耦。策略部分只管写文件,执行部分只管读文件,两边互不干扰。策略崩了不会影响下单,下单程序重启也不丢单。期货夜盘经常遇到交易软件卡死,文件单因为逻辑简单,反而不容易出问题。

文件格式怎么定才不踩坑
文件内容建议用纯文本或CSV,不要用JSON或XML。期货公司那些老旧的交易软件对复杂格式支持很差,纯文本最保险。每一行写一个指令,字段之间用逗号隔开。必须包含的字段有:合约代码、买卖方向、开平标志、价格、手数。股票的话把开平标志换成买卖类型就行。
一个关键细节:每行指令后面加一个唯一序号。监控程序要记录已经处理过的序号,防止因为文件没及时删除导致重复下单。期货交易重复下单是致命错误,一秒钟能给你开出几百手。序号可以用时间戳加随机数,保证不重复。
文件写完不要直接放在发单目录里,先在临时目录写好,再用操作系统的原子移动命令挪过去。否则监控程序可能读到写了一半的文件,解析失败。
监控程序怎么写才可靠
用Python写监控程序最省事,标准库就够。核心循环是:列出目录下所有文件,过滤掉已处理的,按文件名排序,逐个读取解析,调用交易接口,记录结果,删除文件。注意要捕获所有异常,不能让一个坏文件把整个程序搞崩。
期货交易接口推荐用CTP,股票用券商提供的官方API。如果连API都没有,可以用模拟键盘鼠标的方式操作交易软件,但这种方式极不稳定,只适合应急。
监控程序要加心跳机制。每隔几秒往一个心跳文件里写当前时间,策略端检查心跳文件是否更新,超过十秒没更新就报警。期货夜盘没人盯着,心跳机制能救命。
风控必须做在文件单之前
文件单最大的风险是策略端出bug,疯狂写文件。监控程序必须内置硬风控:单笔最大手数、每秒最大发单数、当日最大亏损额度。这些参数写死在监控程序里,策略端改不了。
期货交易还要加价格笼子检查。发单价格偏离最新价超过2%的直接拒单。股票加涨跌停检查。所有拒单记录写到日志文件,方便事后复盘。
账户资金查询也要走文件单。监控程序定时把持仓和资金写到回报目录,策略端读取后决定下一步动作。这样整个闭环都不需要策略端直接接触交易接口。
股票和期货的差异要心里有数
期货文件单天然适合,因为CTP接口成熟,个人也能申请。股票文件单麻烦一些,券商API通常有频率限制,而且股票是T+1,重复下单的后果比期货轻但依然恶心。建议股票文件单只做日频调仓,不要做盘中高频。
期货夜盘时段文件单优势明显。白天人盯着盘面,手动交易没问题;夜盘困得睁不开眼,文件单自动执行策略,第二天早上看回报文件就行。很多做螺纹钢和原油的散户就是这么干的。
一个最小可用的代码骨架
import os, time, csv, shutil
from datetime import datetime
SEND_DIR = 'send'
RECV_DIR = 'recv'
PROCESSED = set()
def safe_move(src, dst):
shutil.move(src, dst)
def process_file(path):
with open(path, 'r') as f:
reader = csv.reader(f)
for row in reader:
order_id = row[0]
if order_id in PROCESSED:
continue
symbol, direction, offset, price, volume = row[1:6]
# 调用交易接口下单
result = place_order(symbol, direction, offset, float(price), int(volume))
with open(os.path.join(RECV_DIR, order_id + '.txt'), 'w') as rf:
rf.write(str(result))
PROCESSED.add(order_id)
os.remove(path)
while True:
for fname in sorted(os.listdir(SEND_DIR)):
if fname.endswith('.csv'):
process_file(os.path.join(SEND_DIR, fname))
time.sleep(0.5)
这段代码只是骨架,真实环境要加异常捕获、日志、心跳和风控。但核心逻辑就这么点东西。文件单不高级,但足够可靠。量化交易的第一原则是活着,不是炫技。