欧易 · 风控
量化风控:API 自动交易怎么不让你爆仓
很多人以为量化的风险来自行情:看错了方向就亏。但跑过一阵脚本的人会告诉你,真正让账户瞬间归零的,往往不是行情,而是你自己的代码——一个写反的方向、一个停不下来的循环、一次断网后的重复下单。手动交易时,你按确认前还有最后一眼;脚本没有这一眼,它会忠实地、连续地把错误执行下去。
这篇我们(量化喵编辑组)专门讲量化风控,而且是从「代码层面怎么防」切入,不是泛泛地喊「控制仓位」。我们会拆开 API 交易特有的几类风险,给出可以照抄的止损、分仓、重试代码,再把账户安全的底线和「小额冷启动」的上场顺序讲清楚。读完你应该能给自己的脚本装上几道刹车,让它就算出错也不至于把你拖到爆仓。
API 交易的特有风险
手动交易和 API 自动交易,风险类型不一样。手动交易的主要敌人是情绪和判断;API 交易在这之上,还多了一整类「机器特有」的风险。认清它们,才知道刹车该装在哪儿。
程序跑飞
这是最典型的。一段逻辑写错了——买卖方向搞反、止损条件判断写成了相反、循环少了退出条件——程序不会像人一样停下来想想「是不是哪里不对」,它会照着错误的指令一遍遍执行。人手动可能下错一单就发现了,脚本能在几秒内下错几十单。跑飞的杀伤力,在于它的「忠实」。
重复下单
网络抖动、请求超时时最容易出。你发了一个下单请求,没收到响应,脚本以为失败了,于是重发——但其实第一单已经成交了,结果你下了两单。在合约上,这意味着仓位翻倍、风险翻倍。重复下单往往不是逻辑错,而是没处理好「不确定的中间状态」。
断网与掉线
脚本跑在你的电脑或服务器上,网络一断,它就和交易所失联了。糟糕的情况是:你的持仓还裸露在市场里,而本该保护它的止损逻辑跟着脚本一起掉线了。等你重连上来,可能已经面目全非。断网风险的本质,是别把所有保护都押在「脚本一直在线」这个假设上。
仓位管理与分仓
风控的第一道墙,是别让任何单笔错误能伤到你的全部资金。这靠仓位规则实现,而且这些规则要写死在代码里,不靠你临场克制。
几条我们自己一直遵守的原则:
- 设单笔上限。任何一单不超过总资金的某个固定比例(比如 1%–2%)。这样就算这一单方向全错,损失也有顶。
- 设总持仓上限。所有未平仓位加起来不超过一个总额,别让程序有机会把你全部资金一次压上去。
- 分仓,不要一把梭。把资金拆成几份分批进场,降低单一进场点位的判断错误带来的冲击。
- 给脚本留现金。账户里始终保留一部分不参与交易的资金,既是缓冲,也是出问题时你能手动操作的余地。
把这些写成代码里的硬约束,下单前先检查,不满足就拒绝下单:
MAX_PER_ORDER_RATIO = 0.02 # 单笔不超过总资金 2%
MAX_TOTAL_RATIO = 0.30 # 总持仓不超过总资金 30%
def check_position_limit(okx, symbol, order_value_usdt):
bal = okx.fetch_balance()
equity = bal['USDT']['total'] # 以 USDT 计的总权益
# 单笔上限
if order_value_usdt > equity * MAX_PER_ORDER_RATIO:
raise ValueError('超过单笔仓位上限,拒绝下单')
# 这里可再叠加"当前总持仓 + 本单"不得超过 MAX_TOTAL_RATIO 的检查
return True
这段不复杂,但它的价值在于:它把「我得控制仓位」这个意愿,变成了脚本下单前必须过的一道闸。意愿会动摇,代码不会。
止损必须程序化(代码)
如果只能记住这篇文章的一句话,就记这句:止损必须程序化。脚本是自动跑的,你不可能 24 小时盯盘;行情快速反向时,等你看到再手动平仓,往往已经晚了好几个价位。
程序化止损有两种思路,推荐配合使用:
思路一:交易所端的条件单 / 止损单。下主单的同时,在欧易挂一个止损委托,让交易所在触发价自动帮你平仓。它最大的好处是:就算你的脚本掉线了,这个止损仍然在交易所那边生效。这是对抗「断网时持仓裸奔」最可靠的一招。
思路二:脚本本地监控 + 触发平仓。脚本在循环里持续读取持仓的浮亏,一旦超过你设的阈值就主动发平仓单。它更灵活(能做移动止损、按时间止损等),但前提是脚本得在线。
下面是一个本地监控止损的最简骨架,演示逻辑(实盘前务必在 模拟盘 验证):
import ccxt, time
okx = ccxt.okx({
'apiKey': '你的_apiKey',
'secret': '你的_secret',
'password': '你的_Passphrase',
'enableRateLimit': True,
})
symbol = 'BTC/USDT'
entry_price = 60000 # 你的进场均价(示例)
amount = 0.001 # 持仓数量
stop_ratio = 0.05 # 跌 5% 止损
while True:
ticker = okx.fetch_ticker(symbol)
last = ticker['last']
drawdown = (entry_price - last) / entry_price
if drawdown >= stop_ratio:
okx.create_order(symbol, 'market', 'sell', amount)
print(f'触发止损,已市价平仓 @ {last}')
break
time.sleep(10) # 留足间隔,别打爆接口
注意两点:一是循环里务必有 sleep,否则会撞限频;二是本地止损只是补充,交易所端的止损单才是断网时的最后防线,两者都做才稳。
防重复下单与断网
重复下单的根源,是「我不确定上一单到底成没成」。防它的核心是:别盲目重发,先确认状态。
两个办法配合用:
用客户端自定义订单号(clientOrderId)。下单时带上一个你自己生成的唯一 ID,交易所看到重复的 ID 会拒掉,这是天然的防重机制。即使你因为超时重发了,交易所也只会认第一单。
import uuid
cid = 'meow-' + uuid.uuid4().hex[:16] # 你自己生成的唯一订单号
order = okx.create_order(
symbol, 'limit', 'buy', 0.001, 50000,
params={'clientOrderId': cid}, # 带上它,重发也只认一次
)
超时 / 断网后,先查再补。下单请求超时了,别直接重发;先用挂单查询或持仓查询确认上一单到底有没有进去,再决定要不要补单。重连之后同理——先 fetch_open_orders、fetch_positions 看清楚当前真实状态,再让策略继续。把「先查状态、再动作」作为重连后的固定第一步,能挡掉绝大多数因失联导致的重复操作。
OK30001 注册欧易,手续费有减免,API 下的单同样适用这个减免。点这里注册欧易并开 API →
限频、超时与重试
风控不只是防亏钱,也包括防脚本「自己把自己搞挂」。限频和超时处理不好,会让你的策略在关键时刻失灵。
限频:初始化时打开 'enableRateLimit': True,ccxt 会自动在请求间插入间隔。高频循环里再加指数退避(撞一次等 1 秒,再撞等 2 秒、4 秒)。这部分我们在 API 常见报错 那篇讲得更细,这里只强调:任何循环里打接口,限速是标配。
超时:给请求设一个明确的超时时间,别让脚本因为某个请求卡住而整体僵死。ccxt 可以配 'timeout'(毫秒):
okx = ccxt.okx({
'apiKey': '你的_apiKey',
'secret': '你的_secret',
'password': '你的_Passphrase',
'enableRateLimit': True,
'timeout': 10000, # 单个请求 10 秒超时,避免卡死
})
重试有上限。遇到网络抖动可以重试,但要设最大次数,撞够了就报警/停下,而不是无限重试。无限重试本身就是一种「程序跑飞」——它会在你没注意时一直消耗请求、甚至重复操作。
权限与 IP 白名单:安全底线
风控的最底层,是账户安全。脚本写得再稳,凭证泄露了一切归零。这里有两条几乎没有例外的底线:
只勾「读取」和「交易」,永远别勾「提现」。跑量化根本用不到提现这个动作。只要 Key 没有提现权限,就算你的 apiKey、secret、Passphrase 三件套哪天泄露了,拿到的人最多在你账户里乱下单(这当然也很糟,但有上面那些仓位和止损约束兜底),没法把你的币卷走。而一旦勾了提现,泄露就等于把保险柜钥匙交出去。
设 IP 白名单。如果你的脚本跑在固定 IP 的机器上(云服务器、固定公网 IP 的家宽),把这个 IP 加进 Key 的白名单,只接受来自它的请求,安全性再上一个台阶。如果你 IP 经常变,白名单会天天误拒,这种情况可以先不设,但务必把凭证保管好——别写死在会上传的代码里,改用环境变量或不被同步的配置文件。
这两条加上前面的仓位和止损,构成了「就算最坏情况发生,损失也有边界」的防护。建 Key 的具体步骤在我们的 API 量化入门 里,也可以用 API 权限自查清单 开 Key 前对一遍。
小额冷启动:真金前清单
所有代码层的风控都装好了,上实盘还差最后一步:别一上来就重仓。新策略上真金,我们固定走「小额冷启动」,顺序如下:
- 先模拟盘连续跑。覆盖几轮涨跌,确认下单、撤单、止损、回调全都符合预期。这步零成本,跳过它等于拿真金当测试环境。
- 再用很小的真金冷启动。金额小到全亏了也不心疼,把它当学费。模拟盘没法复现的滑点、深度,这时候才会露出来。
- 盯着它跑头几天。别真撒手,确认实盘行为和模拟盘一致、止损真的会触发、没有重复下单,再逐步加码。
- 合约和杠杆最后考虑。现货跑稳之前,别碰杠杆。杠杆会把上面每一类风险都成倍放大,新手阶段强烈建议只做现货。
把这份清单和前面的代码约束合起来,你给脚本装的就不止是一道刹车,而是好几道:仓位有上限、止损会自动触发、重复下单被挡、凭证泄露也提不走钱、上场还先用小钱试。任何一道单独都不够,合起来才让「出错」和「爆仓」之间隔着足够的缓冲。
实测:我们踩过的坑
print 刷屏然后 Ctrl+C 停掉,顺手把方向改对、补上退出条件和 sleep(10),再加了单笔仓位上限那段检查。要是这事发生在实盘、还带着杠杆,那串错单就是真金白银连续往外流。这次踩坑直接定了我们现在的规矩:止损逻辑必须先在模拟盘验证、循环必须有间隔和退出条件、下单前必须过仓位上限检查——三样缺一不可。
常见问题
API 自动交易最容易让人爆仓的风险是什么?
不是行情本身,而是程序的「忠实」——脚本不会像人一样犹豫。一个搞反的买卖方向、一个漏掉退出条件的循环、一个断网后重复发出的下单,人手动操作时可能在确认前就发现了,脚本却会连续执行几十遍。加上合约杠杆,这种错误能在极短时间内让本金归零。防它的核心是把风控也写进代码,而不是指望自己盯着。
止损一定要写在代码里吗?手动盯不行吗?
强烈建议程序化。脚本是自动跑的,你不可能 24 小时盯着;一旦行情快速反向,等你看到再手动止损往往已经晚了。把止损逻辑写进策略,或者用欧易的条件单/止损单,让程序在触发线自动平仓,才跟得上自动交易的节奏。手动盯只能作为补充,不能作为唯一防线。
怎么防止脚本重复下单?
两个办法配合用。一是给每个订单带一个客户端自定义订单号(clientOrderId),交易所看到重复的 ID 会拒掉,天然防重;二是下单后查一下当前挂单和持仓再决定要不要继续,而不是盲目地一轮一轮发单。断网或超时后尤其要先查状态、再补单,别假设上一单失败了就直接重发。
API Key 权限怎么设才安全?
跑量化的 Key 只勾「读取」和「交易」,永远别勾「提现」。这样就算三个凭证泄露,拿到的人最多在你账户里乱下单,卷不走你的币。再给 Key 绑定 IP 白名单(如果你跑在固定 IP 的机器上),只接受指定 IP 的请求,安全性再上一个台阶。自动化交易根本用不到提现这个动作。
新策略上实盘第一次该投多少?
用你就算全亏了也不心疼的金额,把它当学费而不是本金。先在模拟盘把流程跑顺,再用很小的真金做冷启动,盯着它跑头几天,确认实盘行为和模拟盘一致、滑点和成交都在预期内,再逐步加码。一上来就压重仓,等于把没验证过的代码直接赌上全部资金。
断网了正在跑的脚本会怎样?
取决于你怎么写的。糟糕的写法是断网时请求超时、脚本崩溃,或者盲目重试导致重复下单,而你的持仓还裸露在市场里没有止损。稳妥的做法是:给请求设超时和重试上限,重连后先查一遍当前持仓和挂单状态再决定动作,并且依赖交易所端的止损单(而不是只靠脚本本地判断),这样即使脚本掉线,平仓保护仍然在交易所那边生效。
风控不是写完代码就一劳永逸的,它得跟着你的策略一起长。建议你把这篇的清单存下来,每次上新策略都对一遍。接下来可以去看 API 常见报错 把脚本的稳定性补齐,新代码一律先丢 模拟盘 验证。记住那句老话:先活下来,再谈收益。
把风控装好,再让策略替你跑
先把账户和 API 准备好,在模拟盘把仓位、止损、防重发都验证过,再用小额真金冷启动。用邀请码注册的新账户,手续费有减免,API 下的单一样适用。
加密资产价格波动剧烈,合约与杠杆可能导致本金全部亏损。量化与自动化交易不保证盈利,请只用你能承受损失的资金。