三只白兵策略
“三只白兵”是经典的看涨反转形态,由三根连续强势的阳线组成。下跌行情后出现该形态常标志买盘力量压倒卖方,行情可能持续上行。
测试表明年均收益约为 175%,该策略在股票市场表现最佳。
策略在第三根阳线形成后做多,期待动能继续。因该形态纯属看涨,策略不主动做空,但允许平掉其他方法开启的空仓。
止损设在形态下方不远处,以防假信号;若价格收盘再次跌破该位置则退出。
细节
- 入场条件:形态满足。
- 多/空:双向(虽然实际只做多)。
- 退出条件:止损或反向信号。
- 止损:是,按百分比。
- 默认值:
CandleType= 15 分钟StopLoss= 2%
- 过滤条件:
- 类别: 形态
- 方向: 双向
- 指标: K线形态
- 止损: 有
- 复杂度: 中等
- 时间框架: 日内
- 季节性: 无
- 神经网络: 无
- 背离: 无
- 风险级别: 中等
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Three White Soldiers strategy.
/// Enters long when three consecutive bullish candles with rising closes are detected.
/// Enters short when three consecutive bearish candles with falling closes are detected.
/// Uses SMA for exit confirmation.
/// Uses cooldown to control trade frequency.
/// </summary>
public class ThreeWhiteSoldiersStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private ICandleMessage _candle1;
private ICandleMessage _candle2;
private int _cooldown;
/// <summary>
/// MA period for exit.
/// </summary>
public int MaLength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ThreeWhiteSoldiersStrategy()
{
_maLength = Param(nameof(MaLength), 20)
.SetRange(10, 50)
.SetDisplay("MA Length", "Period of SMA for exit", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candle1 = null;
_candle2 = null;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candle1 = null;
_candle2 = null;
_cooldown = 0;
var sma = new SimpleMovingAverage { Length = MaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Shift candles
var prev2 = _candle1;
var prev1 = _candle2;
_candle1 = _candle2;
_candle2 = candle;
if (prev2 == null || prev1 == null)
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Three White Soldiers: 3 consecutive bullish candles with rising closes
var threeWhite =
prev2.ClosePrice > prev2.OpenPrice &&
prev1.ClosePrice > prev1.OpenPrice &&
candle.ClosePrice > candle.OpenPrice &&
prev1.ClosePrice > prev2.ClosePrice &&
candle.ClosePrice > prev1.ClosePrice;
// Three Black Crows: 3 consecutive bearish candles with falling closes
var threeBlack =
prev2.ClosePrice < prev2.OpenPrice &&
prev1.ClosePrice < prev1.OpenPrice &&
candle.ClosePrice < candle.OpenPrice &&
prev1.ClosePrice < prev2.ClosePrice &&
candle.ClosePrice < prev1.ClosePrice;
if (Position == 0 && threeWhite)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && threeBlack)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice < smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice > smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class three_white_soldiers_strategy(Strategy):
"""
Three White Soldiers strategy.
Enters long when three consecutive bullish candles with rising closes are detected.
Enters short when three consecutive bearish candles with falling closes are detected.
Uses SMA for exit confirmation.
"""
def __init__(self):
super(three_white_soldiers_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 20).SetDisplay("MA Length", "Period of SMA for exit", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._candle1 = None
self._candle2 = None
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(three_white_soldiers_strategy, self).OnReseted()
self._candle1 = None
self._candle2 = None
self._cooldown = 0
def OnStarted2(self, time):
super(three_white_soldiers_strategy, self).OnStarted2(time)
self._candle1 = None
self._candle2 = None
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = self._ma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
# Shift candles
prev2 = self._candle1
prev1 = self._candle2
self._candle1 = self._candle2
self._candle2 = candle
if prev2 is None or prev1 is None:
return
if self._cooldown > 0:
self._cooldown -= 1
return
cd = self._cooldown_bars.Value
sv = float(sma_val)
# Three White Soldiers: 3 consecutive bullish candles with rising closes
three_white = (
prev2.ClosePrice > prev2.OpenPrice and
prev1.ClosePrice > prev1.OpenPrice and
candle.ClosePrice > candle.OpenPrice and
prev1.ClosePrice > prev2.ClosePrice and
candle.ClosePrice > prev1.ClosePrice
)
# Three Black Crows: 3 consecutive bearish candles with falling closes
three_black = (
prev2.ClosePrice < prev2.OpenPrice and
prev1.ClosePrice < prev1.OpenPrice and
candle.ClosePrice < candle.OpenPrice and
prev1.ClosePrice < prev2.ClosePrice and
candle.ClosePrice < prev1.ClosePrice
)
if self.Position == 0 and three_white:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and three_black:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and float(candle.ClosePrice) < sv:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and float(candle.ClosePrice) > sv:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return three_white_soldiers_strategy()