蜡烛图是期货市场中最重要的图形分析工具之一,每根蜡烛代表了一定时间段的市场活动。通过识别不同的蜡烛图形,我们可以推测出市场的情绪变化,从而制定相应的交易策略。基于这些蜡烛图形及其组合,结合量化指标来衡量市场的情绪波动(例如贪婪、恐惧和犹豫),形成一种动量趋势交易策略。这篇文章将通过蜡烛图形、各个量化指标的功能以及具体的开平仓逻辑来帮助您理解这个策略。
Doji (十字星)
Doji形态是指蜡烛的开盘价和收盘价几乎相同,蜡烛实体很小,上下影线较长。它代表市场处于犹豫状态,买卖双方的力量接近平衡。
作用: 在期货市场中,Doji通常出现在反转趋势的关键位置,标志着可能的趋势反转。
市场悄悄话:”现在多空打成平手,大家都很迷茫啊!”
Spinning Top (纺锤线)
旋转顶形态类似Doji,实体较小,但较Doji要大一些。它表示市场的犹豫不决,通常预示着震荡或短期的反转。
作用: 在上涨或下跌趋势中出现,常常意味着短期内价格波动会减弱。
市场悄悄话:”买卖双方在拔河,胜负难分!”
Shooting Star (射击之星)
射击之星是一根上影线非常长的蜡烛,实体较小,且下影线短。通常出现在上升趋势中,预示市场情绪转为看空。
作用: 在期货市场中,射击之星意味着买方失去控制,卖方可能即将主导市场。
期货作用:期货夜盘常见,特别是当大宗商品突发消息时。
Hanging Man (吊颈线)
吊人线和射击之星形态类似,但出现在下跌趋势的末端。它表示市场可能出现反弹,买方即将占上风。
作用: 吊人线在下跌趋势中出现时,暗示市场可能会在此处找到支撑并反弹。
市场悄悄话:”看着涨得欢,其实有人在偷偷出货!”
Engulfing (吞没形态)
吞没形态是一种强烈的反转信号,其中后一根蜡烛完全吞没前一根蜡烛的实体。看涨吞没通常预示着多头反攻的开始,而看跌吞没则表明空头力量加强。
作用: 吞没形态经常出现在大幅度的价格反转点。
市场悄悄话:”多头/空头发起总攻了!”
Marubozu (光头光脚)
Marubozu是一种没有上影线或下影线的蜡烛,表示强烈的市场情绪。它通常表示买方或卖方力量强劲。
作用: 出现Marubozu时,表明市场情绪较为极端,可能会继续沿着当前趋势发展。
市场悄悄话:”多头/空头完全掌控局面!”
Hammer (锤子线)
锤子线是一种下影线很长的蜡烛,实体较小,且接近价格区间的上部。它出现在下跌趋势末端,通常预示着市场可能会反弹。
作用: 锤子线通常意味着市场将出现反转或止跌,尤其是在低点区域。
市场悄悄话:”价格被打压后强势反弹!”
Three White Soldiers (三只白兵)
三只白兵是一种由三根连续上涨的蜡烛组成的形态,且每根蜡烛都比前一根大。它表明市场在强劲的多头推动下上涨。
作用: 这是一种非常强烈的上涨信号,表明市场很可能会继续上涨。
市场悄悄话:“多头力量不断积聚,市场准备继续上涨!”
本策略基于三种情绪震荡指标:犹豫震荡指标(Indecision Oscillator)、恐惧震荡指标(Fear Oscillator) 和 贪婪震荡指标(Greed Oscillator),这些指标通过识别不同的蜡烛图形来衡量市场情绪的变化。
该指标通过识别Doji和Spinning Top来衡量市场的犹豫不决。
// 检测是否为Doji(十字星)形态
isDoji(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算实体大小(开盘价与收盘价的差值)
rangeSize = high - low // 计算蜡烛的总范围(最高价与最低价的差值)
bodySize / rangeSize < threshold // 如果实体占总范围的比值小于阈值,则认为是Doji
// 检测是否为旋转顶形态(Spinning Top)
isSpinningTop(open, close, high, low, threshold) =>
bodySize = math.abs(close - open)
rangeSize = high - low
// 旋转顶要求实体占总范围的比值小于阈值,并且大于Doji阈值
bodySize / rangeSize < threshold and bodySize / rangeSize >= dojiThreshold
// 计算犹豫震荡指标
indecisionOscillator() =>
var float dojiScore = 0.0 // 初始化Doji形态的得分
var float spinningTopScore = 0.0 // 初始化旋转顶的得分
for i = 1 to length
if isDoji(open[i], close[i], high[i], low[i], dojiThreshold) // 检查Doji形态
dojiScore := dojiScore + 1.0
if isSpinningTop(open[i], close[i], high[i], low[i], spinningTopThreshold) // 检查旋转顶形态
spinningTopScore := spinningTopScore + 1.0
dojiScore := dojiScore / length // 计算Doji形态的得分比例
spinningTopScore := spinningTopScore / length // 计算旋转顶的得分比例
(dojiScore + spinningTopScore) / 2 // 返回两个形态的平均得分,作为犹豫震荡指标的结果
功能: 用于检测市场是否处于犹豫状态。通过识别Doji和旋转顶形态,来计算市场情绪的波动。
该指标通过识别Shooting Star、Hanging Man和Bearish Engulfing形态来衡量市场的恐惧情绪。
// 检测是否为射击之星
isShootingStar(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算蜡烛的实体大小
upperWick = high - math.max(open, close) // 上影线大小
lowerWick = math.min(open, close) - low // 下影线大小
upperWick / bodySize > threshold and lowerWick < bodySize // 上影线大且下影线小,符合射击之星条件
// 检测是否为吊颈线
isHangingMan(open, close, high, low, threshold) =>
bodySize = math.abs(close - open)
upperWick = high - math.max(open, close)
lowerWick = math.min(open, close) - low
lowerWick / bodySize > threshold and upperWick < bodySize // 下影线大,上影线小,符合吊人线条件
// 检测是否为看跌吞没形态
isBearishEngulfing(open, close, openPrev, closePrev, threshold) =>
bodySize = math.abs(close - open) // 当前蜡烛的实体大小
prevBodySize = math.abs(closePrev - openPrev) // 前一根蜡烛的实体大小
close < openPrev and open > closePrev and bodySize / prevBodySize > threshold // 当前蜡烛吞没前一根蜡烛并且实体大小更大
// 计算恐惧震荡指标
fearOscillator() =>
var float shootingStarScore = 0.0 // 初始化射击之星得分
var float hangingManScore = 0.0 // 初始化吊人线得分
var float engulfingScore = 0.0 // 初始化看跌吞没得分
for i = 1 to length
if isShootingStar(open[i], close[i], high[i], low[i], shootingStarThreshold) // 检查射击之星
shootingStarScore := shootingStarScore + 1.0
if isHangingMan(open[i], close[i], high[i], low[i], hangingManThreshold) // 检查吊颈线
hangingManScore := hangingManScore + 1.0
if isBearishEngulfing(open[i], close[i], open[i+1], close[i+1], engulfingThreshold) // 检查看跌吞没
engulfingScore := engulfingScore + 1.0
shootingStarScore := shootingStarScore / length // 计算射击之星的得分比例
hangingManScore := hangingManScore / length // 计算吊人线的得分比例
engulfingScore := engulfingScore / length // 计算看跌吞没的得分比例
(shootingStarScore + hangingManScore + engulfingScore) / 3 // 返回恐惧震荡指标的平均值
功能: 用于评估市场恐惧情绪的强度,基于射击之星、吊颈线和看跌吞没形态的频率。
该指标通过识别Marubozu、Hammer、Bullish Engulfing和Three White Soldiers形态来衡量市场的贪婪情绪。
// 检测是否为Marubozu(光头光脚)
isMarubozu(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算实体大小
totalRange = high - low // 计算蜡烛的总范围
bodySize / totalRange > threshold // 实体占总范围的比例大,表示为Marubozu形态
// 检测是否为锤子线
isHammer(open, close, high, low, threshold) =>
bodySize = math.abs(close - open)
lowerWick = math.min(open, close) - low
upperWick = high - math.max(open, close)
lowerWick / bodySize > threshold and upperWick < bodySize // 下影线大,符合锤子线的特征
// 检测是否为看涨吞没
isBullishEngulfing(open, close, openPrev, closePrev, threshold) =>
bodySize = math.abs(close - open)
prevBodySize = math.abs(closePrev - openPrev)
close > openPrev and open < closePrev and bodySize / prevBodySize > threshold // 当前蜡烛吞没前一根蜡烛,符合看涨吞没的条件
// 检测是否为三只白兵
isThreeWhiteSoldiers(open, close, openPrev, closePrev, openPrev2, closePrev2, threshold) =>
close > open and closePrev > openPrev and closePrev2 > openPrev2 and close > closePrev and closePrev > closePrev2 // 连续三根上涨蜡烛,符合三只白兵形态
// 计算贪婪震荡指标
greedOscillator() =>
var float marubozuScore = 0.0 // 初始化光头光脚得分
var float hammerScore = 0.0 // 初始化锤子线得分
var float engulfingScore = 0.0 // 初始化看涨吞没得分
var float soldiersScore = 0.0 // 初始化三只白兵得分
for i = 1 to length
if isMarubozu(open[i], close[i], high[i], low[i], marubozuThreshold) // 检查光头光脚
marubozuScore := marubozuScore + 1.0
if isHammer(open[i], close[i], high[i], low[i], hammerThreshold) // 检查锤子线
hammerScore := hammerScore + 1.0
if isBullishEngulfing(open[i], close[i], open[i+1], close[i+1], engulfingThreshold) // 检查看涨吞没
engulfingScore := engulfingScore + 1.0
if isThreeWhiteSoldiers(open[i], close[i], open[i+1], close[i+1], open[i+2], close[i+2], threeWhiteSoldiersThreshold) // 检查三只白兵
soldiersScore := soldiersScore + 1.0
marubozuScore := marubozuScore / length // 计算光头光脚的得分比例
hammerScore := hammerScore / length // 计算锤子线的得分比例
engulfingScore := engulfingScore / length // 计算看涨吞没的得分比例
soldiersScore := soldiersScore / length // 计算三只白兵的得分比例
(marubozuScore + hammerScore + engulfingScore + soldiersScore) / 4 // 返回贪婪震荡指标的平均值
功能: 用于评估市场的贪婪情绪,通过检测强势的上涨信号(如Marubozu、锤子线等)来衡量市场的买盘压力。
情绪指数三剑客
1. 犹豫指数:十字星+纺锤线,数值越高市场越像迷路的小孩
2. 恐慌指数:流星线+吊颈线+看跌吞噬,空头司令部集结号
3. 贪婪指数:光头线+锤子线+看涨吞噬,多头狂欢派对
当三个指数调和出的鸡尾酒浓度超过设定值:
- 做多信号:鸡尾酒浓度突破10%(可调节)
- 做空信号:鸡尾酒浓度突破20%(可调节)
风控三保险
1. 成交量认证:平仓时需要成交量是均量的1.5倍(可调节),避免假突破
2. 最长持仓时间:盈利单最多拿20根K线(约4个交易日)
3. 紧急逃生舱:亏损超2%或持仓10根K线仍亏损,强制止损
买入信号(Long Entry)
卖出信号(Take Profit / Stop Loss)
空仓信号(Short Entry)
空头平仓信号
通过这些蜡烛图形和情绪动量指标的结合,本策略旨在捕捉市场的情绪变化,制定合适的买卖决策,从而实现较为稳定的收益。
//@version=6
strategy("Candle Emotion Index Strategy", shorttitle="CEI Strategy", overlay=true)
// 用户输入参数
length = input.int(14, title="回看周期", minval=1) // 设置回看周期,默认为14
dojiThreshold = input.float(0.1, title="Doji 阈值", minval=0.01, maxval=0.5) // 设置Doji形态的阈值
spinningTopThreshold = input.float(0.3, title="旋转顶阈值", minval=0.1, maxval=0.5) // 设置旋转顶形态的阈值
shootingStarThreshold = input.float(0.5, title="射击之星阈值", minval=0.1, maxval=1.0) // 设置射击之星形态的阈值
hangingManThreshold = input.float(0.5, title="吊人线阈值", minval=0.1, maxval=1.0) // 设置吊人线形态的阈值
engulfingThreshold = input.float(0.5, title="吞没形态阈值", minval=0.1, maxval=1.0) // 设置吞没形态的阈值
marubozuThreshold = input.float(0.9, title="光头光脚阈值", minval=0.5, maxval=1.0) // 设置光头光脚形态的阈值
hammerThreshold = input.float(0.5, title="锤子线阈值", minval=0.1, maxval=1.0) // 设置锤子线形态的阈值
threeWhiteSoldiersThreshold = input.float(0.5, title="三只白兵阈值", minval=0.1, maxval=1.0) // 设置三只白兵形态的阈值
// 成交量倍数
volumeMultiplier = input.float(1.5, title="成交量倍数", minval=1.0) // 设置成交量倍数,用于平仓的条件判断
// 冷却期输入
cooldownPeriod = input.int(10, title="冷却期(蜡烛数)", minval=1) // 设置冷却期,表示每次交易后等待冷却的蜡烛数
// 最大持仓周期输入
maxHoldingPeriod = input.int(20, title="最大持仓周期(蜡烛数)", minval=1) // 设置最大持仓周期,限制持仓时间
lossHoldingPeriod = input.int(10, title="亏损退出持仓周期(蜡烛数)", minval=1) // 设置亏损退出持仓的最大周期
lossThreshold = input.float(0.02, title="亏损阈值(相对于开盘价的百分比)", minval=0.01, maxval=1.0) // 设置亏损阈值,当亏损达到此百分比时退出
// --- 犹豫震荡指标函数 ---
isDoji(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算蜡烛实体大小
rangeSize = high - low // 计算蜡烛的价格区间
bodySize / rangeSize < threshold // 若实体占总范围的比值小于阈值,认为是Doji
isSpinningTop(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算蜡烛实体大小
rangeSize = high - low // 计算蜡烛的价格区间
bodySize / rangeSize < threshold and bodySize / rangeSize >= dojiThreshold // 若实体占总范围的比值小于阈值,且大于Doji阈值,认为是旋转顶
indecisionOscillator() =>
var float dojiScore = 0.0 // 初始化Doji形态的得分
var float spinningTopScore = 0.0 // 初始化旋转顶形态的得分
for i = 1 to length
if isDoji(open[i], close[i], high[i], low[i], dojiThreshold) // 检测Doji形态
dojiScore := dojiScore + 1.0
if isSpinningTop(open[i], close[i], high[i], low[i], spinningTopThreshold) // 检测旋转顶形态
spinningTopScore := spinningTopScore + 1.0
dojiScore := dojiScore / length // 计算Doji形态得分的平均值
spinningTopScore := spinningTopScore / length // 计算旋转顶形态得分的平均值
(dojiScore + spinningTopScore) / 2 // 返回犹豫震荡指标的平均得分
// --- 恐惧震荡指标函数 ---
isShootingStar(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算蜡烛实体大小
upperWick = high - math.max(open, close) // 计算上影线长度
lowerWick = math.min(open, close) - low // 计算下影线长度
upperWick / bodySize > threshold and lowerWick < bodySize // 上影线较长且下影线较短,符合射击之星条件
isHangingMan(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算蜡烛实体大小
upperWick = high - math.max(open, close) // 计算上影线长度
lowerWick = math.min(open, close) - low // 计算下影线长度
lowerWick / bodySize > threshold and upperWick < bodySize // 下影线较长且上影线较短,符合吊人线条件
isBearishEngulfing(open, close, openPrev, closePrev, threshold) =>
bodySize = math.abs(close - open) // 当前蜡烛的实体大小
prevBodySize = math.abs(closePrev - openPrev) // 前一根蜡烛的实体大小
close < openPrev and open > closePrev and bodySize / prevBodySize > threshold // 当前蜡烛吞没前一根蜡烛,且实体大小更大
fearOscillator() =>
var float shootingStarScore = 0.0 // 初始化射击之星得分
var float hangingManScore = 0.0 // 初始化吊人线得分
var float engulfingScore = 0.0 // 初始化看跌吞没得分
for i = 1 to length
if isShootingStar(open[i], close[i], high[i], low[i], shootingStarThreshold) // 检测射击之星
shootingStarScore := shootingStarScore + 1.0
if isHangingMan(open[i], close[i], high[i], low[i], hangingManThreshold) // 检测吊人线
hangingManScore := hangingManScore + 1.0
if isBearishEngulfing(open[i], close[i], open[i+1], close[i+1], engulfingThreshold) // 检测看跌吞没
engulfingScore := engulfingScore + 1.0
shootingStarScore := shootingStarScore / length // 计算射击之星的得分比例
hangingManScore := hangingManScore / length // 计算吊人线的得分比例
engulfingScore := engulfingScore / length // 计算看跌吞没的得分比例
(shootingStarScore + hangingManScore + engulfingScore) / 3 // 返回恐惧震荡指标的平均得分
// --- 贪婪震荡指标函数 ---
isMarubozu(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算蜡烛实体大小
totalRange = high - low // 计算蜡烛的价格区间
bodySize / totalRange > threshold // 实体占总范围的比例大,符合光头光脚条件
isHammer(open, close, high, low, threshold) =>
bodySize = math.abs(close - open) // 计算蜡烛实体大小
lowerWick = math.min(open, close) - low // 计算下影线长度
upperWick = high - math.max(open, close) // 计算上影线长度
lowerWick / bodySize > threshold and upperWick < bodySize // 下影线较长且上影线较短,符合锤子线条件
isBullishEngulfing(open, close, openPrev, closePrev, threshold) =>
bodySize = math.abs(close - open) // 当前蜡烛的实体大小
prevBodySize = math.abs(closePrev - openPrev) // 前一根蜡烛的实体大小
close > openPrev and open < closePrev and bodySize / prevBodySize > threshold // 当前蜡烛吞没前一根蜡烛,符合看涨吞没条件
isThreeWhiteSoldiers(open, close, openPrev, closePrev, openPrev2, closePrev2, threshold) =>
close > open and closePrev > openPrev and closePrev2 > openPrev2 and close > closePrev and closePrev > closePrev2 // 连续三根上涨蜡烛,符合三只白兵条件
greedOscillator() =>
var float marubozuScore = 0.0 // 初始化光头光脚得分
var float hammerScore = 0.0 // 初始化锤子线得分
var float engulfingScore = 0.0 // 初始化看涨吞没得分
var float soldiersScore = 0.0 // 初始化三只白兵得分
for i = 1 to length
if isMarubozu(open[i], close[i], high[i], low[i], marubozuThreshold) // 检查光头光脚
marubozuScore := marubozuScore + 1.0
if isHammer(open[i], close[i], high[i], low[i], hammerThreshold) // 检查锤子线
hammerScore := hammerScore + 1.0
if isBullishEngulfing(open[i], close[i], open[i+1], close[i+1], engulfingThreshold) // 检查看涨吞没
engulfingScore := engulfingScore + 1.0
if isThreeWhiteSoldiers(open[i], close[i], open[i+1], close[i+1], open[i+2], close[i+2], threeWhiteSoldiersThreshold) // 检查三只白兵
soldiersScore := soldiersScore + 1.0
marubozuScore := marubozuScore / length // 计算光头光脚的得分比例
hammerScore := hammerScore / length // 计算锤子线的得分比例
engulfingScore := engulfingScore / length // 计算看涨吞没的得分比例
soldiersScore := soldiersScore / length // 计算三只白兵的得分比例
(marubozuScore + hammerScore + engulfingScore + soldiersScore) / 4 // 返回贪婪震荡指标的平均得分
// --- 最终计算 ---
indecision = indecisionOscillator() // 计算犹豫震荡指标
fear = fearOscillator() // 计算恐惧震荡指标
greed = greedOscillator() // 计算贪婪震荡指标
// 计算三个震荡指标的平均值
averageOscillator = (indecision + fear + greed) / 3 // 计算所有情绪指标的平均得分
// --- 组合策略逻辑 ---
var float entryPriceLong = na // 定义多头入场价格
var float entryPriceShort = na // 定义空头入场价格
var int holdingPeriodLong = 0 // 多头持仓周期
var int holdingPeriodShort = 0 // 空头持仓周期
var int cooldownCounter = 0 // 冷却期计数器
// 多头买入信号
longBuySignal = ta.crossover(averageOscillator, 0.1) // 当情绪震荡指标上穿0.1时,产生多头买入信号
// 空头买入信号
shortBuySignal = ta.crossover(averageOscillator, 0.2) // 当情绪震荡指标上穿0.2时,产生空头买入信号
// 计算回看期的平均成交量
avgVolume = ta.sma(volume, length) // 计算回看期内的平均成交量
// 多头平仓条件
longTakeProfitCondition = close > open and volume > avgVolume * volumeMultiplier // 如果当前价格上涨且成交量超过平均成交量的1.5倍,则平仓
// 空头平仓条件
shortTakeProfitCondition = close < open and volume > avgVolume * volumeMultiplier // 如果当前价格下跌且成交量超过平均成交量的1.5倍,则平仓
// 多头买入逻辑
if longBuySignal and strategy.position_size == 0 and cooldownCounter <= 0
entryPriceLong := close // 记录入场价格
strategy.entry("Long Entry", strategy.long) // 进场做多
cooldownCounter := cooldownPeriod // 进入冷却期
holdingPeriodLong := 0 // 重置持仓周期
// 增加多头持仓周期
if strategy.position_size > 0
holdingPeriodLong := holdingPeriodLong + 1
// 多头平仓逻辑
if longTakeProfitCondition and strategy.position_size > 0 and close > entryPriceLong // 满足平仓条件,且当前价格高于入场价
strategy.close_all() // 平掉所有多头仓位
cooldownCounter := cooldownPeriod // 进入冷却期
// 若持仓超过最大持仓周期,平仓
if holdingPeriodLong >= maxHoldingPeriod and strategy.position_size > 0 and close >= entryPriceLong
strategy.close_all()
cooldownCounter := cooldownPeriod
// 若亏损超过阈值,平仓
if holdingPeriodLong >= lossHoldingPeriod and strategy.position_size > 0 and close < entryPriceLong * (1 - lossThreshold)
strategy.close_all()
cooldownCounter := cooldownPeriod
// 空头买入逻辑
if shortBuySignal and strategy.position_size == 0 and cooldownCounter <= 0
entryPriceShort := close // 记录入场价格
strategy.entry("Short Entry", strategy.short) // 进场做空
cooldownCounter := cooldownPeriod // 进入冷却期
holdingPeriodShort := 0 // 重置持仓周期
// 增加空头持仓周期
if strategy.position_size < 0
holdingPeriodShort := holdingPeriodShort + 1
// 空头平仓逻辑
if shortTakeProfitCondition and strategy.position_size < 0 and close < entryPriceShort // 满足平仓条件,且当前价格低于入场价
strategy.close_all() // 平掉所有空头仓位
cooldownCounter := cooldownPeriod // 进入冷却期
// 若持仓超过最大持仓周期,平仓
if holdingPeriodShort >= maxHoldingPeriod and strategy.position_size < 0 and close <= entryPriceShort
strategy.close_all()
cooldownCounter := cooldownPeriod
// 若亏损超过阈值,平仓
if holdingPeriodShort >= lossHoldingPeriod and strategy.position_size < 0 and close > entryPriceShort * (1 + lossThreshold)
strategy.close_all()
cooldownCounter := cooldownPeriod
// 每根蜡烛减少冷却期计数器
if cooldownCounter > 0
cooldownCounter := cooldownCounter - 1