Hammer Hanging Stochastic
该策略将 MetaTrader 顾问 "Expert_AH_HM_Stoch" 迁移到 StockSharp 高级 API。它结合锤子线/上吊线形态与随机指标确认,用于捕捉强趋势后的反转机会。
所有决策均基于已完成的 K 线。策略使用随机指标 %D 线作为过滤器,并在动能离开极值区域时平仓。
详情
- 入场条件:
- 多头:出现锤子线且上一根柱子的随机指标 %D 低于超卖阈值。
- 空头:出现上吊线且上一根柱子的随机指标 %D 高于超买阈值。
- 方向:支持多空双向。
- 离场:当随机指标 %D 向上/向下突破可配置的恢复与极值水平时退出持仓。
- 止损:通过
StartProtection()启动(默认使用账户级别的保护参数,可按需调整)。 - 默认参数:
CandleType= TimeSpan.FromHours(1)StochPeriodK= 15StochPeriodD= 49StochPeriodSlow= 25OversoldLevel= 30OverboughtLevel= 70ExitLowerLevel= 20ExitUpperLevel= 80MaxBodyRatio= 0.35LowerShadowMultiplier= 2.5UpperShadowMultiplier= 0.3
- 过滤器:
- 分类:形态 + 振荡器确认
- 方向:双向
- 指标:蜡烛形态、Stochastic
- 止损:通过
StartProtection提供 - 复杂度:中等
- 周期:波段/日内(默认 1 小时)
- 季节性:无
- 神经网络:无
- 背离:无
- 风险等级:中等
工作流程
- 通过
BindEx订阅所选蜡烛序列和随机指标,使用 StockSharp 高级 API。 - 根据实体与影线比例识别锤子线和上吊线形态。
- 使用上一根柱子的随机指标 %D 确认入场信号。
- 当随机指标离开超卖/超买区域时平仓,复刻原始 MQL 策略的退出逻辑。
- 在可用的图表区域中绘制蜡烛、随机指标以及策略自身的成交记录。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Hammer/Hanging Man + Stochastic strategy.
/// Buys on hammer in oversold, sells on hanging man in overbought.
/// </summary>
public class HammerHangingStochasticStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _stochPeriod;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int StochPeriod { get => _stochPeriod.Value; set => _stochPeriod.Value = value; }
public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
public HammerHangingStochasticStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_stochPeriod = Param(nameof(StochPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Stoch Period", "Stochastic K period", "Indicators");
_oversold = Param(nameof(Oversold), 30m)
.SetDisplay("Oversold", "Stochastic oversold level", "Signals");
_overbought = Param(nameof(Overbought), 70m)
.SetDisplay("Overbought", "Stochastic overbought level", "Signals");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var stoch = new StochasticOscillator { K = { Length = StochPeriod }, D = { Length = 3 } };
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(stoch, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
{
if (candle.State != CandleStates.Finished) return;
var stochTyped = stochValue as StochasticOscillatorValue;
if (stochTyped?.K is not decimal kValue) return;
var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
var range = candle.HighPrice - candle.LowPrice;
if (range <= 0 || body <= 0) return;
var upperShadow = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
var lowerShadow = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;
// Hammer: small body at top, long lower shadow
var isHammer = lowerShadow > body * 2 && upperShadow < body;
// Hanging Man: small body at bottom, long upper shadow
var isHangingMan = upperShadow > body * 2 && lowerShadow < body;
if (isHammer && kValue < Oversold && Position <= 0)
BuyMarket();
else if (isHangingMan && kValue > Overbought && Position >= 0)
SellMarket();
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
class hammer_hanging_stochastic_strategy(Strategy):
"""
Hammer/Hanging Man + Stochastic strategy.
Buys on hammer candle in oversold stochastic.
Sells on hanging man candle in overbought stochastic.
"""
def __init__(self):
super(hammer_hanging_stochastic_strategy, self).__init__()
self._stoch_period = self.Param("StochPeriod", 14) \
.SetDisplay("Stoch Period", "Stochastic K period", "Indicators")
self._oversold = self.Param("Oversold", 30.0) \
.SetDisplay("Oversold", "Stochastic oversold level", "Signals")
self._overbought = self.Param("Overbought", 70.0) \
.SetDisplay("Overbought", "Stochastic overbought level", "Signals")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(hammer_hanging_stochastic_strategy, self).OnStarted2(time)
stoch = StochasticOscillator()
stoch.K.Length = self._stoch_period.Value
stoch.D.Length = 3
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(stoch, self._process_candle).Start()
def _process_candle(self, candle, stoch_val):
if candle.State != CandleStates.Finished:
return
k_value = stoch_val.K
if k_value is None:
return
k_value = float(k_value)
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
body = abs(close - open_p)
range_val = high - low
if range_val <= 0 or body <= 0:
return
upper_shadow = high - max(open_p, close)
lower_shadow = min(open_p, close) - low
is_hammer = lower_shadow > body * 2 and upper_shadow < body
is_hanging_man = upper_shadow > body * 2 and lower_shadow < body
if is_hammer and k_value < self._oversold.Value and self.Position <= 0:
self.BuyMarket()
elif is_hanging_man and k_value > self._overbought.Value and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return hammer_hanging_stochastic_strategy()