ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

克莱诺趋势跟踪:50/100 EMA与ATR仓位管理实战

克莱诺趋势跟踪:50/100 EMA与ATR仓位管理实战 做趋势跟踪这些年被问得最多的一个问题就是为什么你一套信号能同时跑几十个品种还不用天天调参数我一般会先把安德烈亚斯·克莱诺Andreas Clenow那套框架甩出来。它不是最赚钱的但它是最讲得清楚的。克莱诺是瑞士出身的管理人写过《Following the Trend》和《Stocks on the Move》前者把一整套期货趋势跟踪系统拆成了信号、仓位、组合三块规则干净到你可以在一张A4纸上写完。核心就三句话50日和100日指数移动平均线的交叉决定方向ATR平均真实波幅决定每个品种下多少手再用二三十个相关性不高的市场把单笔风险摊薄。它回答的不是明天涨还是跌而是在一个方向上我该拿多少仓位以及什么时候认输。这套东西适合有基础编程能力、能忍受30%级别回撤、愿意花时间搭数据管道的朋友如果你指望它月月正收益那还是早点关掉这一页。1. 克莱诺趋势跟踪到底在赚什么钱1.1 一笔交易的完整生命周期先把镜头拉近看一笔交易从头到尾长什么样这比上来丢公式好懂得多。假设账户权益100万美元交易标的取原油当前价格60美元/桶合约乘数是每手1000桶也就是价格每变动1美元一手盈亏1000美元。此刻算出来的100日ATR是1.5美元账户设定的单市场风险因子是0.3%也就是单笔愿意承担3000美元的波动。手数怎么算把我愿意亏多少钱除以一手一个ATR波动值多少钱。一手一个ATR的价值是 1.5 × 1000 1500美元所以手数 3000 ÷ 1500 2手。注意这里算的是ATR价值不是价格乘以乘数——ATR本身已经是价格单位乘上乘数就换算成了美元。这一步是整套系统的地基后面所有花活都建立在这个换算上。开仓条件也很直白当50日EMA上穿100日EMA做多2手反过来下穿就做空2手。假设我们在这里做多2手。接下来会发生两种情况。一种是价格顺着走涨到72美元浮盈已经是 (72-60) × 1000 × 2 24000美元此时EMA50大概率还在EMA100上方那就继续拿一个字都不改。另一种是价格掉头ATR从1.5涨到2.0这时候一手一个ATR的价值变成2000美元按0.3%风险重新算手数应该是 3000 ÷ 2000 1.5手也就是要减到1手或2手——减仓的动作就发生在这里。平仓信号只有一个EMA50反向穿越EMA100。没有固定止盈没有目标价也没有赚够了先跑。整个生命周期里你只做两件事——顺着均线方向待在场上以及按波动率调整手数。听起来过于简单但正是因为简单才不容易在执行层面走样。1.2 收益到底从哪来不是预测是盈亏比的错配很多人第一次看到这套规则会问均线交叉明明滞后怎么可能赚钱答案在于这套系统根本不依赖预测准确率。它的胜率通常在35%到45%之间也就是说超过一半的交易是亏的。赚钱靠的是另一头的分布——赢的那些单子平均盈利往往是平均亏损的三到五倍。这背后的逻辑是均线交叉在震荡区间会频繁被打脸每次亏掉一到两个ATR但只要某一次踩上了一个持续半年甚至一年的大趋势那笔交易的利润可能是十几个甚至几十个ATR。市场在宏观层面确实存在持续性利率周期、产业供需周期、资本在国别之间的流动这些东西一旦转向很少是三五天就结束的。趋势跟踪吃的就是这段惯性。我自己的感受是这套系统的痛苦点极其集中——它一定是小亏、小亏、小亏、小赚、小亏、大赚这种节奏。连续七八笔亏损是家常便饭而且往往发生在市场横盘期那段时间你每天看着别的策略在赚钱自己却在原地打转非常考验人。能不能扛过这段比参数调得多漂亮重要得多。1.3 这套框架适合谁不适合谁适配维度适合的特征不适合的特征资金规模建议20万以上能覆盖多品种保证金与分散要求几万块还想跑20个品种手续费会吃掉一切技术能力会Python/任意脚本语言能自己拼数据管道只会用现成软件拖拽遇到连续合约就卡住心理承受能接受连续数月回撤、年度负收益每天必须看到浮盈回撤5%就失眠时间投入每周能抽出固定时间做再平衡和检查期望完全躺平、几个月不看一眼收益预期长期年化个位数到十几个百分点靠杠杆调节指望年化翻倍、月月新高我在实际使用中发现最大的门槛不是策略本身而是能不能忍住不动。克莱诺这套东西最大的好处是——它把每一个决策都固定下来了你没有空间去发挥我觉得这次不一样。如果你天性喜欢临场判断这套系统会让你难受得抓狂。2. 三大核心组件拆解2.1 信号层为什么偏偏是50和100这两条均线信号层是整个策略里最容易被人质疑的地方凭什么50和100为什么不用20和60为什么不用MACD这个问题我拆成三层来回答。第一层是EMA和SMA的区别。指数移动平均线对最近的价格给更高权重简单移动平均线则是等权。用EMA的好处是反应快一轮趋势启动之后EMA通常比同周期的SMA早一到两周完成交叉。这一到两周对趋势跟踪很关键因为大部分趋势跟踪的利润都来自趋势最陡的那一段进场晚两周可能就把最肥的一段让出去了。代价是EMA在震荡区间更容易被假信号扎到交叉频率更高但趋势跟踪本来就不怕多交易怕的是错过趋势。第二层是50和100这两个数值的由来。克莱诺自己在书里说得很清楚这不是优化出来的结果而是一个够慢但不过慢的折中。50日在日线上大约对应两个半月的交易日100日大约是五个月。前者过滤掉了大部分日内和短周期的噪音后者提供了一条更迟钝的基准线。两条线的间距本身就构成了一个滞后缓冲带只有当价格把这条缓冲带彻底推过去才认为是趋势变了。第三层是参数敏感性的自检。这一点很重要也是判断一套策略是不是过拟合的关键。你把50/100换成40/80或者60/120回测曲线的形状大体相似年化收益会有几个百分点的差异但不会出现50/100赚钱、51/101亏钱这种断崖。如果出现断崖那说明你在拟合噪音不是在捕捉趋势。我自己的做法是在40到60、80到120这个区间里扫一遍只要大部分组合的结果落在同一个量级这套参数就是可用的如果只有一两个点特别漂亮那基本就是运气。2.2 仓位层ATR是整套系统的地基如果说信号层决定往哪边站那仓位层决定站多重而后者对最终收益曲线的影响其实更大。很多人搭趋势跟踪系统时信号做得花里胡哨仓位却是固定手数结果就是高波动品种比如某些农产品一波动就把账户打穿低波动品种比如利率期货则毫无贡献。ATR的计算方式要先说清楚。真实波幅TR取三个值里的最大值当日最高减当日最低、当日最高减前一日收盘的绝对值、当日最低减前一日收盘的绝对值。取绝对值是因为跳空缺口也要算进波动里不能只看日内振幅。把这100个交易日的TR做简单平均就是100日ATR。用简单平均而不是EMA是因为这里要的是稳定的波动率估计不需要它反应那么快。为什么要用100日这种慢周期因为波动率本身是均值回归的短周期ATR会在恐慌时突然拉高、在平静时突然塌下去用它算手数会导致仓位忽大忽小来回被摩擦成本割。100日ATR平滑得多仓位变化更温和。代价是对突发的波动率跳变反应迟钝所以后面要配一个杠杆上限来兜底。手数公式的正确写法是手数 (账户权益 × 单市场风险因子) ÷ (ATR × 合约乘数)其中ATR × 合约乘数就是一手在一个ATR波动下的美元价值。这个公式的直觉是不管这个品种的绝对价格是多少、波动多大我都让每一手在我账户里占据相同的风险预算。价格1000的品种和价格2的品种在同一个账户里说话的份量是一样的这就是风险等价。举个实际计算的例子。账户50万美元风险因子0.2%即1000美元。品种是黄金合约乘数100盎司当前100日ATR是18美元。一手一个ATR的价值 18 × 100 1800美元手数 1000 ÷ 1800 ≈ 0.56手四舍五入到0或者1。这种结果说明账户规模对这个品种来说偏小很多小账户跑来跑去最后发现只能做1手分散效果大打折扣这就是前面说资金规模门槛的原因。把风险因子提到0.5%手数变成 2500 ÷ 1800 ≈ 1.39也就是1手勉强能做。提示算出来的手数小于1时不要为了凑够一手去抬高风险因子。宁可这个品种不做也不要让单笔风险超过预算。这是新手最容易破的戒。2.3 组合层分散是这套系统里唯一的免费午餐单品种的趋势跟踪收益曲线会难看得让人怀疑人生。克莱诺整套方法真正的威力在组合层他反复强调市场数量的重要性——能跑40个品种就不要只跑10个。原因不复杂。趋势跟踪靠的是少数几笔大赢。如果你只跑5个品种一年下来可能只有两三笔踩上趋势运气成分极大跑40个相关性不高的品种就是在把同一年里谁踩上趋势这件事变成一次概率抽样靠大数定律把方差压下来。我做过一个粗略的对照同样的信号和参数跑10个品种时最大回撤能到40%以上跑40个品种时最大回撤通常能压到20%到25%的区间。收益未必提高但曲线的可承受度完全不是一个级别。市场池的构建有几个要点。第一是覆盖不同板块能源原油、燃料油、天然气、贵金属黄金、白银、工业金属铜、铝、锌、农产品大豆、玉米、小麦、白糖、棉花、利率各国国债期货、股指、外汇。第二是每个板块内部的品种不要太多否则相关性很高等于重复下注。第三是同一个品种不要同时用近月和远月两个合约那更是自己和自己对冲。资金分配上有两种做法。一种是等风险分配每个品种的风险预算一样这个最省事也最接近克莱诺的原意。另一种是按相关性做加权给相关性低的品种更高权重。第二种听起来聪明实际做起来很容易陷入用历史相关性预测未来相关性的陷阱因为相关性本身在危机时会突然全部趋同——平时看起来不相干的品种一旦出现系统性波动全都在同一个方向动。我个人的偏好是等风险打底只在明显重复的品种之间做减法。再平衡的节奏也需要定死。仓位会因为价格变动和ATR变化而偏离目标太久不调实际风险会漂移得离谱。常见做法是每周固定时间检查一次当实际手数与目标手数偏离超过一个合约就调整。也有每天调的版本但交易成本会上去。我的建议是先在回测里比较每周和每天的差异如果收益差距不大就选每周把成本省下来。3. 手把手复现从数据到信号3.1 数据准备与连续合约处理这一步是绝大多数人翻车的地方也是最容易被忽略的。期货和股票不一样单个合约有到期日你不可能拿一个三个月后就要交割的合约去做五个月的均线。必须拼一条连续价格序列。拼接方式有三种各有代价。第一种是直接换月到期就切到下个月简单但在换月当天会有一个价格跳空这个跳空会被均线当成一次剧烈的趋势信号产生假信号。第二种是价差调整差分复权把历史合约价格整体加减一个常数让换月点的价差为零价格跳空消失了但会出现负价格这种不合理的情况。第三种是比例调整后复权把历史价格乘一个比例因子保持价格的相对关系不会出现负数是目前比较常用的做法。无论用哪种都要记住一条调整后的价格只能用来算信号和ATR真实的下单价格必须用当前实际合约的价格盈亏结算也要用实际价格。把这两者混在一起回测出来的绝对盈亏会完全失真。数据源方面能拿到本地历史数据最好至少要保证日线的开、高、低、收四个字段齐全没有明显缺失主力合约的换月规则固定下来。缺失值不要简单前向填充会人为压低ATR宁可那天不做信号。3.2 从ATR到目标手数一次完整的参数选择拿一个具体场景走一遍。账户权益80万美元市场池里放了25个品种单市场风险因子定为0.15%。为什么是0.15%可以粗略反推25个品种如果全部同时持仓理论上最大总风险敞口是 25 × 0.15% 3.75% 的权益对应一个ATR的平均不利波动。考虑到实际不会同时全部满仓、也不会所有品种同向这个数字在可接受范围内。如果品种数降到10个我会把单市场因子提到0.3%左右保持总敞口量级差不多。以铜为例。假设铜价7000合约乘数25吨/手100日ATR为120美元。一手一个ATR的价值 120 × 25 3000美元。目标手数 (800000 × 0.0015) ÷ 3000 1200 ÷ 3000 0.4手。又是小于1说明这个账户对铜来说偏小。这时候有两个选择把品种池缩小到15个、把单市场因子提到0.25%那么手数 (800000×0.0025)÷3000 0.67手还是不到1或者接受只能做1手然后把这1手视为轻微超配。我一般会选后者但要在这个品种的权重上打个标记组合层面做一次归一化不让它意外占太大权重。注意手数取整会带来系统性偏差。所有品种都向下取整会让实际风险低于目标账户长期偏保守全部四舍五入则可能在某些品种上超配。稳妥的做法是取整后统计一遍各品种的实际风险占比若某个品种偏离目标超过50%就手动修正。3.3 Python实现信号、ATR、手数一条龙下面这段代码是我自己用的骨架省略了数据读取部分重点看逻辑。import numpy as np import pandas as pd def ema(series, span): return series.ewm(spanspan, adjustFalse).mean() def atr_simple(df, window100): 简单平均版ATRdf需含 high/low/close prev_close df[close].shift(1) tr pd.concat([ df[high] - df[low], (df[high] - prev_close).abs(), (df[low] - prev_close).abs() ], axis1).max(axis1) return tr.rolling(window).mean() def build_signals(df, fast50, slow100, atr_window100): df df.copy() df[ema_f] ema(df[close], fast) df[ema_s] ema(df[close], slow) df[atr] atr_simple(df, atr_window) # 1 多头-1 空头0 数据不足 cond df[ema_f].notna() df[ema_s].notna() df[atr].notna() df[signal] 0 df.loc[cond (df[ema_f] df[ema_s]), signal] 1 df.loc[cond (df[ema_f] df[ema_s]), signal] -1 return df def target_contracts(equity, atr_value, point_value, risk0.0015, k1.0): k1 线性仓位k1 指数化收缩高波动品种 if atr_value is None or atr_value 0 or point_value 0: return 0 raw (equity * risk) / ((atr_value ** k) * point_value) return raw # 取整交给上层方便统计四舍五入偏差逐段解释一下。atr_simple里的三个分量分别对应日内振幅、向上跳空、向下跳空取最大值这一动作不能省。build_signals的写法刻意避开了np.where因为用loc赋值能保证在数据不足的前100根K线上留下0而不是NaN后续统计胜率时不会算错。target_contracts里的k参数是留给下一节的扩展位先把它设为1.0就是最朴素的线性版本。跑完信号之后组合层面的循环大致是这样的逻辑每天遍历所有品种取当日信号和ATR算出目标手数与当前持仓比对差额部分按当日收盘或次日开盘成交成交价加上一个滑点假设通常按半个到一个最小变动价位算。整个循环里唯一需要小心的是成交时序——用当日收盘价算出来的信号绝不能用当日收盘价成交至少也要推到次日开盘否则回测会凭空多出一块不存在的收益。4. 参数与细节决定成败的那些魔鬼4.1 线性仓位还是指数化仓位克莱诺在书里花了不小篇幅讨论指数化仓位这个概念这是很多人读的时候会跳过去、但实际影响很大的部分。线性版本k1的手数与ATR成反比ATR翻倍手数减半。指数化版本则让手数与ATR的k次方成反比k取1.5或2。差别在哪举个例子。品种A的ATR是1品种B的ATR是4两者价格单位不同但已经换算成美元波动。线性版本下B的手数是A的四分之一。如果k2B的手数是A的十六分之一。也就是说指数化版本对高波动品种的惩罚要狠得多。为什么要这么做因为现实中的波动率分布有肥尾ATR从1涨到4往往不是平静变成普通而是普通变成极端。线性收缩在这种时候还是给得太多了而极端波动往往伴随着流动性变差和跳空风险实际亏损可能远超ATR的估计。指数化相当于给这类情况加了一层保险。代价是显而易见的你会系统性地少配高波动品种而这些品种恰恰经常贡献最大的趋势利润。k越高组合越温吞回撤更小但收益也更低。我自己试下来k在1.0到1.5之间比较平衡k2会明显牺牲收益。这个参数没有标准答案取决于你更怕回撤还是更怕收益不够。我的建议是先用k1把整套流程跑通并确认没有bug再去试k的取值否则你无法判断结果差异是来自参数还是来自代码。还有一点要注意指数化之后手数的量级会变必须重新做一次归一化否则整体杠杆会失控。常见做法是在回测初期用一段样本算出平均手数然后调一个缩放常数让两版的平均总持仓量级接近这样两者才有可比性。4.2 杠杆上限与波动率目标整套系统里最容易失控的地方在总杠杆。如果某段时间所有品种的ATR都掉到很低按公式算出来的手数会集体膨胀组合总持仓名义价值可能达到权益的好几倍。这不是理论问题是真实会发生的——波动率低谷期往往就是这种状态。两道闸门必须设。第一道是单品种的上限比如单个品种的名义价值不超过权益的30%。第二道是组合总杠杆上限比如所有持仓的名义价值合计不超过权益的3倍。这两条线不参与信号计算只在仓位生成后做一次裁剪裁掉的部分就是放弃的收益换成的是活下来。波动率目标则是另一种思路先定一个组合层面的目标年化波动率比如10%然后根据近期的组合波动率估计整体放大或缩小所有仓位。这个方法听起来优雅但实际用起来有个大坑——波动率估计本身是滞后的等到你发现波动率上来了损失已经发生了。而且它容易和趋势信号打架趋势最猛的时候波动率往往最高按目标波动率一缩放反而在最该重仓的时候减仓了。我自己的做法是不用组合级波动率目标只用上面那两道硬上限简单、可预测、不会在关键时刻帮倒忙。4.3 回测里最容易骗自己的五个地方第一是幸存者偏差。如果你只拿今天还在活跃的品种做回测那些因为流动性枯竭、合约规则变更而退出的品种就消失了你看到的收益会系统性偏高。解决办法是尽量用历史某个时间点的品种池来跑而不是用今天的品种池。第二是成本估算。趋势跟踪换手不算高但也不算低一年下来单品种换手几到十几次是常态。手续费加上滑点如果按每笔往返千分之几来算长期能吃掉不少收益。回测里一定要把滑点设成不低于一个最小变动价位尤其是那些流动性一般的品种。第三是成交价假设。前面提过一次这里再强调用收盘价算信号、用收盘价成交是最常见也最致命的错误。趋势跟踪的收益有大半来自趋势突破那几天的连续行情这几天的收益凭空到手回测曲线会漂亮得不像话。老老实实推到次日开盘或者用当日收盘加上不利滑点。第四是数据质量。连续合约的拼接方式、除权处理、异常跳点这些都会在均线上留下痕迹而均线对异常点很敏感——一个错的价格可能让50日和100日的交叉提前十天发生。回测前一定要做一次数据体检看有没有单日涨跌超过30%却没有明显消息支持的点了看有没有连续几天价格完全不动看换月点的跳空是否被正确抹平。第五是过拟合的自欺。很多人跑完回测之后发现某段时间表现不好就回去调参数、加一个只在波动率低于某阈值时开仓的过滤器曲线立刻好看了。这个动作本身没错但你是在用全样本数据做决策得到的参数已经不干净了。检验方法是把数据切成前半段和后半段只用前半段调参看后半段是否还行。如果后半段崩了那这个过滤器就是为历史量身定做的。5. 常见问题与排查实录5.1 回测很漂亮实盘却像换了一套策略这是被问到频率最高的问题我把它拆成几个具体的排查方向。先看成交假设。回测里如果用收盘价成交实盘用市价单在开盘或者盘中成交光是这个差异就能解释一大部分落差。先做一次次开盘成交版本的回测看看曲线掉多少如果掉得厉害说明原来的收益本来就不是你的。再看合约选择。回测里也许用的是某条调整后的连续价格实盘却做的是特定月份合约两者的基差和展期成本完全不同。有些品种的展期成本一年下来能有百分之几这个在回测里如果没算进去就是凭空多出来的。然后看流动性。回测里假设每次都能按某个价格成交实盘可能只成交一部分。特别是小品种一旦你的手数超过了当日成交量的某个比例滑点会急剧放大。最后看样本。如果你的回测只覆盖了五年而这五年恰好是趋势明显的一段比如有一段持续的商品行情那回测结果本身就不具代表性。趋势跟踪最怕的就是把运气好的样本当成策略的能力。5.2 长回撤期怎么扛过去这套策略必然会有回撤期而且往往持续半年到一年半回撤幅度20%到35%都算正常。我在实盘里经历过的最长一次横盘是十一个月那段时间几乎每一笔开仓都被打回来。能做的只有三件事。第一是把风险预算缩小一点让回撤的绝对金额待在你心理能承受的范围内——这不是策略调整是仓位管理因为一个让你睡不着的仓位你一定会在最坏的时点手动干预。第二是严格按规则执行因为回撤期正是趋势跟踪在攒弹药的时候你在这个阶段停手等于把后面那波行情的入场券扔了。第三是做记录把每一次开平仓的原因写下来回撤结束后回看你会发现绝大部分亏损都来自正常的信号磨损而不是你哪里做错了。反面做法也要说清楚回撤的时候加品种、加杠杆、加过滤器是最容易把一个小问题变成大问题的操作。加品种作为分散是对的但要在策略平稳期做在回撤期临时加是在用未来的收益去赌当下的情绪。5.3 常见问题速查表现象最可能的原因排查动作回测收益远高于实盘用了收盘价成交或没算成本改成次开盘成交加上1倍最小变动价位的滑点信号频繁翻转均线参数太短或数据有跳点检查连续合约拼接确认没有异常单日跳空单品种亏损远超预期ATR被低估或取整后超配打印该品种的历史实际风险占比加单品种上限整体回撤超过40%品种太少或相关性太高统计品种池的相关性矩阵扩充到25个以上某些年份完全没收益该年市场处于横盘拉长样本看逐年统计贡献是否集中在少数年份换手成本吃掉一半利润再平衡过于频繁从每天改为每周或设置偏离阈值再调手数长期算出来小于1账户规模与品种池不匹配缩小品种池或提高风险因子重新算总敞口再补一个我踩过的坑曾经为了更精确把ATR周期从100改成20想着能更快适应波动。结果回测还行实盘里仓位天天变手续费和滑点把收益磨掉了一大截而且在波动率突然放大的那几天手数被砍得过狠错过了后半段趋势。改回100之后世界就安静了。趋势跟踪这类慢策略参数的慢不是缺陷是设计的一部分动它之前先想清楚自己在优化什么。我个人在实际操作中的体会是这套框架真正的价值不在于它有多聪明而在于它把所有决策都提前定死了让你在市场里只剩下执行这一个动作。你可以在信号层做文章也可以在仓位层玩出花但别同时改两处——那样你永远不知道自己赚的是哪一部分的钱。
返回列表