基于陈凯 (Chen Kai),交易之路 (Path to Trading) (2019)
陈凯的交易之路绘制了从新手散户到专业、系统化交易者的完整旅程。与许多专注于单一技术或秘密指标的中国交易书籍不同,陈凯认为交易成功源于五个支柱的整合:市场理解、完整的交易系统、有纪律的风险管理、心理成熟和持续的自我完善。缺少任何一个支柱最终都会摧毁交易者的账户。
本书扎根于中国市场的现实 — A股的T+1结算规则、10%涨跌停限制、散户主导地位、中国期货市场的独特行为,以及决定策略如何从西方教科书适应的监管环境。
陈凯为三类读者撰写:
交易不是关于预测;而是关于概率和过程。市场总是做不可预测的事情。交易者的工作不是准确判断方向,而是构建一个系统,在这个系统中,做对了能获得比做错了损失更多的东西,然后绝对一致地执行该系统。
陈凯反复强调:交易是一场修行 — "Trading is a practice of self-cultivation." 技术技能可能只占长期成功的30%。其余70%是心理纪律、情绪管理,以及在每种本能尖叫着偏离规则时遵循规则的能力。
初学者不知道他所不知道的。特征包括:
在重大亏损后(通常为资本的30-50%),交易者意识到有些根本错误。特征包括:
交易者有了突破性认识 — 通常不是关于技术,而是关于游戏的本质。常见认识包括:
交易者有一个可行的系统并理解其工作原理。这个阶段的挑战:
执行变得自动。交易者不再争论是否遵循系统;这样做就像呼吸一样自然。特征包括:
陈凯将完整交易系统定义为能够绝对具体地回答六个问题的系统。缺少任何一个的系统都是不完整的,在压力下会失败。
| 组成部分 | 它回答的问题 | 示例 |
|---|---|---|
| 市场选择 (品种选择) | 我交易什么? | 沪深300成分股中日均成交量 > 5000万人民币的股票 |
| 方向偏见 (方向判断) | 我是做多、做空还是两者? | 仅在周线MA20 > MA60时做多(上升趋势) |
| 入场信号 (入场信号) | 我何时精确入场? | 价格以成交量 > 1.5倍均值收于20日高点之上 |
| 出场信号 (出场信号) | 我何时精确出场 — 盈利和亏损? | 止损:入场价下方2x ATR。目标:3x ATR跟踪止损 |
| 仓位调整 (仓位管理) | 这笔交易我承担多少风险? | 每笔交易风险账户权益的1% |
| 交易管理 (交易管理) | 入场和出场之间我如何处理交易? | 在1R盈利时加仓;永不逆势加仓 |
陈凯按对长期盈利贡献的顺序排列组成部分:
每个组成部分必须在哲学上一致。将趋势跟踪入场与均值回归出场配对会产生混乱和不一致。陈凯提供了一致性测试:
混合两种哲学的元素是交易系统失败的最常见原因。
结构特征:
对系统设计的影响:
结构特征:
对系统设计的影响:
结构特征:
对系统设计的影响:
初学者:从A股开始。T+1约束实际上有助于防止冲动日内交易。涨跌停限制单日最大损失。在股票上实现持续盈利后至少一年再转向期货。
陈凯认为移动平均线是最重要的技术工具,因为它们是客观的、明确的,直接代表重要的事情:市场参与者在给定时期内支付的平均价格。
A股关键移动平均线:
| 均线周期 | 功能 | 常用中文术语 |
|---|---|---|
| 5日 | 非常短期趋势,激进时机 | 攻击线 (Attack Line) |
| 10日 | 短期趋势 | 操盘线 (Trading Line) |
| 20日 | 中期趋势 | 辅助线 (Support Line) |
| 60日 | 中期趋势,机构参考 | 生命线 (Lifeline) |
| 120日 | 半年趋势,牛熊分界 | 决策线 (Decision Line) |
| 250日 | 年度趋势,长期方向 | 趋势线 (Trend Line) |
基于均线的信号:
A股特定调整: 60日均线是最受关注的机构参考线。交易在60日均线上方的股票处于"牛市 territory";下方的处于"熊市 territory"。这条线在上升趋势中经常充当支撑,在下降趋势中充当阻力,因为机构算法参考它。
标准设置:MACD(12, 26, 9)。
A股背景下的关键信号:
标准设置:日线RSI(14),短期RSI(6)。
陈凯的A股 RSI框架:
标准设置:BB(20, 2)。
在A股中的应用:
陈凯的关键规则:永远不要同时使用超过三个指标。 指标的目的是过滤噪音,不是添加噪音。他推荐的组合:
在陈凯的框架中,趋势跟踪基于一个简单观察:市场大约30%的时间处于强劲趋势,70%处于震荡、无趋势区间。 趋势跟随者在70%期间接受亏损,以换取30%期间捕获大波动。
客观地使用两个标准定义趋势:
两个条件必须同时满足。显示更高高点但移动平均线纠缠的市场尚未处于确认的趋势中。
主要入场 — 突破 (突破入场):
次要入场 — 回撤 (回调入场):
止损 (止损):
跟踪止损 (移动止损):
目标 (止盈):
均值回归是趋势跟踪的补充策略。它利用了价格在显著偏离其均值后往往迅速恢复到该均值的观察。
陈凯明确警告:不要在强劲趋势中尝试均值回归。 反向交易趋势是快速摧毁资本的最快方式。
买入设置 (做多条件):
卖出设置 (做空条件,用于期货或退出多头仓位):
改编自亚历山大·埃尔德的概念,陈凯将三时间框架方法应用于A股交易:
| 屏幕 | 时间框架 | 目的 | 工具 |
|---|---|---|---|
| 屏幕1(战略) | 周线 | 确定主要趋势方向 | MA60,MACD零轴 |
| 屏幕2(战术) | 日线 | 识别设置并确认条件 | 布林带,RSI,成交量 |
| 屏幕3(执行) | 60分钟 | 时机精确入场和出场 | 价格行为,MA5/MA10交叉 |
当所有三个时间框架一致时,最有利可图的交易发生。陈凯称之为共振:
当时间框架冲突时(例如,周线看涨但日线看跌),正确行动是等待。在模糊条件下强制交易违反了在条件清晰时才交易的原则。
陈凯称仓位调整为"交易中最重要和最被忽视的方面。" 胜率60%、奖励风险比2:1的系统仍然可能摧毁账户,如果每笔交易风险20%资本的话。相反,胜率40%的系统如果每笔交易只风险1%可以稳定积累财富。
核心规则:每笔交易风险当前账户权益的固定百分比。
仓位 = (账户权益 × 风险百分比) / (入场价 - 止损价)
推荐风险百分比:
| 交易者级别 | 每笔交易风险 | 最大同时风险 |
|---|---|---|
| 初学者 | 0.5% | 3%总计 |
| 中级 | 1.0% | 6%总计 |
| 高级 | 2.0% | 10%总计 |
示例:账户权益 = 500,000人民币。每笔交易风险 = 1% = 5,000。入场合 = 25.00。止损价 = 23.50。每份风险 = 1.50。仓位 = 5,000 / 1.50 = 3,333股。取整至A股最接近手数(100股)= 3,300股。所需资本 = 3,300 × 25.00 = 82,500人民币。
凯利最优赌注调整公式:
f = (bp - q) / b
其中f = 资本比例,b = 盈亏比,p = 盈利概率,q = 亏损概率。
陈凯解释全凯利对实际交易来说太激进。他推荐四分之一凯利或半凯利以考虑:
向盈利者加仓 (加仓):
分批出场 (分批出场):
永远不要同时持有超过3个高度相关的仓位。中国银行股(例如工商银行、建设银行、中国银行、农业银行)几乎同步波动。以每笔1%风险持有4只银行股不是4%风险 — 实际上是对银行板块的单一4%赌注。
| 级别 | 范围 | 最大损失 | 触发时的行动 |
|---|---|---|---|
| 交易风险 | 单笔持仓 | 权益的1-2% | 自动执行止损 |
| 日风险 | 一天内所有交易 | 权益的3% | 当天停止交易 |
| 回撤风险 | 滚动峰值到谷值 | 峰值权益的15% | 仓位减半50%;在20%时停止交易2周 |
当账户回撤达到10%时,实施以下措施:
当账户回撤达到15%时:
当账户回撤达到20%时:
由于A股受T+1约束,交易者无法在同日入场的当天退出持仓。这创造了独特的隔夜缺口风险。缓解策略:
陈凯描述每个交易者都会经历的反复情绪周期:
兴奋(新车)→ 焦虑(回撤)→ 恐惧(止损触发)→
沮丧(连续亏损)→ 报复(下一笔超额交易)→
否认(移除止损)→ 投降(恐慌性卖出)→ 抑郁 →
决心(更多研究)→ 平静(新系统)→ 兴奋(新车)→ ...
打破这个周期需要意识、日志和覆盖情绪的规则。
恐惧 (恐惧):
贪婪 (贪婪):
希望 (希望):
后悔 (后悔):
陈凯的实际建议:
回测有一个目的:确定系统是否有真正的统计优势还是过去利润归因于运气。未在统计显著样本上回测的系统是赌博,不是策略。
| 指标 | 可接受范围 | 理想范围 |
|---|---|---|
| 胜率 | > 35%(趋势)/ > 55%(回归) | > 45%(趋势)/ > 65%(回归) |
| 利润因子 | > 1.5 | > 2.0 |
| 平均盈利/平均亏损 | > 2.0(趋势)/ > 0.8(回归) | > 3.0(趋势)/ > 1.2(回归) |
| 最大回撤 | < 25% | < 15% |
| 年化夏普比率 | > 0.8 | > 1.5 |
| 连续亏损次数 | < 10 | < 7 |
| 恢复因子(净利润 / 最大DD) | > 3.0 | > 5.0 |
过度拟合是回测中最大的危险。陈凯的规则:
交易日志是交易者的镜子。没有它,自我评估基于记忆,而记忆是有选择性和有偏的。交易者记得最好和最差的交易,但忘记了决定长期结果的普通多数。
每笔交易数据:
| 字段 | 示例 |
|---|---|
| 日期/时间 | 2019-03-15 14:45 |
| 品种 | 600519(贵州茅台) |
| 方向 | 做多 |
| 入场价 | 780.00 |
| 止损 | 748.00 |
| 目标 | 20日均线跟踪止损 |
| 仓位 | 200股 |
| 资本风险 | 6,400人民币(权益的0.8%) |
| 理由 | 周线上升趋势,日线回撤至MA20,RSI从45反弹 |
| 入场时情绪状态 | 平静,对设置有信心 |
| 出场价 | 825.00 |
| 出场日期 | 2019-04-02 |
| 盈亏 | +9,000人民币(+1.12R) |
| 教训 | 持有初始回撤;系统按设计工作 |
每周回顾: 总结盈亏统计、最大盈利、最大亏损、任何规则违规、观察到的情绪模式。
每月回顾: 计算运行夏普比率、回撤、利润因子。将实际表现与回测期望比较。识别任何环境变化(市场状态变化)是否影响表现。
陈凯规定特定的盘前程序:
| # | 错误 | 为何致命 |
|---|---|---|
| 1 | 无止损 | 单个灾难性亏损可能抹去数月收益 |
| 2 | 逆势加仓 | 好钱追坏钱;随着论点恶化,仓位增加 |
| 3 | 超额仓位 | 即使正确的交易如果太大也会造成毁灭性回撤 |
| 4 | 无计划交易 | 没有预定框架时,每个决策都是情绪化的 |
| 5 | 系统跳转 | 在正常回撤期间放弃有效系统;从不给优势展现的机会 |
| 6 | 指标过载 | 更多指标产生更多矛盾,导致瘫痪或 cherry-picking |
| 7 | 忽略趋势 | 在下降趋势中买"便宜"股票;在上升趋势中做空"昂贵"股票 |
| 8 | 追涨 (追涨停) | 在10%涨跌停时买入股票期望继续;高风险,流动性差的出场 |
| 9 | 满仓操作 (满仓操作) | 把100%资本放在一笔交易或一个板块;没有安全边际 |
| 10 | 根据消息交易 | 他人的分析不是你的优势;你不会知道他们何时改变主意 |
| 11 | 忽略交易成本 | A股频繁交易(印花税 + 佣金)迅速侵蚀回报 |
| 12 | 忽视宏观环境 | 交易个股时不关注市场整体状况(例如央行收紧) |
| 13 | 拒绝休息 | 倦怠降低决策质量;休息是风险管理工具 |
日期:2019年3月13日,星期三
品种:000858(五粮液)
账户权益:800,000人民币。每笔交易风险:1% = 8,000人民币。
| 指标 | 值 |
|---|---|
| 总利润 | 27,480人民币 |
| 资本回报率 | 27,480 / 8,000 = 3.44R |
| 持仓期 | 18个交易日 |
| 最大不利偏移 | -1,080人民币(第1天日内低点72.90) |
| 最大有利偏移 | +40,680人民币(峰值84.50) |
| 捕获比率 | 27,480 / 40,680 = 67.5%的波动 |
class TradingSystem:
config:
risk_per_trade = 0.01 # 权益的1%
max_concurrent_positions = 5
max_daily_loss = 0.03 # 权益的3%
max_drawdown_threshold = 0.15 # 从峰值下跌15%
atr_period = 14
ma_fast = 20
ma_slow = 60
rsi_period = 14
bb_period = 20
bb_std = 2.0
state:
account_equity = initial_capital
peak_equity = initial_capital
open_positions = []
daily_pnl = 0.0
is_halted = false
function on_daily_close(market_data):
if is_halted:
check_halt_conditions()
return
update_equity()
check_circuit_breakers()
if daily_pnl <= -max_daily_loss * account_equity:
log("日损失限额达到。今天不进行新交易。")
return
# 屏幕1:周线趋势过滤器
weekly_trend = assess_weekly_trend(market_data)
# 管理现有持仓
for position in open_positions:
manage_position(position, market_data)
# 如果有容量则扫描新入场
if len(open_positions) < max_concurrent_positions:
candidates = scan_for_setups(market_data, weekly_trend)
for candidate in candidates:
if passes_correlation_filter(candidate, open_positions):
execute_entry(candidate)
function assess_weekly_trend(data):
weekly_ma20 = moving_average(data.weekly_close, 20)
weekly_ma60 = moving_average(data.weekly_close, 60)
weekly_macd = macd(data.weekly_close, 12, 26, 9)
if weekly_ma20 > weekly_ma60 and weekly_macd.histogram > 0:
return BULLISH
elif weekly_ma20 < weekly_ma60 and weekly_macd.histogram < 0:
return BEARISH
else:
return NEUTRAL
function scan_for_setups(data, weekly_trend):
setups = []
for stock in universe:
if weekly_trend == BULLISH:
if is_trend_pullback_buy(stock, data):
setups.append(create_trade_plan(stock, LONG, "PULLBACK"))
elif is_breakout_buy(stock, data):
setups.append(create_trade_plan(stock, LONG, "BREAKOUT"))
elif weekly_trend == BEARISH:
# A股:离场;期货:寻找做空
pass
else:
if is_mean_reversion_buy(stock, data):
setups.append(create_trade_plan(stock, LONG, "REVERSION"))
return setups
function is_trend_pullback_buy(stock, data):
close = data.daily_close[stock]
ma20 = moving_average(close, 20)
ma60 = moving_average(close, 60)
rsi = compute_rsi(close, rsi_period)
volume = data.daily_volume[stock]
avg_volume = moving_average(volume, 20)
conditions:
close[-1] > ma60[-1] # 高于60日均线
ma20[-1] > ma60[-1] # 均线排列看涨
close[-1] <= ma20[-1] * 1.02 # 价格接近20日均线
close[-2] > ma20[-2] or close[-3] > ma20[-3] # 最近回撤
rsi[-1] > 40 and rsi[-1] < 60 # RSI在中性区域
volume[-1] < avg_volume[-1] # 回撤时成交量下降
return all(conditions)
function is_breakout_buy(stock, data):
close = data.daily_close[stock]
high_20 = max(close[-21:-1]) # 20日最高收盘价
volume = data.daily_volume[stock]
avg_volume = moving_average(volume, 20)
ma60 = moving_average(close, 60)
conditions:
close[-1] > high_20 # 收盘突破
close[-1] > ma60[-1] # 高于60日均线
volume[-1] > avg_volume[-1] * 1.5 # 成交量确认
return all(conditions)
function is_mean_reversion_buy(stock, data):
close = data.daily_close[stock]
bb = bollinger_bands(close, bb_period, bb_std)
rsi = compute_rsi(close, rsi_period)
ma250 = moving_average(close, 250)
conditions:
close[-1] <= bb.lower[-1] # 在或低于下轨
rsi[-1] < 30 # 超卖
close[-1] > ma250[-1] # 高于250日均线(结构性上升趋势)
is_bullish_reversal_candle(data, stock) # 反转形态
return all(conditions)
function create_trade_plan(stock, direction, strategy):
atr = compute_atr(stock, atr_period)
entry_price = current_price(stock)
if strategy == "PULLBACK" or strategy == "BREAKOUT":
stop_loss = entry_price - 2.0 * atr
stop_loss = max(stop_loss, entry_price * 0.92) # 最大8%止损
elif strategy == "REVERSION":
stop_loss = entry_price - 1.5 * atr
target = moving_average(stock.close, 20)[-1] # 均值目标
risk_per_share = entry_price - stop_loss
shares = floor((account_equity * risk_per_trade) / risk_per_share)
shares = round_to_lot(shares, 100) # A股手数
return TradePlan(stock, direction, strategy,
entry_price, stop_loss, shares, atr)
function manage_position(position, data):
current = data.daily_close[position.stock][-1]
# 检查止损
if current <= position.stop_loss:
execute_exit(position, current, "STOP_LOSS")
return
# 更新趋势交易的跟踪止损
if position.strategy in ["PULLBACK", "BREAKOUT"]:
highest_since_entry = max(closes since position.entry_date)
new_trail = highest_since_entry - 2.0 * position.atr
if new_trail > position.stop_loss:
position.stop_loss = new_trail
log(f"跟踪止损更新至 {new_trail}")
# 在2R时分批出场
profit_r = (current - position.entry_price) / position.initial_risk
if profit_r >= 2.0 and not position.scaled_out_1:
exit_shares = position.shares // 3
execute_partial_exit(position, exit_shares, current, "SCALE_2R")
position.scaled_out_1 = true
# 在4R时分批出场
if profit_r >= 4.0 and not position.scaled_out_2:
exit_shares = position.shares // 3
execute_partial_exit(position, exit_shares, current, "SCALE_4R")
position.scaled_out_2 = true
# 均值回归交易的时间止损
if position.strategy == "REVERSION":
days_held = trading_days_since(position.entry_date)
if days_held >= 5:
execute_exit(position, current, "TIME_STOP")
return
if current >= position.target:
execute_exit(position, current, "TARGET_HIT")
return
class RiskManager:
state:
peak_equity
current_equity
daily_loss
consecutive_losses = 0
size_multiplier = 1.0
function check_circuit_breakers():
drawdown = (peak_equity - current_equity) / peak_equity
if drawdown >= 0.20:
halt_trading(duration_days=10)
size_multiplier = 0.25
alert("严重:20%回撤。停止交易10天。")
elif drawdown >= 0.15:
halt_trading(duration_days=5)
size_multiplier = 0.50
alert("警告:15%回撤。停止交易5天。")
elif drawdown >= 0.10:
size_multiplier = 0.50
alert("注意:10%回撤。仓位减半。")
else:
size_multiplier = 1.0
function check_daily_limit():
if daily_loss >= current_equity * 0.03:
return HALT_TODAY
return CONTINUE
function check_consecutive_losses(trade_result):
if trade_result.is_loss:
consecutive_losses += 1
else:
consecutive_losses = 0
if consecutive_losses >= 3:
alert("3次连续亏损。强制休息1天。")
return HALT_TOMORROW
function adjusted_position_size(base_size):
return floor(base_size * size_multiplier)
function check_correlation(new_stock, existing_positions):
for position in existing_positions:
corr = correlation(new_stock.returns_60d, position.stock.returns_60d)
if corr > 0.70:
return REJECT # 过于相关
sector_count = count_by_sector(existing_positions, new_stock.sector)
if sector_count >= 2:
return REJECT # 每板块最多2个
return ACCEPT
function update_peak():
if current_equity > peak_equity:
peak_equity = current_equity
class TradeJournal:
storage: database or spreadsheet
function record_entry(trade):
entry = {
id: generate_id(),
date: today(),
time: now(),
stock: trade.stock,
stock_name: trade.stock_name,
direction: trade.direction,
strategy: trade.strategy,
entry_price: trade.entry_price,
stop_loss: trade.stop_loss,
target: trade.target,
shares: trade.shares,
capital_risked: trade.risk_amount,
risk_pct: trade.risk_amount / account_equity,
rationale: trade.rationale, # 文本:为什么这笔交易?
weekly_trend: trade.weekly_trend,
daily_setup: trade.daily_setup,
emotional_state: prompt_user("评估你的情绪状态 1-5"),
confidence: prompt_user("评估你的信心 1-5"),
screenshot: capture_chart(trade.stock)
}
storage.insert(entry)
function record_exit(trade_id, exit_data):
update = {
exit_date: today(),
exit_price: exit_data.price,
exit_reason: exit_data.reason, # STOP_LOSS, TARGET, TRAIL, TIME, MANUAL
pnl_rmb: exit_data.pnl,
pnl_r: exit_data.pnl / original_risk,
holding_days: exit_data.days_held,
max_adverse_excursion: exit_data.mae,
max_favorable_excursion: exit_data.mfe,
capture_ratio: exit_data.pnl / exit_data.mfe,
emotional_state_exit: prompt_user("评估你的情绪状态 1-5"),
followed_rules: prompt_user("你是否遵守了所有规则? Y/N"),
lessons: prompt_user("这笔交易的主要教训是什么?")
}
storage.update(trade_id, update)
function weekly_review():
trades = get_trades_this_week()
report = {
total_trades: len(trades),
winners: count(t for t in trades if t.pnl > 0),
losers: count(t for t in trades if t.pnl <= 0),
win_rate: winners / total_trades,
total_pnl: sum(t.pnl for t in trades),
average_r: mean(t.pnl_r for t in trades),
largest_win: max(t.pnl for t in trades),
largest_loss: min(t.pnl for t in trades),
rule_violations: count(t for t in trades if not t.followed_rules),
avg_emotional_state: mean(t.emotional_state for t in trades)
}
print_report(report)
(文件已截断,原文共1034行)
实施规范编译自陈凯,交易之路。本文件是用于实际应用的系统化提炼,不替代阅读原作。