交易不是免费的
免费交易的回测会高估所有策略,交易越多,谎越大。真实成本包括券商佣金、交易所和监管费用,最重要的是每次都要跨越的买卖价差。它们通常以成交金额的基点报价:1 基点是 0.01%。单边 5 基点的一次往返要花 10 基点,一个每天赚 3 基点的策略如果每天翻转方向,就扛不住。
def trade_cost(notional, bps):
return abs(notional) * bps / 10000
print(trade_cost(25000, 5)) # 12.5 buying 25,000 at 5 bps
print(trade_cost(-25000, 5)) # 12.5 selling costs the same
print(trade_cost(1_000_000, 1)) # 100.0 one basis point on a million换手率:你交易了多少
成本取决于仓位变化了多少,而不是仓位本身有多大。把仓位表示为账户的比例,某天的换手率就是相对前一天仓位的变化绝对值:abs(position[t] - position[t - 1]),第 0 天从空仓开始。持有多头在第一次买入后不花钱;从多翻空要交易账户的两倍。一年累计的换手率,是评价任何策略时首先要看的数字。
import numpy as np
positions = np.array([1.0, 1.0, -1.0, -1.0, 0.0]) # long, long, flip to short, short, flat
turnover = np.abs(np.diff(positions, prepend=0.0)) # day 0 starts from a flat position
print(turnover) # [1. 0. 2. 0. 1.]
print(turnover.sum()) # 4.0 accounts traded over the five days净收益与盈亏平衡成本
某天的成本占账户的比例是 turnover * bps / 10000,净收益就是毛收益减去它。一个很有用的数字是盈亏平衡成本:使总利润恰好为零的单位交易成本,即 sum(gross) / sum(turnover) * 10000。把它与你实际支付的成本对比。盈亏平衡为 2 基点的策略在实践中已经死了,40 基点的则有余地。
# Gross and net returns of a rule that flips often, at 5 bps per unit traded
import numpy as np
rng = np.random.default_rng(11)
positions = np.where(rng.random(250) > 0.5, 1.0, -1.0) # a coin-flip position, flipping often
gross = rng.normal(0.0015, 0.005, size=250) # a strategy with a real daily edge before costs
turnover = np.abs(np.diff(positions, prepend=0.0))
net = gross - turnover * 5 / 10000
print(round(float(gross.sum()), 4), round(float(net.sum()), 4))
print(round(float(turnover.sum()), 1), "accounts traded;", round(float(gross.sum() / turnover.sum() * 10000), 2), "bps break-even")# The break-even cost of a small example
import numpy as np
gross = np.array([0.004, 0.002, 0.003, 0.001, 0.002])
positions = np.array([1.0, 1.0, -1.0, -1.0, 0.0])
turnover = np.abs(np.diff(positions, prepend=0.0))
breakeven = gross.sum() / turnover.sum() * 10000
print(round(float(breakeven), 2)) # 30.0 bps per unit traded
print(abs(round(float((gross - turnover * breakeven / 10000).sum()), 10))) # 0.0: the whole profit is gone成本不只是佣金固定基点收费是最简单的模型。真实成本还取决于品种、一天中的时间和订单大小:小盘股和开盘时价差更大,大单还会把价格推向对你不利的方向,这是接下来几节的主题。无论用什么模型,忽略成本的回测都过于乐观,成本估得太低的回测则很危险。
- 成本以成交金额的基点报价:
abs(notional) * bps / 10000,买卖相同。 - 换手率是
abs(仓位变化)(翻转为 2);净收益 = 毛收益 - 换手率 * bps / 10000。 - 盈亏平衡成本
sum(gross) / sum(turnover) * 10000显示策略能承受多少成本;与实际成本对比。
下一节:滑点,预期价格与实际成交价格之间的差距。
实验:评分内容
- 用
trade_cost给一笔交易定价25 分 - 用
turnover统计交易量25 分 - 用
net_returns扣除成本25 分 - 用
breakeven_bps找出让利润归零的成本25 分